From 023fc857e9cfba3e6970682e3a1a7b3c0c584c7b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 28 Jul 2025 13:10:02 +0200 Subject: [PATCH] ipq806x: add 2.11 version of the target Signed-off-by: John Crispin --- ipq806x/Makefile | 33 + ...dcode-path-to-awk-in-scripts-ld-vers.patch | 30 + .../011-kbuild-export-SUBARCH.patch | 21 + ...lper-to-get-data-pointed-by-a-symbol.patch | 53 + ...-namespace_from_kstrtabns-to-not-har.patch | 62 + ...Implement-optimised-checksum-routine.patch | 176 + ...m-Fix-pathological-zero-length-calls.patch | 28 + ...y-up-lib-crypto-Kconfig-and-Makefile.patch | 112 + ...ve-existing-library-code-into-lib-cr.patch | 668 ++ ...a-depend-on-generic-chacha-library-i.patch | 192 + ...a-expose-SIMD-ChaCha-routine-as-libr.patch | 205 + ...cha-depend-on-generic-chacha-library.patch | 129 + ...cha-expose-arm64-ChaCha-routine-as-l.patch | 138 + ...a-import-Eric-Biggers-s-scalar-accel.patch | 480 + ...a-remove-dependency-on-generic-ChaCh.patch | 691 ++ ...a-expose-ARM-ChaCha-routine-as-libra.patch | 108 + ...ha-import-32r2-ChaCha-code-from-Zinc.patch | 451 + ...ha-wire-up-accelerated-32r2-code-fro.patch | 559 ++ ...cha-unexport-chacha_generic-routines.patch | 115 + ...move-core-routines-into-a-separate-l.patch | 649 ++ ...305-unify-Poly1305-state-struct-with.patch | 251 + ...expose-init-update-final-library-int.patch | 224 + ...305-depend-on-generic-library-not-ge.patch | 217 + ...305-expose-existing-driver-as-poly13.patch | 163 + ...y1305-incorporate-OpenSSL-CRYPTOGAMS.patch | 2083 +++++ ...305-incorporate-OpenSSL-CRYPTOGAMS-N.patch | 2776 ++++++ ...1305-incorporate-OpenSSL-CRYPTOGAMS-.patch | 1563 ++++ ...eneric-C-library-implementation-and-.patch | 1097 +++ ...o-testmgr-add-test-cases-for-Blake2s.patch | 322 + ...ake2s-implement-generic-shash-driver.patch | 245 + ...o-blake2s-x86_64-SIMD-implementation.patch | 557 ++ ...19-generic-C-library-implementations.patch | 1849 ++++ ...6-crypto-curve25519-add-kpp-selftest.patch | 1268 +++ ...ve25519-implement-generic-KPP-driver.patch | 136 + ...25519-work-around-Clang-stack-spilli.patch | 75 + ...9-x86_64-library-and-KPP-implementat.patch | 2536 ++++++ ...25519-import-Bernstein-and-Schwabe-s.patch | 2135 +++++ ...rve25519-wire-up-NEON-implementation.patch | 1058 +++ ...oly1305-import-construction-and-self.patch | 7677 ++++++++++++++++ ...a20poly1305-reimplement-crypt_from_s.patch | 295 + ...neric-remove-unnecessary-setkey-func.patch | 68 + ...a-only-unregister-algorithms-if-regi.patch | 31 + ...-chacha20poly1305-use-chacha20_crypt.patch | 83 + ...itionalize-crypto-api-in-arch-glue-f.patch | 275 + ...a-fix-warning-message-in-header-file.patch | 35 + ...25519-add-arch-specific-key-generati.patch | 38 + ...ypto-lib-curve25519-re-add-selftests.patch | 1387 +++ ...add-new-32-and-64-bit-generic-versio.patch | 1164 +++ ...305-import-unmodified-cryptogams-imp.patch | 4183 +++++++++ ...305-wire-up-faster-implementations-f.patch | 2927 ++++++ ...-mips-poly1305-remove-redundant-non-.patch | 171 + ...-curve25519-Fix-selftest-build-error.patch | 102 + ...pto-x86-poly1305-fix-.gitignore-typo.patch | 23 + ...oly1305-add-back-missing-test-vector.patch | 1858 ++++ ...305-emit-does-base-conversion-itself.patch | 36 + ...a-fix-build-failured-when-kernel-mod.patch | 58 + ...llow-tests-to-be-disabled-when-manag.patch | 40 + ...oly1305-prevent-integer-overflow-on-.patch | 40 + ...25519-support-assemblers-with-no-adx.patch | 84 + ...chacha-correctly-walk-through-blocks.patch | 68 + ...25519-replace-with-formally-verified.patch | 3765 ++++++++ ...rve25519-leave-r12-as-spare-register.patch | 376 + ...ly1305-add-artifact-to-.gitignore-fi.patch | 35 + ...ch-lib-limit-simd-usage-to-4k-chunks.patch | 243 + ...a20poly1305-Add-missing-function-dec.patch | 38 + ...a-sse3-use-unaligned-loads-for-state.patch | 147 + ...e25519-Remove-unused-carry-variables.patch | 46 + ...rve25519-include-linux-scatterlist.h.patch | 36 + ...305-Add-prototype-for-poly1305_block.patch | 33 + ...to-curve25519-x86_64-Use-XORL-r32-32.patch | 261 + ...ypto-poly1305-x86_64-Use-XORL-r32-32.patch | 59 + ...305-Remove-assignments-with-no-effec.patch | 29 + ...oly1305-add-back-a-needed-assignment.patch | 33 + ...RYPTO_MANAGER_EXTRA_TESTS-requires-t.patch | 33 + ...a-neon-optimize-for-non-block-size-m.patch | 272 + ...-chacha-simplify-tail-block-handling.patch | 324 + ...a20poly1305-define-empty-module-exit.patch | 37 + ...a-neon-add-missing-counter-increment.patch | 38 + ...-net-WireGuard-secure-network-tunnel.patch | 8071 +++++++++++++++++ ...sts-import-harness-makefile-for-test.patch | 1078 +++ ...g-select-parent-dependency-for-crypt.patch | 30 + ...al-fix-spelling-mistakes-in-comments.patch | 66 + ...emove-unused-include-linux-version.h.patch | 28 + ...dips-use-kfree_rcu-instead-of-call_r.patch | 41 + ...sts-remove-ancient-kernel-compatibil.patch | 373 + ...ng-do-not-account-for-pfmemalloc-whe.patch | 39 + ...-mark-skbs-as-not-on-list-when-recei.patch | 34 + ...dips-fix-use-after-free-in-root_remo.patch | 164 + ...reject-peers-with-low-order-public-k.patch | 233 + ...sts-ensure-non-addition-of-peers-wit.patch | 34 + ...sts-tie-socket-waiting-to-target-pid.patch | 77 + ...uard-device-use-icmp_ndo_send-helper.patch | 64 + ...sts-reduce-complexity-and-fix-make-r.patch | 104 + ...eceive-reset-last_under_load-to-zero.patch | 38 + ...guard-send-account-for-mtu-0-devices.patch | 95 + ...-remove-extra-call-to-synchronize_ne.patch | 32 + ...sts-remove-duplicated-include-sys-ty.patch | 27 + ...-queueing-account-for-skb-protocol-0.patch | 100 + ...e-remove-dead-code-from-default-pack.patch | 35 + ...error-out-precomputed-DH-during-hand.patch | 224 + ...emove-errant-newline-from-packet_enc.patch | 29 + ...ng-cleanup-ptr_ring-in-error-path-of.patch | 35 + ...e-use-tunnel-helpers-for-decapsulati.patch | 50 + ...sts-use-normal-kernel-stack-size-on-.patch | 28 + ...-remove-errant-restriction-on-loopin.patch | 162 + ...eceive-cond_resched-when-processing-.patch | 58 + ...sts-initalize-ipv6-members-to-NULL-t.patch | 51 + ...eceive-use-explicit-unlikely-branch-.patch | 88 + ...ftests-use-newer-iproute2-for-gcc-10.patch | 31 + ...read-preshared-key-while-taking-lock.patch | 61 + ...ng-preserve-flow-hash-across-packet-.patch | 116 + ...separate-receive-counter-from-send-c.patch | 330 + ...do-not-assign-initiation-time-in-if-.patch | 33 + ...vice-avoid-circular-netns-references.patch | 296 + ...e-account-for-napi_gro_receive-never.patch | 42 + ...l-add-header_ops-for-layer-3-devices.patch | 58 + ...ent-header_ops-parse_protocol-for-AF.patch | 36 + ...ng-make-use-of-ip_tunnel_parse_proto.patch | 68 + ...onsistently-use-NLA_POLICY_EXACT_LEN.patch | 49 + ...-consistently-use-NLA_POLICY_MIN_LEN.patch | 39 + ...take-lock-when-removing-handshake-en.patch | 127 + ...okup-take-lock-before-checking-hash-.patch | 62 + ...sts-check-that-route_me_harder-packe.patch | 56 + ...double-unlikely-notation-when-using-.patch | 55 + ...ocket-remove-bogus-__be32-annotation.patch | 52 + ...tests-test-multiple-parallel-streams.patch | 52 + ...ut-frequently-used-members-above-cac.patch | 42 + ...-do-not-generate-ICMP-for-non-IP-pac.patch | 47 + ...ing-get-rid-of-per-peer-ring-buffers.patch | 560 ++ ...fig-use-arm-chacha-even-with-no-neon.patch | 30 + ...y1305-enable-for-all-MIPS-processors.patch | 60 + ...ps-add-poly1305-core.S-to-.gitignore.patch | 24 + ...fix-poly1305_core_setkey-declaration.patch | 172 + ...sts-remove-old-conntrack-kconfig-val.patch | 29 + ...sts-make-sure-rp_filter-is-disabled-.patch | 31 + ...reguard-0129-wireguard-do-not-use-O3.patch | 33 + ...nchronize_net-rather-than-synchroniz.patch | 66 + ...ireguard-peer-allocate-in-kmem_cache.patch | 125 + ...dips-initialize-list-head-in-selftes.patch | 43 + ...guard-allowedips-remove-nodes-in-O-1.patch | 237 + ...owedips-allocate-nodes-in-kmem_cache.patch | 173 + ...dips-free-empty-intermediate-nodes-w.patch | 521 ++ ...e-dsemul-code-when-CONFIG_MIPS_FP_SU.patch | 134 + ...-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch | 32 + ...-vdso-fix-jalr-t9-crash-in-vdso-code.patch | 54 + ...11-MIPS-Fix-exception-handler-memcpy.patch | 107 + ...ow_offload-handle-netdevice-events-f.patch | 99 + ...w_table-fix-offloaded-connection-tim.patch | 114 + ...w_table-fix-up-ct-state-of-flows-aft.patch | 24 + ...rop-unused-variable-tin_quantum_prio.patch | 158 + ...antage-of-skb-hash-where-appropriate.patch | 170 + ...-8622-LE-PHB-support-to-CAKE-diffser.patch | 57 + ...partition-Document-the-slc-mode-prop.patch | 28 + ...convert-fixed-partitions-to-the-json.patch | 324 + ...move-partition-binding-to-its-own-fi.patch | 115 + ...d-add-binding-for-BCM4908-partitions.patch | 92 + ...art-support-BCM4908-fixed-partitions.patch | 648 ++ ...rt-limit-parsing-of-deprecated-DT-sy.patch | 69 + ...rt-make-symbol-bcm4908_partitions_qu.patch | 34 + ...em-cells-compatible-to-parse-mtd-as-.patch | 40 + ...ings-nvmem-drop-nodename-restriction.patch | 28 + ...Document-use-of-nvmem-cells-compatib.patch | 119 + ...add-binding-for-Linksys-Northstar-pa.patch | 98 + ...rt-support-Linksys-Northstar-partiti.patch | 156 + ...ix-calculating-partition-end-address.patch | 28 + ...pi-poll-functionality-to-__napi_poll.patch | 88 + ...threaded-able-napi-poll-loop-support.patch | 261 + ...tribute-to-control-napi-threaded-mod.patch | 177 + ...ween-napi-kthread-mode-and-busy-poll.patch | 93 + ...up-on-napi_disable-for-threaded-napi.patch | 53 + ...ast-GRO-for-skbs-with-Ethernet-heade.patch | 78 + ...ve-fwnode-parsing-into-sfp-bus-layer.patch | 179 + ....5-net-sfp-rework-upstream-interface.patch | 254 + ...fix-sfp_bus_put-kernel-documentation.patch | 27 + ...sfp-fix-sfp_bus_add_upstream-warning.patch | 27 + ...-sub-state-machines-into-separate-fu.patch | 124 + ...disable-on-device-down-to-main-state.patch | 41 + ...e-sfp_sm_ins_next-as-sfp_sm_mod_next.patch | 71 + ...-module-remove-outside-state-machine.patch | 53 + ...-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch | 51 + ...-parse-SFP-power-requirement-earlier.patch | 115 + ...wer-switch-on-address-change-modules.patch | 65 + ...TX_DISABLE-and-phy-only-from-main-st.patch | 52 + ...t-the-PHY-probe-from-sfp_sm_mod_init.patch | 53 + ...-sfp-eliminate-mdelay-from-PHY-probe.patch | 130 + ...ult-processing-to-transition-to-othe.patch | 69 + ...X_FAULT-has-deasserted-before-probin.patch | 80 + ...stream-s-attachment-state-in-state-m.patch | 153 + ...plit-power-mode-switching-from-probe.patch | 184 + ...module-insert-reporting-out-of-probe.patch | 159 + ...p-to-probe-slow-to-initialise-GPON-m.patch | 110 + ...dules-with-slow-diagnostics-to-probe.patch | 198 + ...-net-phy-add-core-phylib-sfp-support.patch | 183 + ...5-net-phy-marvell10g-add-SFP-support.patch | 67 + ...update-to-use-phy_support_asym_pause.patch | 43 + ...-sfp-soft-status-and-control-support.patch | 225 + ...t7530-add-support-for-port-mirroring.patch | 123 + ...xxx-Split-monitor-port-configuration.patch | 149 + ...e6xxx-Add-support-for-port-mirroring.patch | 266 + ...x-fix-broken-if-statement-because-of.patch | 30 + ...mv88e6xxx-Fix-masking-of-egress-port.patch | 34 + ...pport-for-clause-37-auto-negotiation.patch | 195 + ...avoid-error-message-for-optional-IRQ.patch | 33 + ...an-option-for-drivers-to-always-rece.patch | 121 + ...3-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch | 51 + ...dsa-rtl8366-Pass-GENMASK-signed-bits.patch | 27 + ...tl4_a-Implement-Realtek-4-byte-A-tag.patch | 232 + ...sa-rtl8366rb-Support-the-CPU-DSA-tag.patch | 100 + ...iatek-Integrate-GDM-PSE-setup-operat.patch | 80 + ...iatek-Refine-the-timing-of-GDM-PSE-s.patch | 45 + ...diatek-Enable-GDM-GDMA_DROP_ALL-mode.patch | 33 + ...cally-bring-up-DSA-master-when-openi.patch | 85 + ...y-switchdev-of-disappearance-of-old-.patch | 126 + ...r-when-a-non-legacy-FDB-operation-fa.patch | 52 + ...e-switchdev_notifier_fdb_info-in-dsa.patch | 226 + ...tchdev-event-implementation-under-th.patch | 85 + ...ly-in-dsa_slave_switchdev_event-if-w.patch | 42 + ...or-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch | 263 + ...setup-core-clock-even-in-TRGMII-mode.patch | 84 + ...imu-Add-support-for-the-FXOS8700-IMU.patch | 893 ++ ...sfs-attributes-for-VPD-pages-0h-and-.patch | 122 + ...-disk-and-solid-state-drives-with-te.patch | 737 ++ ...6-leds-populate-the-device-s-of_node.patch | 36 + ...pxa-use-official-address-byte-helper.patch | 59 + ...5.8-i2c-pxa-remove-unneeded-includes.patch | 37 + ...ge-includes-to-be-in-alphabetical-or.patch | 52 + ...-re-arrange-functions-to-flow-better.patch | 380 + ...e-arrange-register-field-definitions.patch | 161 + ...nd-use-definitions-for-IBMR-register.patch | 66 + ...-set-fm-and-hs-members-for-each-type.patch | 66 + ...ove-private-definitions-to-i2c-pxa.c.patch | 128 + ...-move-DT-IDs-along-side-platform-IDs.patch | 50 + ...13-v5.8-i2c-pxa-clean-up-decode_bits.patch | 53 + ...pxa_wait_bus_not_busy-boundary-condi.patch | 53 + ...lidate-i2c_pxa_-xfer-implementations.patch | 91 + ...omplaints-with-non-responsive-slaves.patch | 67 + ...a-ensure-timeout-messages-are-unique.patch | 45 + ...2c-pxa-remove-some-unnecessary-debug.patch | 34 + ...a-use-master-abort-for-device-probes.patch | 35 + ...a-implement-generic-i2c-bus-recovery.patch | 285 + ...-v5.8-spi-rb4xx-null-pointer-bug-fix.patch | 48 + ...pdate-driver-to-be-device-tree-aware.patch | 60 + ..._nvram-rename-finding-function-and-i.patch | 80 + ..._nvram-add-helper-checking-for-NVRAM.patch | 90 + ...7xx_nvram-extract-code-copying-NVRAM.patch | 80 + ..._nvram-look-for-NVRAM-with-for-inste.patch | 37 + ..._nvram-inline-code-checking-NVRAM-si.patch | 70 + .../999-bpf-off-by-one-backport.patch | 13 + ...r-bridge-s-private-skb-space-on-xmit.patch | 36 + ipq806x/base-files/etc/board.d/01_leds | 71 + ipq806x/base-files/etc/board.d/02_network | 101 + .../etc/hotplug.d/firmware/11-ath10k-caldata | 139 + .../etc/hotplug.d/firmware/40-ct-fw-cfg | 32 + .../etc/hotplug.d/ieee80211/10_fix_wifi_mac | 39 + ipq806x/base-files/etc/init.d/bootcount | 21 + ipq806x/base-files/etc/init.d/cpufreq | 17 + ipq806x/base-files/etc/inittab | 4 + .../etc/uci-defaults/04_led_migration | 7 + .../lib/firmware/ath10k/fwcfg-qca9888.txt | 16 + .../lib/firmware/ath10k/fwcfg-qca9984.txt | 16 + ipq806x/base-files/lib/preinit/04_reorder_eth | 13 + .../lib/preinit/05_set_iface_mac_ipq806x.sh | 14 + ipq806x/base-files/lib/upgrade/asrock.sh | 56 + ipq806x/base-files/lib/upgrade/buffalo.sh | 44 + ipq806x/base-files/lib/upgrade/linksys.sh | 118 + ipq806x/base-files/lib/upgrade/platform.sh | 66 + ipq806x/base-files/lib/upgrade/zyxel.sh | 127 + .../sbin/asrock_g10_back_to_factory | 15 + ipq806x/config-5.10 | 508 ++ ipq806x/config-5.4 | 456 + ipq806x/config-5.4-generic | 6572 ++++++++++++++ .../mtd/partitions/openwrt,uimage.yaml | 91 + .../Documentation/networking/adm6996.txt | 110 + .../files-5.4/arch/mips/fw/myloader/Makefile | 5 + .../arch/mips/fw/myloader/myloader.c | 63 + ipq806x/files-5.4/block/partitions/fit.c | 254 + .../files-5.4/drivers/mtd/mtdsplit/Kconfig | 103 + .../files-5.4/drivers/mtd/mtdsplit/Makefile | 17 + .../files-5.4/drivers/mtd/mtdsplit/mtdsplit.c | 130 + .../files-5.4/drivers/mtd/mtdsplit/mtdsplit.h | 67 + .../drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c | 186 + .../drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c | 523 ++ .../drivers/mtd/mtdsplit/mtdsplit_brnimage.c | 104 + .../mtd/mtdsplit/mtdsplit_cfe_bootfs.c | 90 + .../drivers/mtd/mtdsplit/mtdsplit_elf.c | 287 + .../drivers/mtd/mtdsplit/mtdsplit_eva.c | 103 + .../drivers/mtd/mtdsplit/mtdsplit_fit.c | 157 + .../drivers/mtd/mtdsplit/mtdsplit_jimage.c | 284 + .../drivers/mtd/mtdsplit/mtdsplit_lzma.c | 104 + .../drivers/mtd/mtdsplit/mtdsplit_minor.c | 125 + .../drivers/mtd/mtdsplit/mtdsplit_seama.c | 118 + .../drivers/mtd/mtdsplit/mtdsplit_squashfs.c | 72 + .../drivers/mtd/mtdsplit/mtdsplit_tplink.c | 176 + .../drivers/mtd/mtdsplit/mtdsplit_trx.c | 155 + .../drivers/mtd/mtdsplit/mtdsplit_uimage.c | 282 + .../drivers/mtd/mtdsplit/mtdsplit_wrgg.c | 142 + .../drivers/mtd/parsers/routerbootpart.c | 365 + ipq806x/files-5.4/drivers/net/phy/adm6996.c | 1243 +++ ipq806x/files-5.4/drivers/net/phy/adm6996.h | 186 + ipq806x/files-5.4/drivers/net/phy/ar8216.c | 2925 ++++++ ipq806x/files-5.4/drivers/net/phy/ar8216.h | 723 ++ ipq806x/files-5.4/drivers/net/phy/ar8327.c | 1550 ++++ ipq806x/files-5.4/drivers/net/phy/ar8327.h | 333 + ipq806x/files-5.4/drivers/net/phy/b53/Kconfig | 37 + .../files-5.4/drivers/net/phy/b53/Makefile | 10 + .../drivers/net/phy/b53/b53_common.c | 1730 ++++ .../files-5.4/drivers/net/phy/b53/b53_mdio.c | 468 + .../files-5.4/drivers/net/phy/b53/b53_mmap.c | 241 + .../drivers/net/phy/b53/b53_phy_fixup.c | 55 + .../files-5.4/drivers/net/phy/b53/b53_priv.h | 336 + .../files-5.4/drivers/net/phy/b53/b53_regs.h | 348 + .../files-5.4/drivers/net/phy/b53/b53_spi.c | 344 + .../files-5.4/drivers/net/phy/b53/b53_srab.c | 378 + ipq806x/files-5.4/drivers/net/phy/ip17xx.c | 1370 +++ ipq806x/files-5.4/drivers/net/phy/mvswitch.c | 446 + ipq806x/files-5.4/drivers/net/phy/mvswitch.h | 145 + ipq806x/files-5.4/drivers/net/phy/psb6970.c | 444 + ipq806x/files-5.4/drivers/net/phy/rtl8306.c | 1063 +++ .../files-5.4/drivers/net/phy/rtl8366_smi.c | 1624 ++++ .../files-5.4/drivers/net/phy/rtl8366_smi.h | 160 + ipq806x/files-5.4/drivers/net/phy/rtl8366rb.c | 1532 ++++ ipq806x/files-5.4/drivers/net/phy/rtl8366s.c | 1320 +++ ipq806x/files-5.4/drivers/net/phy/rtl8367.c | 1846 ++++ ipq806x/files-5.4/drivers/net/phy/rtl8367b.c | 1673 ++++ ipq806x/files-5.4/drivers/net/phy/swconfig.c | 1242 +++ .../files-5.4/drivers/net/phy/swconfig_leds.c | 555 ++ .../drivers/platform/mikrotik/Kconfig | 19 + .../drivers/platform/mikrotik/Makefile | 4 + .../drivers/platform/mikrotik/rb_hardconfig.c | 825 ++ .../drivers/platform/mikrotik/rb_softconfig.c | 806 ++ .../drivers/platform/mikrotik/routerboot.c | 218 + .../drivers/platform/mikrotik/routerboot.h | 37 + .../dt-bindings/mtd/partitions/uimage.h | 198 + .../files-5.4/include/linux/ar8216_platform.h | 133 + .../files-5.4/include/linux/ath5k_platform.h | 30 + .../files-5.4/include/linux/ath9k_platform.h | 58 + ipq806x/files-5.4/include/linux/myloader.h | 121 + .../linux/platform_data/adm6996-gpio.h | 29 + ipq806x/files-5.4/include/linux/routerboot.h | 106 + .../files-5.4/include/linux/rt2x00_platform.h | 23 + ipq806x/files-5.4/include/linux/rtl8366.h | 42 + ipq806x/files-5.4/include/linux/rtl8367.h | 63 + ipq806x/files-5.4/include/linux/switch.h | 179 + ipq806x/files-5.4/include/uapi/linux/switch.h | 119 + .../arm/boot/dts/qcom-ipq8062-wg2600hp3.dts | 454 + .../files/arch/arm/boot/dts/qcom-ipq8062.dtsi | 95 + .../boot/dts/qcom-ipq8064-ad7200-c2600.dtsi | 327 + .../arch/arm/boot/dts/qcom-ipq8064-ad7200.dts | 135 + .../arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 121 + .../arch/arm/boot/dts/qcom-ipq8064-ap161.dts | 159 + .../arch/arm/boot/dts/qcom-ipq8064-c2600.dts | 119 + .../arch/arm/boot/dts/qcom-ipq8064-d7800.dts | 339 + .../arch/arm/boot/dts/qcom-ipq8064-db149.dts | 163 + .../arm/boot/dts/qcom-ipq8064-ea7500-v1.dts | 91 + .../arch/arm/boot/dts/qcom-ipq8064-ea8500.dts | 128 + .../arm/boot/dts/qcom-ipq8064-eax500.dtsi | 207 + .../arch/arm/boot/dts/qcom-ipq8064-g10.dts | 250 + .../arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 316 + .../arm/boot/dts/qcom-ipq8064-r7500v2.dts | 337 + .../arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts | 317 + .../arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi | 69 + .../arm/boot/dts/qcom-ipq8064-vr2600v.dts | 362 + .../arm/boot/dts/qcom-ipq8064-wg2600hp.dts | 398 + .../arch/arm/boot/dts/qcom-ipq8064-wpq864.dts | 465 + .../arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts | 482 + .../arm/boot/dts/qcom-ipq8065-nbg6817.dts | 316 + .../arch/arm/boot/dts/qcom-ipq8065-r7800.dts | 470 + .../boot/dts/qcom-ipq8065-rt4230w-rev6.dts | 319 + .../files/arch/arm/boot/dts/qcom-ipq8065.dtsi | 164 + .../arm/boot/dts/qcom-ipq8068-ecw5410.dts | 341 + .../arm/boot/dts/qcom-ipq8068-ssw2ac2600.dts | 341 + ipq806x/generic/target.mk | 1 + ipq806x/hack-5.4/204-module_strip.patch | 204 + .../hack-5.4/210-darwin_scripts_include.patch | 3053 +++++++ .../211-darwin-uuid-typedef-clash.patch | 22 + ipq806x/hack-5.4/212-tools_portability.patch | 110 + .../hack-5.4/214-spidev_h_portability.patch | 24 + ipq806x/hack-5.4/220-gc_sections.patch | 136 + ipq806x/hack-5.4/221-module_exports.patch | 109 + .../hack-5.4/230-openwrt_lzma_options.patch | 71 + .../hack-5.4/249-udp-tunnel-selection.patch | 11 + ipq806x/hack-5.4/250-netfilter_depends.patch | 27 + ipq806x/hack-5.4/251-sound_kconfig.patch | 199 + ipq806x/hack-5.4/259-regmap_dynamic.patch | 125 + .../260-crypto_test_dependencies.patch | 52 + ipq806x/hack-5.4/260-lib-arc4-unhide.patch | 15 + ipq806x/hack-5.4/280-rfkill-stubs.patch | 84 + ...cache-use-more-efficient-cache-blast.patch | 64 + .../301-mips_image_cmdline_hack.patch | 38 + .../321-powerpc_crtsavres_prereq.patch | 39 + ...k_mx25l6406e_with_4bit_block_protect.patch | 69 + ipq806x/hack-5.4/531-debloat_lzma.patch | 1040 +++ .../550-loop-Report-EOPNOTSUPP-properly.patch | 41 + .../640-bridge-only-accept-EAP-locally.patch | 82 + ...lter-connmark-introduce-set-dscpmark.patch | 212 + .../hack-5.4/647-netfilter-flow-acct.patch | 70 + .../650-netfilter-add-xt_OFFLOAD-target.patch | 589 ++ .../hack-5.4/651-wireless_mesh_header.patch | 24 + ipq806x/hack-5.4/660-fq_codel_defaults.patch | 27 + .../661-use_fq_codel_by_default.patch | 100 + ipq806x/hack-5.4/662-remove_pfifo_fast.patch | 243 + .../700-swconfig_switch_drivers.patch | 135 + .../hack-5.4/703-add_vsc8504_support.patch | 57 + .../710-net-dsa-mv88e6xxx-default-VID-1.patch | 18 + ...-dsa-mv88e6xxx-disable-ATU-violation.patch | 12 + ipq806x/hack-5.4/721-phy_packets.patch | 176 + .../hack-5.4/773-bgmac-add-srab-switch.patch | 98 + ipq806x/hack-5.4/901-debloat_sock_diag.patch | 145 + ipq806x/hack-5.4/902-debloat_proc.patch | 408 + ipq806x/hack-5.4/904-debloat_dma_buf.patch | 74 + ipq806x/hack-5.4/910-kobject_uevent.patch | 32 + .../911-kobject_add_broadcast_uevent.patch | 76 + ...ays-create-console-node-in-initramfs.patch | 40 + ipq806x/image/Makefile | 438 + ipq806x/modules.mk | 16 + ...ings-qcom_adm-Fix-channel-specifiers.patch | 71 + ...ically-select-PCI_DOMAINS-if-PCI-is-.patch | 29 + ...arch-arm-force-ZRELADDR-on-arch-qcom.patch | 62 + .../0065-arm-override-compiler-flags.patch | 21 + ...Mangle-bootloader-s-kernel-arguments.patch | 210 + .../0069-arm-boot-add-dts-files.patch | 39 + .../0072-add-ipq806x-with-no-clocks.patch | 10 + .../082-ipq8064-dtsi-tweaks.patch | 211 + .../083-ipq8064-dtsi-additions.patch | 754 ++ .../084-ipq8064-v1.0-dtsi-cleanup.patch | 89 + .../085-ipq8064-v1.0-dtsi-additions.patch | 14 + .../086-ipq8064-fix-duplicate-node.patch | 145 + ...qcom-cpufreq-nvmem-support-specific-.patch | 51 + ...7-1-ipq806x-gcc-add-missing-clk-flag.patch | 115 + .../097-2-ipq806x-lcc-add-missing-reset.patch | 59 + ...com-krait-add-missing-enable-disable.patch | 57 + ...missing-clk-and-reset-for-crypto-eng.patch | 372 + ...q-add-Krait-dedicated-scaling-driver.patch | 681 ++ ...ufreq-add-qcom-krait-cpufreq-binding.patch | 237 + ...add-fab-scaling-support-with-cpufreq.patch | 243 + ...m_nandc-add-boot_layout_mode-support.patch | 239 + ...vicetree-mtd-qcom_nandc-document-qco.patch | 42 + ...-v5.11-dmaengine-qcom-add_ADM_driver.patch | 965 ++ ....12-mtd-parsers-Add-Qcom-SMEM-parser.patch | 217 + ...-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch | 83 + ...conflicts-with-OpenWrt-auto-mounting.patch | 24 + ...M-dts-qcom-reduce-pci-IO-size-to-64K.patch | 46 + ...hermal-tsens-Add-VER_0-tsens-version.patch | 285 + ...al-tsens-Don-t-hardcode-sensor-slope.patch | 28 + ...l-tsens-Convert-msm8960-to-reg_field.patch | 119 + ...al-tsens-Use-init_common-for-msm8960.patch | 81 + ...tsens-Fix-bug-in-sensor-enable-for-m.patch | 66 + ...tsens-Replace-custom-8960-apis-with-.patch | 109 + ...tsens-Drop-unused-define-for-msm8960.patch | 65 + ...-tsens-Add-support-for-ipq8064-tsens.patch | 26 + ...rmal-tsens-Document-ipq8064-bindings.patch | 112 + ...al-tsens-Fix-wrong-slope-on-msm-8960.patch | 32 + ...ns-init-debugfs-only-with-successful.patch | 41 + ...tsens-simplify-debugfs-init-function.patch | 54 + .../850-soc-add-qualcomm-syscon.patch | 121 + ipq806x/patches-5.10/851-add-gsbi1-dts.patch | 44 + .../900-arm-add-cmdline-override.patch | 37 + .../997-device_tree_cmdline.patch | 12 + ...ings-qcom_adm-Fix-channel-specifiers.patch | 71 + ...0030-clk-Disable-i2c-device-on-gsbi4.patch | 40 + ...ically-select-PCI_DOMAINS-if-PCI-is-.patch | 29 + ...le-Add-cpuidle-support-for-QCOM-cpus.patch | 29 + ...arch-arm-force-ZRELADDR-on-arch-qcom.patch | 62 + .../0063-1-ipq806x-tsens-driver.patch | 616 ++ ...sens-support-configurable-interrupts.patch | 437 + .../0063-3-tsens-fix-kernel-5_4.patch | 68 + .../0063-4-ip806x-tsense-rework-driver.patch | 107 + .../0065-arm-override-compiler-flags.patch | 21 + ...Mangle-bootloader-s-kernel-arguments.patch | 210 + .../0069-arm-boot-add-dts-files.patch | 39 + .../0072-add-ipq806x-with-no-clocks.patch | 10 + ...RM-dts-qcom-add-gpio-ranges-property.patch | 70 + ...s-qcom-add-scm-definition-to-ipq806x.patch | 29 + .../patches-5.4/082-ipq8064-dtsi-tweaks.patch | 130 + .../083-ipq8064-dtsi-additions.patch | 1024 +++ .../084-ipq8064-v1.0-dtsi-cleanup.patch | 89 + .../085-ipq8064-v1.0-dtsi-additions.patch | 14 + ...e-scm_call-to-route-GPIO-irq-to-Apps.patch | 104 + ...Fixed-missing-RGMII-pincontrol-defin.patch | 56 + ...t-disable-pretimeout-on-timer-platfo.patch | 98 + ...ed-the-enable-regs-and-mask-for-PRNG.patch | 28 + .../090-v5.8-clk-clk-rpm-fixes.patch | 90 + ...91-v5.8-regulator-add-smb208-support.patch | 63 + ...mem-Add-support-for-krait-based-socs.patch | 361 + ...eq-qcom-fix-wrong-compatible-binding.patch | 26 + ...Use-bulk-clk-api-and-assert-on-error.patch | 228 + ...6x-PCI-qcom-Add-ipq8064-rev2-variant.patch | 36 + ...om-Support-pci-speed-set-for-ipq806x.patch | 74 + ...qcom-cpufreq-nvmem-support-specific-.patch | 51 + ...06x-net-mdio-add-ipq8064-mdio-driver.patch | 216 + ...-add-qcom-ipq806x-dwc-usb-phy-driver.patch | 621 ++ ..._5db-when-device-property-read-fails.patch | 31 + ...q-add-Krait-dedicated-scaling-driver.patch | 681 ++ ...ufreq-add-qcom-krait-cpufreq-binding.patch | 237 + ...add-fab-scaling-support-with-cpufreq.patch | 243 + ...-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch | 83 + ...-v5.11-dmaengine-qcom-add_ADM_driver.patch | 965 ++ ....12-mtd-parsers-Add-Qcom-SMEM-parser.patch | 217 + ...conflicts-with-OpenWrt-auto-mounting.patch | 24 + .../850-soc-add-qualcomm-syscon.patch | 121 + ipq806x/patches-5.4/851-add-gsbi1-dts.patch | 44 + .../900-arm-add-cmdline-override.patch | 37 + .../patches-5.4/997-device_tree_cmdline.patch | 12 + ...9-HAVE_LD_DEAD_CODE_DATA_ELIMINATION.patch | 10 + ...problem-with-platfom-data-in-w1-gpio.patch | 26 + ...s-negative-stack-offsets-on-stack-tr.patch | 57 + ...CPU_MIPS64-for-remaining-MIPS64-CPUs.patch | 37 + .../pending-5.4/110-ehci_hcd_ignore_oc.patch | 79 + ...e_mem_map-with-ARCH_PFN_OFFSET-calcu.patch | 82 + ...0-add-linux-spidev-compatible-si3210.patch | 18 + ...ame2-and-add-RENAME_WHITEOUT-support.patch | 62 + ...41-jffs2-add-RENAME_EXCHANGE-support.patch | 73 + ...ge_allow_receiption_on_disabled_port.patch | 45 + ...et-phy-at803x-add-support-for-AT8032.patch | 63 + ...-rs5c372-support_alarms_up_to_1_week.patch | 94 + ...he_alarm_to_be_used_as_wakeup_source.patch | 70 + .../pending-5.4/201-extra_optimization.patch | 31 + .../203-kallsyms_uncompressed.patch | 119 + .../205-backtrace_module_info.patch | 41 + ...e-filenames-from-deps_initramfs-list.patch | 47 + ...able_wilink_platform_without_drivers.patch | 20 + .../270-platform-mikrotik-build-bits.patch | 31 + .../300-mips_expose_boot_raw.patch | 40 + .../302-mips_no_branch_likely.patch | 22 + .../pending-5.4/305-mips_module_reloc.patch | 371 + .../pending-5.4/307-mips_highmem_offset.patch | 19 + ipq806x/pending-5.4/308-mips32r2_tune.patch | 22 + ...CPU-option-reporting-to-proc-cpuinfo.patch | 142 + .../310-arm_module_unresolved_weak_sym.patch | 22 + ...boot-put-appended-dtb-into-a-section.patch | 36 + ...t-command-line-parameters-from-users.patch | 281 + .../332-arc-add-OWRTDTB-section.patch | 84 + ...able-unaligned-access-in-kernel-mode.patch | 24 + ...ernel-XZ-compression-option-on-PPC_8.patch | 25 + .../400-mtd-add-rootfs-split-support.patch | 107 + ...for-different-partition-parser-types.patch | 142 + ...arsers-for-rootfs-and-firmware-split.patch | 44 + .../403-mtd-hook-mtdsplit-to-Kbuild.patch | 32 + .../404-mtd-add-more-helper-functions.patch | 76 + ...ers-ofpart-fix-parsing-subpartitions.patch | 76 + .../411-mtd-partial_eraseblock_write.patch | 130 + .../412-mtd-partial_eraseblock_unlock.patch | 40 + ...t-add-of_match_table-with-DT-binding.patch | 22 + .../pending-5.4/420-mtd-redboot_space.patch | 41 + ...30-mtd-add-myloader-partition-parser.patch | 229 + ...check-for-bad-blocks-when-calculatin.patch | 68 + ...bcm47xxpart-detect-T_Meter-partition.patch | 37 + ...mtd-add-routerbootpart-parser-config.patch | 38 + ...igadevice-Add-support-for-GD5F4GQ4xC.patch | 87 + ...w-NOR-driver-to-write-fewer-bytes-th.patch | 22 + ...mtd-cfi_cmdset_0002-no-erase_suspend.patch | 25 + ...et_0002-add-buffer-write-cmd-timeout.patch | 17 + ...25p80-mx-disable-software-protection.patch | 18 + ...or-fix-Spansion-regressions-aliased-.patch | 35 + ...ort-limiting-4K-sectors-support-base.patch | 79 + .../476-mtd-spi-nor-add-eon-en25q128.patch | 18 + .../479-mtd-spi-nor-add-xtx-xt25f128b.patch | 42 + .../480-mtd-set-rootfs-to-be-root-dev.patch | 38 + ...or-rework-broken-flash-reset-support.patch | 167 + ...r-add-support-for-Gigadevice-GD25D05.patch | 24 + ...ix-4-byte-opcode-support-for-w25q256.patch | 60 + ...mtd-device-named-ubi-or-data-on-boot.patch | 97 + ...to-create-ubiblock-device-for-rootfs.patch | 66 + ...ting-ubi0-rootfs-in-init-do_mounts.c.patch | 51 + ...ROOT_DEV-to-ubiblock-rootfs-if-unset.patch | 34 + .../494-mtd-ubi-add-EOF-marker-support.patch | 60 + ...-mtd-core-add-get_mtd_device_by_node.patch | 75 + ...-add-bindings-for-mtd-concat-devices.patch | 52 + ...cat-add-dt-driver-for-concat-devices.patch | 216 + ...-mtdconcat-select-readwrite-function.patch | 24 + .../530-jffs2_make_lzma_available.patch | 5180 +++++++++++ ipq806x/pending-5.4/532-jffs2_eofdetect.patch | 65 + .../600-netfilter_conntrack_flush.patch | 88 + ...etfilter_match_bypass_default_checks.patch | 110 + ...netfilter_match_bypass_default_table.patch | 106 + ...netfilter_match_reduce_memory_access.patch | 22 + ...-netfilter_optional_tcp_window_check.patch | 73 + ...del-do-not-defer-queue-length-update.patch | 86 + .../pending-5.4/630-packet_socket_type.patch | 138 + ...w_table-add-hardware-offload-support.patch | 564 ++ ...w_table-support-hw-offload-through-v.patch | 306 + ...-support-hardware-flow-table-offload.patch | 61 + ...-support-hardware-flow-table-offload.patch | 61 + ...-support-hardware-flow-table-offload.patch | 125 + ...w_table-rework-hardware-offload-time.patch | 37 + ...low_table-rework-private-driver-data.patch | 25 + ...-support-hardware-flow-table-offload.patch | 78 + .../pending-5.4/655-increase_skb_pad.patch | 20 + ...Add-support-for-MAP-E-FMRs-mesh-mode.patch | 501 + ...ng-with-source-address-failed-policy.patch | 263 + ...nes-for-_POLICY_FAILED-until-all-cod.patch | 50 + ...T-skip-GRO-for-foreign-MAC-addresses.patch | 149 + .../681-NET-add-of_get_mac_address_mtd.patch | 135 + ...detach-callback-to-struct-phy_driver.patch | 38 + ...l-knob-for-filtering-rx-tx-BPDU-pack.patch | 107 + ...net-phy-at803x-fix-at8033-sgmii-mode.patch | 51 + ...void-tx-fault-with-Nokia-GPON-module.patch | 108 + ...ncomplete-100BASE-FX-and-100BASE-LX-.patch | 52 + ...nterface-mode-from-ethtool-link-mode.patch | 89 + ...p-add-more-extended-compliance-codes.patch | 251 + ...le-start-stop-upstream-notifications.patch | 131 + ...p-move-phy_start-phy_stop-to-phylink.patch | 72 + ...c-add-support-for-Clause-45-accesses.patch | 74 + ...ylink-re-split-__phylink_connect_phy.patch | 93 + ...upport-Clause-45-PHYs-on-SFP-modules.patch | 89 + ...t-link_an_mode-configured-and-curren.patch | 257 + ...link-split-phylink_sfp_module_insert.patch | 120 + ...y-MAC-configuration-for-copper-SFP-m.patch | 201 + ...ke-Broadcom-BCM84881-based-SFPs-work.patch | 59 + ...phy-add-Broadcom-BCM84881-PHY-driver.patch | 315 + ...t-sfp-add-support-for-Clause-45-PHYs.patch | 94 + .../pending-5.4/754-net-sfp-fix-unbind.patch | 28 + .../pending-5.4/755-net-sfp-fix-hwmon.patch | 44 + ...finition-for-the-fault-recovery-atte.patch | 55 + .../757-net-sfp-rename-sm_retries.patch | 60 + ...net-sfp-error-handling-for-phy-probe.patch | 97 + ...9-net-sfp-re-attempt-probing-for-phy.patch | 132 + ...760-net-dsa-mv88e6xxx-fix-vlan-setup.patch | 27 + ...-net-dsa-mt7530-Support-EEE-features.patch | 121 + ...hdev-Refactor-br_switchdev_fdb_notif.patch | 71 + ...hdev-Include-local-flag-in-FDB-notif.patch | 42 + ...hdev-Send-FDB-notifications-for-host.patch | 94 + ...local-addresses-in-assisted-CPU-port.patch | 36 + ...bridge-addresses-in-assisted-CPU-por.patch | 30 + ...tic-FDB-entries-on-foreign-interface.patch | 56 + ...equest-assisted-learning-on-CPU-port.patch | 27 + ...net-mtk_eth_soc-use-napi_consume_skb.patch | 72 + ..._eth_soc-significantly-reduce-mdio-b.patch | 26 + ..._eth_soc-fix-unnecessary-tx-queue-st.patch | 50 + ..._eth_soc-use-larger-burst-size-for-q.patch | 32 + ...-mtk_eth_soc-increase-DMA-ring-sizes.patch | 21 + ..._eth_soc-implement-dynamic-interrupt.patch | 281 + ..._eth_soc-cache-hardware-pointer-of-l.patch | 67 + ..._eth_soc-only-read-the-full-rx-descr.patch | 44 + ..._eth_soc-unmap-rx-data-before-callin.patch | 44 + ..._eth_soc-avoid-rearming-interrupt-if.patch | 35 + ...k_eth_soc-fix-parsing-packets-in-GDM.patch | 67 + ..._eth_soc-set-PPE-flow-hash-as-skb-ha.patch | 41 + ...iatek-mtk_eth_soc-add-support-for-in.patch | 1058 +++ ...iatek-mtk_eth_soc-add-flow-offloadin.patch | 401 + ...ice-struct-copy-its-DMA-params-to-th.patch | 64 + .../810-pci_disable_common_quirks.patch | 62 + .../811-pci_disable_usb_common_quirks.patch | 115 + ...ta-Assign-OF-node-to-the-SCSI-device.patch | 86 + ipq806x/pending-5.4/834-ledtrig-libata.patch | 149 + ...40-hwrng-bcm2835-set-quality-to-1000.patch | 26 + ipq806x/pending-5.4/920-mangle_bootargs.patch | 71 + 647 files changed, 166395 insertions(+) create mode 100644 ipq806x/Makefile create mode 100644 ipq806x/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch create mode 100644 ipq806x/backport-5.4/011-kbuild-export-SUBARCH.patch create mode 100644 ipq806x/backport-5.4/030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch create mode 100644 ipq806x/backport-5.4/031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch create mode 100644 ipq806x/backport-5.4/041-v5.5-arm64-Implement-optimised-checksum-routine.patch create mode 100644 ipq806x/backport-5.4/042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0129-wireguard-do-not-use-O3.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch create mode 100644 ipq806x/backport-5.4/080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch create mode 100644 ipq806x/backport-5.4/300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch create mode 100644 ipq806x/backport-5.4/310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch create mode 100644 ipq806x/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch create mode 100644 ipq806x/backport-5.4/311-MIPS-Fix-exception-handler-memcpy.patch create mode 100644 ipq806x/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch create mode 100644 ipq806x/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch create mode 100644 ipq806x/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch create mode 100644 ipq806x/backport-5.4/393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch create mode 100644 ipq806x/backport-5.4/395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch create mode 100644 ipq806x/backport-5.4/399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch create mode 100644 ipq806x/backport-5.4/400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch create mode 100644 ipq806x/backport-5.4/401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch create mode 100644 ipq806x/backport-5.4/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch create mode 100644 ipq806x/backport-5.4/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch create mode 100644 ipq806x/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch create mode 100644 ipq806x/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch create mode 100644 ipq806x/backport-5.4/405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch create mode 100644 ipq806x/backport-5.4/406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch create mode 100644 ipq806x/backport-5.4/406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch create mode 100644 ipq806x/backport-5.4/406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch create mode 100644 ipq806x/backport-5.4/407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch create mode 100644 ipq806x/backport-5.4/407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch create mode 100644 ipq806x/backport-5.4/410-mtd-fix-calculating-partition-end-address.patch create mode 100644 ipq806x/backport-5.4/600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch create mode 100644 ipq806x/backport-5.4/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch create mode 100644 ipq806x/backport-5.4/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch create mode 100644 ipq806x/backport-5.4/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch create mode 100644 ipq806x/backport-5.4/604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch create mode 100644 ipq806x/backport-5.4/700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch create mode 100644 ipq806x/backport-5.4/716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch create mode 100644 ipq806x/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch create mode 100644 ipq806x/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch create mode 100644 ipq806x/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch create mode 100644 ipq806x/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch create mode 100644 ipq806x/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch create mode 100644 ipq806x/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch create mode 100644 ipq806x/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch create mode 100644 ipq806x/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch create mode 100644 ipq806x/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch create mode 100644 ipq806x/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch create mode 100644 ipq806x/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch create mode 100644 ipq806x/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch create mode 100644 ipq806x/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch create mode 100644 ipq806x/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch create mode 100644 ipq806x/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch create mode 100644 ipq806x/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch create mode 100644 ipq806x/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch create mode 100644 ipq806x/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch create mode 100644 ipq806x/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch create mode 100644 ipq806x/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch create mode 100644 ipq806x/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch create mode 100644 ipq806x/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch create mode 100644 ipq806x/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch create mode 100644 ipq806x/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch create mode 100644 ipq806x/backport-5.4/745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch create mode 100644 ipq806x/backport-5.4/746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch create mode 100644 ipq806x/backport-5.4/747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch create mode 100644 ipq806x/backport-5.4/748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch create mode 100644 ipq806x/backport-5.4/749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch create mode 100644 ipq806x/backport-5.4/750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch create mode 100644 ipq806x/backport-5.4/751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch create mode 100644 ipq806x/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch create mode 100644 ipq806x/backport-5.4/753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch create mode 100644 ipq806x/backport-5.4/756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch create mode 100644 ipq806x/backport-5.4/757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch create mode 100644 ipq806x/backport-5.4/758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch create mode 100644 ipq806x/backport-5.4/760-net-ethernet-mediatek-Integrate-GDM-PSE-setup-operat.patch create mode 100644 ipq806x/backport-5.4/761-net-ethernet-mediatek-Refine-the-timing-of-GDM-PSE-s.patch create mode 100644 ipq806x/backport-5.4/762-net-ethernet-mediatek-Enable-GDM-GDMA_DROP_ALL-mode.patch create mode 100644 ipq806x/backport-5.4/765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch create mode 100644 ipq806x/backport-5.4/770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch create mode 100644 ipq806x/backport-5.4/771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch create mode 100644 ipq806x/backport-5.4/772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch create mode 100644 ipq806x/backport-5.4/773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch create mode 100644 ipq806x/backport-5.4/774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch create mode 100644 ipq806x/backport-5.4/775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch create mode 100644 ipq806x/backport-5.4/780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch create mode 100644 ipq806x/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch create mode 100644 ipq806x/backport-5.4/800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch create mode 100644 ipq806x/backport-5.4/801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch create mode 100644 ipq806x/backport-5.4/801-v5.6-leds-populate-the-device-s-of_node.patch create mode 100644 ipq806x/backport-5.4/803-v5.8-i2c-pxa-use-official-address-byte-helper.patch create mode 100644 ipq806x/backport-5.4/804-v5.8-i2c-pxa-remove-unneeded-includes.patch create mode 100644 ipq806x/backport-5.4/805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch create mode 100644 ipq806x/backport-5.4/806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch create mode 100644 ipq806x/backport-5.4/807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch create mode 100644 ipq806x/backport-5.4/808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch create mode 100644 ipq806x/backport-5.4/809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch create mode 100644 ipq806x/backport-5.4/810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch create mode 100644 ipq806x/backport-5.4/811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch create mode 100644 ipq806x/backport-5.4/813-v5.8-i2c-pxa-clean-up-decode_bits.patch create mode 100644 ipq806x/backport-5.4/814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch create mode 100644 ipq806x/backport-5.4/815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch create mode 100644 ipq806x/backport-5.4/816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch create mode 100644 ipq806x/backport-5.4/817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch create mode 100644 ipq806x/backport-5.4/818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch create mode 100644 ipq806x/backport-5.4/820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch create mode 100644 ipq806x/backport-5.4/821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch create mode 100644 ipq806x/backport-5.4/825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch create mode 100644 ipq806x/backport-5.4/826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch create mode 100644 ipq806x/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch create mode 100644 ipq806x/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch create mode 100644 ipq806x/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch create mode 100644 ipq806x/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch create mode 100644 ipq806x/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch create mode 100644 ipq806x/backport-5.4/999-bpf-off-by-one-backport.patch create mode 100644 ipq806x/backport-5.4/999-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch create mode 100755 ipq806x/base-files/etc/board.d/01_leds create mode 100755 ipq806x/base-files/etc/board.d/02_network create mode 100644 ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata create mode 100644 ipq806x/base-files/etc/hotplug.d/firmware/40-ct-fw-cfg create mode 100644 ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac create mode 100755 ipq806x/base-files/etc/init.d/bootcount create mode 100755 ipq806x/base-files/etc/init.d/cpufreq create mode 100644 ipq806x/base-files/etc/inittab create mode 100644 ipq806x/base-files/etc/uci-defaults/04_led_migration create mode 100644 ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9888.txt create mode 100644 ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9984.txt create mode 100644 ipq806x/base-files/lib/preinit/04_reorder_eth create mode 100644 ipq806x/base-files/lib/preinit/05_set_iface_mac_ipq806x.sh create mode 100644 ipq806x/base-files/lib/upgrade/asrock.sh create mode 100644 ipq806x/base-files/lib/upgrade/buffalo.sh create mode 100644 ipq806x/base-files/lib/upgrade/linksys.sh create mode 100644 ipq806x/base-files/lib/upgrade/platform.sh create mode 100644 ipq806x/base-files/lib/upgrade/zyxel.sh create mode 100755 ipq806x/base-files/sbin/asrock_g10_back_to_factory create mode 100644 ipq806x/config-5.10 create mode 100644 ipq806x/config-5.4 create mode 100644 ipq806x/config-5.4-generic create mode 100644 ipq806x/files-5.4/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml create mode 100644 ipq806x/files-5.4/Documentation/networking/adm6996.txt create mode 100644 ipq806x/files-5.4/arch/mips/fw/myloader/Makefile create mode 100644 ipq806x/files-5.4/arch/mips/fw/myloader/myloader.c create mode 100644 ipq806x/files-5.4/block/partitions/fit.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/Kconfig create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/Makefile create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.h create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_brnimage.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_elf.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_eva.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_fit.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_jimage.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_lzma.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_minor.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_seama.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_squashfs.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_tplink.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_trx.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_uimage.c create mode 100644 ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_wrgg.c create mode 100644 ipq806x/files-5.4/drivers/mtd/parsers/routerbootpart.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/adm6996.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/adm6996.h create mode 100644 ipq806x/files-5.4/drivers/net/phy/ar8216.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/ar8216.h create mode 100644 ipq806x/files-5.4/drivers/net/phy/ar8327.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/ar8327.h create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/Kconfig create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/Makefile create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_common.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_mdio.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_mmap.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_phy_fixup.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_priv.h create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_regs.h create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_spi.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/b53/b53_srab.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/ip17xx.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/mvswitch.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/mvswitch.h create mode 100644 ipq806x/files-5.4/drivers/net/phy/psb6970.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/rtl8306.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.h create mode 100644 ipq806x/files-5.4/drivers/net/phy/rtl8366rb.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/rtl8366s.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/rtl8367.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/rtl8367b.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/swconfig.c create mode 100644 ipq806x/files-5.4/drivers/net/phy/swconfig_leds.c create mode 100644 ipq806x/files-5.4/drivers/platform/mikrotik/Kconfig create mode 100644 ipq806x/files-5.4/drivers/platform/mikrotik/Makefile create mode 100644 ipq806x/files-5.4/drivers/platform/mikrotik/rb_hardconfig.c create mode 100644 ipq806x/files-5.4/drivers/platform/mikrotik/rb_softconfig.c create mode 100644 ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.c create mode 100644 ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.h create mode 100644 ipq806x/files-5.4/include/dt-bindings/mtd/partitions/uimage.h create mode 100644 ipq806x/files-5.4/include/linux/ar8216_platform.h create mode 100644 ipq806x/files-5.4/include/linux/ath5k_platform.h create mode 100644 ipq806x/files-5.4/include/linux/ath9k_platform.h create mode 100644 ipq806x/files-5.4/include/linux/myloader.h create mode 100644 ipq806x/files-5.4/include/linux/platform_data/adm6996-gpio.h create mode 100644 ipq806x/files-5.4/include/linux/routerboot.h create mode 100644 ipq806x/files-5.4/include/linux/rt2x00_platform.h create mode 100644 ipq806x/files-5.4/include/linux/rtl8366.h create mode 100644 ipq806x/files-5.4/include/linux/rtl8367.h create mode 100644 ipq806x/files-5.4/include/linux/switch.h create mode 100644 ipq806x/files-5.4/include/uapi/linux/switch.h create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-db149.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts create mode 100644 ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ssw2ac2600.dts create mode 100644 ipq806x/generic/target.mk create mode 100644 ipq806x/hack-5.4/204-module_strip.patch create mode 100644 ipq806x/hack-5.4/210-darwin_scripts_include.patch create mode 100644 ipq806x/hack-5.4/211-darwin-uuid-typedef-clash.patch create mode 100644 ipq806x/hack-5.4/212-tools_portability.patch create mode 100644 ipq806x/hack-5.4/214-spidev_h_portability.patch create mode 100644 ipq806x/hack-5.4/220-gc_sections.patch create mode 100644 ipq806x/hack-5.4/221-module_exports.patch create mode 100644 ipq806x/hack-5.4/230-openwrt_lzma_options.patch create mode 100644 ipq806x/hack-5.4/249-udp-tunnel-selection.patch create mode 100644 ipq806x/hack-5.4/250-netfilter_depends.patch create mode 100644 ipq806x/hack-5.4/251-sound_kconfig.patch create mode 100644 ipq806x/hack-5.4/259-regmap_dynamic.patch create mode 100644 ipq806x/hack-5.4/260-crypto_test_dependencies.patch create mode 100644 ipq806x/hack-5.4/260-lib-arc4-unhide.patch create mode 100644 ipq806x/hack-5.4/280-rfkill-stubs.patch create mode 100644 ipq806x/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch create mode 100644 ipq806x/hack-5.4/301-mips_image_cmdline_hack.patch create mode 100644 ipq806x/hack-5.4/321-powerpc_crtsavres_prereq.patch create mode 100644 ipq806x/hack-5.4/400-unlock_mx25l6406e_with_4bit_block_protect.patch create mode 100644 ipq806x/hack-5.4/531-debloat_lzma.patch create mode 100644 ipq806x/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch create mode 100644 ipq806x/hack-5.4/640-bridge-only-accept-EAP-locally.patch create mode 100644 ipq806x/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch create mode 100644 ipq806x/hack-5.4/647-netfilter-flow-acct.patch create mode 100644 ipq806x/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch create mode 100644 ipq806x/hack-5.4/651-wireless_mesh_header.patch create mode 100644 ipq806x/hack-5.4/660-fq_codel_defaults.patch create mode 100644 ipq806x/hack-5.4/661-use_fq_codel_by_default.patch create mode 100644 ipq806x/hack-5.4/662-remove_pfifo_fast.patch create mode 100644 ipq806x/hack-5.4/700-swconfig_switch_drivers.patch create mode 100644 ipq806x/hack-5.4/703-add_vsc8504_support.patch create mode 100644 ipq806x/hack-5.4/710-net-dsa-mv88e6xxx-default-VID-1.patch create mode 100644 ipq806x/hack-5.4/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch create mode 100644 ipq806x/hack-5.4/721-phy_packets.patch create mode 100644 ipq806x/hack-5.4/773-bgmac-add-srab-switch.patch create mode 100644 ipq806x/hack-5.4/901-debloat_sock_diag.patch create mode 100644 ipq806x/hack-5.4/902-debloat_proc.patch create mode 100644 ipq806x/hack-5.4/904-debloat_dma_buf.patch create mode 100644 ipq806x/hack-5.4/910-kobject_uevent.patch create mode 100644 ipq806x/hack-5.4/911-kobject_add_broadcast_uevent.patch create mode 100644 ipq806x/hack-5.4/921-always-create-console-node-in-initramfs.patch create mode 100644 ipq806x/image/Makefile create mode 100644 ipq806x/modules.mk create mode 100644 ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch create mode 100644 ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch create mode 100644 ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch create mode 100644 ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch create mode 100644 ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch create mode 100644 ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch create mode 100644 ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch create mode 100644 ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch create mode 100644 ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch create mode 100644 ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch create mode 100644 ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch create mode 100644 ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch create mode 100644 ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch create mode 100644 ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch create mode 100644 ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch create mode 100644 ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch create mode 100644 ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch create mode 100644 ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch create mode 100644 ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch create mode 100644 ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch create mode 100644 ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch create mode 100644 ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch create mode 100644 ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch create mode 100644 ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch create mode 100644 ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch create mode 100644 ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch create mode 100644 ipq806x/patches-5.10/103-ARM-dts-qcom-reduce-pci-IO-size-to-64K.patch create mode 100644 ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch create mode 100644 ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch create mode 100644 ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch create mode 100644 ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch create mode 100644 ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch create mode 100644 ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch create mode 100644 ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch create mode 100644 ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch create mode 100644 ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch create mode 100644 ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch create mode 100644 ipq806x/patches-5.10/107-1-thermal-qcom-tsens-init-debugfs-only-with-successful.patch create mode 100644 ipq806x/patches-5.10/107-2-thermal-qcom-tsens-simplify-debugfs-init-function.patch create mode 100644 ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch create mode 100644 ipq806x/patches-5.10/851-add-gsbi1-dts.patch create mode 100644 ipq806x/patches-5.10/900-arm-add-cmdline-override.patch create mode 100644 ipq806x/patches-5.10/997-device_tree_cmdline.patch create mode 100644 ipq806x/patches-5.4/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch create mode 100644 ipq806x/patches-5.4/0030-clk-Disable-i2c-device-on-gsbi4.patch create mode 100644 ipq806x/patches-5.4/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch create mode 100644 ipq806x/patches-5.4/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch create mode 100644 ipq806x/patches-5.4/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch create mode 100644 ipq806x/patches-5.4/0063-1-ipq806x-tsens-driver.patch create mode 100644 ipq806x/patches-5.4/0063-2-tsens-support-configurable-interrupts.patch create mode 100644 ipq806x/patches-5.4/0063-3-tsens-fix-kernel-5_4.patch create mode 100644 ipq806x/patches-5.4/0063-4-ip806x-tsense-rework-driver.patch create mode 100644 ipq806x/patches-5.4/0065-arm-override-compiler-flags.patch create mode 100644 ipq806x/patches-5.4/0067-generic-Mangle-bootloader-s-kernel-arguments.patch create mode 100644 ipq806x/patches-5.4/0069-arm-boot-add-dts-files.patch create mode 100644 ipq806x/patches-5.4/0072-add-ipq806x-with-no-clocks.patch create mode 100644 ipq806x/patches-5.4/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch create mode 100644 ipq806x/patches-5.4/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch create mode 100644 ipq806x/patches-5.4/082-ipq8064-dtsi-tweaks.patch create mode 100644 ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch create mode 100644 ipq806x/patches-5.4/084-ipq8064-v1.0-dtsi-cleanup.patch create mode 100644 ipq806x/patches-5.4/085-ipq8064-v1.0-dtsi-additions.patch create mode 100644 ipq806x/patches-5.4/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch create mode 100644 ipq806x/patches-5.4/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch create mode 100644 ipq806x/patches-5.4/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch create mode 100644 ipq806x/patches-5.4/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch create mode 100644 ipq806x/patches-5.4/090-v5.8-clk-clk-rpm-fixes.patch create mode 100644 ipq806x/patches-5.4/091-v5.8-regulator-add-smb208-support.patch create mode 100644 ipq806x/patches-5.4/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch create mode 100644 ipq806x/patches-5.4/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch create mode 100644 ipq806x/patches-5.4/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch create mode 100644 ipq806x/patches-5.4/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch create mode 100644 ipq806x/patches-5.4/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch create mode 100644 ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch create mode 100644 ipq806x/patches-5.4/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch create mode 100644 ipq806x/patches-5.4/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch create mode 100644 ipq806x/patches-5.4/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch create mode 100644 ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch create mode 100644 ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch create mode 100644 ipq806x/patches-5.4/098-3-add-fab-scaling-support-with-cpufreq.patch create mode 100644 ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch create mode 100644 ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch create mode 100644 ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch create mode 100644 ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch create mode 100644 ipq806x/patches-5.4/850-soc-add-qualcomm-syscon.patch create mode 100644 ipq806x/patches-5.4/851-add-gsbi1-dts.patch create mode 100644 ipq806x/patches-5.4/900-arm-add-cmdline-override.patch create mode 100644 ipq806x/patches-5.4/997-device_tree_cmdline.patch create mode 100644 ipq806x/patches-5.4/999-HAVE_LD_DEAD_CODE_DATA_ELIMINATION.patch create mode 100644 ipq806x/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch create mode 100644 ipq806x/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch create mode 100644 ipq806x/pending-5.4/103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch create mode 100644 ipq806x/pending-5.4/110-ehci_hcd_ignore_oc.patch create mode 100644 ipq806x/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch create mode 100644 ipq806x/pending-5.4/130-add-linux-spidev-compatible-si3210.patch create mode 100644 ipq806x/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch create mode 100644 ipq806x/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch create mode 100644 ipq806x/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch create mode 100644 ipq806x/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch create mode 100644 ipq806x/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch create mode 100644 ipq806x/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch create mode 100644 ipq806x/pending-5.4/201-extra_optimization.patch create mode 100644 ipq806x/pending-5.4/203-kallsyms_uncompressed.patch create mode 100644 ipq806x/pending-5.4/205-backtrace_module_info.patch create mode 100644 ipq806x/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch create mode 100644 ipq806x/pending-5.4/261-enable_wilink_platform_without_drivers.patch create mode 100644 ipq806x/pending-5.4/270-platform-mikrotik-build-bits.patch create mode 100644 ipq806x/pending-5.4/300-mips_expose_boot_raw.patch create mode 100644 ipq806x/pending-5.4/302-mips_no_branch_likely.patch create mode 100644 ipq806x/pending-5.4/305-mips_module_reloc.patch create mode 100644 ipq806x/pending-5.4/307-mips_highmem_offset.patch create mode 100644 ipq806x/pending-5.4/308-mips32r2_tune.patch create mode 100644 ipq806x/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch create mode 100644 ipq806x/pending-5.4/310-arm_module_unresolved_weak_sym.patch create mode 100644 ipq806x/pending-5.4/311-MIPS-zboot-put-appended-dtb-into-a-section.patch create mode 100644 ipq806x/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch create mode 100644 ipq806x/pending-5.4/332-arc-add-OWRTDTB-section.patch create mode 100644 ipq806x/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch create mode 100644 ipq806x/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch create mode 100644 ipq806x/pending-5.4/400-mtd-add-rootfs-split-support.patch create mode 100644 ipq806x/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch create mode 100644 ipq806x/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch create mode 100644 ipq806x/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch create mode 100644 ipq806x/pending-5.4/404-mtd-add-more-helper-functions.patch create mode 100644 ipq806x/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch create mode 100644 ipq806x/pending-5.4/411-mtd-partial_eraseblock_write.patch create mode 100644 ipq806x/pending-5.4/412-mtd-partial_eraseblock_unlock.patch create mode 100644 ipq806x/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch create mode 100644 ipq806x/pending-5.4/420-mtd-redboot_space.patch create mode 100644 ipq806x/pending-5.4/430-mtd-add-myloader-partition-parser.patch create mode 100644 ipq806x/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch create mode 100644 ipq806x/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch create mode 100644 ipq806x/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch create mode 100644 ipq806x/pending-5.4/447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch create mode 100644 ipq806x/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch create mode 100644 ipq806x/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch create mode 100644 ipq806x/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch create mode 100644 ipq806x/pending-5.4/465-m25p80-mx-disable-software-protection.patch create mode 100644 ipq806x/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch create mode 100644 ipq806x/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch create mode 100644 ipq806x/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch create mode 100644 ipq806x/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch create mode 100644 ipq806x/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch create mode 100644 ipq806x/pending-5.4/481-mtd-spi-nor-rework-broken-flash-reset-support.patch create mode 100644 ipq806x/pending-5.4/482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch create mode 100644 ipq806x/pending-5.4/482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch create mode 100644 ipq806x/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch create mode 100644 ipq806x/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch create mode 100644 ipq806x/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch create mode 100644 ipq806x/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch create mode 100644 ipq806x/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch create mode 100644 ipq806x/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch create mode 100644 ipq806x/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch create mode 100644 ipq806x/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch create mode 100644 ipq806x/pending-5.4/498-mtd-mtdconcat-select-readwrite-function.patch create mode 100644 ipq806x/pending-5.4/530-jffs2_make_lzma_available.patch create mode 100644 ipq806x/pending-5.4/532-jffs2_eofdetect.patch create mode 100644 ipq806x/pending-5.4/600-netfilter_conntrack_flush.patch create mode 100644 ipq806x/pending-5.4/610-netfilter_match_bypass_default_checks.patch create mode 100644 ipq806x/pending-5.4/611-netfilter_match_bypass_default_table.patch create mode 100644 ipq806x/pending-5.4/612-netfilter_match_reduce_memory_access.patch create mode 100644 ipq806x/pending-5.4/613-netfilter_optional_tcp_window_check.patch create mode 100644 ipq806x/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch create mode 100644 ipq806x/pending-5.4/630-packet_socket_type.patch create mode 100644 ipq806x/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch create mode 100644 ipq806x/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch create mode 100644 ipq806x/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch create mode 100644 ipq806x/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch create mode 100644 ipq806x/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch create mode 100644 ipq806x/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch create mode 100644 ipq806x/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch create mode 100644 ipq806x/pending-5.4/647-net-dsa-support-hardware-flow-table-offload.patch create mode 100644 ipq806x/pending-5.4/655-increase_skb_pad.patch create mode 100644 ipq806x/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch create mode 100644 ipq806x/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch create mode 100644 ipq806x/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch create mode 100644 ipq806x/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch create mode 100644 ipq806x/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch create mode 100644 ipq806x/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch create mode 100644 ipq806x/pending-5.4/710-bridge-add-sysctl-knob-for-filtering-rx-tx-BPDU-pack.patch create mode 100644 ipq806x/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch create mode 100644 ipq806x/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch create mode 100644 ipq806x/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch create mode 100644 ipq806x/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch create mode 100644 ipq806x/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch create mode 100644 ipq806x/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch create mode 100644 ipq806x/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch create mode 100644 ipq806x/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch create mode 100644 ipq806x/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch create mode 100644 ipq806x/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch create mode 100644 ipq806x/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch create mode 100644 ipq806x/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch create mode 100644 ipq806x/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch create mode 100644 ipq806x/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch create mode 100644 ipq806x/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch create mode 100644 ipq806x/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch create mode 100644 ipq806x/pending-5.4/754-net-sfp-fix-unbind.patch create mode 100644 ipq806x/pending-5.4/755-net-sfp-fix-hwmon.patch create mode 100644 ipq806x/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch create mode 100644 ipq806x/pending-5.4/757-net-sfp-rename-sm_retries.patch create mode 100644 ipq806x/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch create mode 100644 ipq806x/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch create mode 100644 ipq806x/pending-5.4/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch create mode 100644 ipq806x/pending-5.4/761-net-dsa-mt7530-Support-EEE-features.patch create mode 100644 ipq806x/pending-5.4/762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch create mode 100644 ipq806x/pending-5.4/763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch create mode 100644 ipq806x/pending-5.4/764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch create mode 100644 ipq806x/pending-5.4/765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch create mode 100644 ipq806x/pending-5.4/766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch create mode 100644 ipq806x/pending-5.4/767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch create mode 100644 ipq806x/pending-5.4/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch create mode 100644 ipq806x/pending-5.4/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch create mode 100644 ipq806x/pending-5.4/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch create mode 100644 ipq806x/pending-5.4/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch create mode 100644 ipq806x/pending-5.4/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch create mode 100644 ipq806x/pending-5.4/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch create mode 100644 ipq806x/pending-5.4/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch create mode 100644 ipq806x/pending-5.4/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch create mode 100644 ipq806x/pending-5.4/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch create mode 100644 ipq806x/pending-5.4/770-10-net-ethernet-mtk_eth_soc-unmap-rx-data-before-callin.patch create mode 100644 ipq806x/pending-5.4/770-11-net-ethernet-mtk_eth_soc-avoid-rearming-interrupt-if.patch create mode 100644 ipq806x/pending-5.4/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch create mode 100644 ipq806x/pending-5.4/770-14-net-ethernet-mtk_eth_soc-set-PPE-flow-hash-as-skb-ha.patch create mode 100644 ipq806x/pending-5.4/770-15-net-ethernet-mediatek-mtk_eth_soc-add-support-for-in.patch create mode 100644 ipq806x/pending-5.4/770-16-net-ethernet-mediatek-mtk_eth_soc-add-flow-offloadin.patch create mode 100644 ipq806x/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch create mode 100644 ipq806x/pending-5.4/810-pci_disable_common_quirks.patch create mode 100644 ipq806x/pending-5.4/811-pci_disable_usb_common_quirks.patch create mode 100644 ipq806x/pending-5.4/820-libata-Assign-OF-node-to-the-SCSI-device.patch create mode 100644 ipq806x/pending-5.4/834-ledtrig-libata.patch create mode 100644 ipq806x/pending-5.4/840-hwrng-bcm2835-set-quality-to-1000.patch create mode 100644 ipq806x/pending-5.4/920-mangle_bootargs.patch diff --git a/ipq806x/Makefile b/ipq806x/Makefile new file mode 100644 index 0000000..97d8ead --- /dev/null +++ b/ipq806x/Makefile @@ -0,0 +1,33 @@ +# Copyright (c) 2013 The Linux Foundation. All rights reserved. +# +include $(TOPDIR)/rules.mk + +ARCH:=arm +BOARD:=ipq806x +BOARDNAME:=Qualcomm Atheros IPQ806X +FEATURES:=squashfs nand fpu ramdisk +CPU_TYPE:=cortex-a15 +CPU_SUBTYPE:=neon-vfpv4 +SUBTARGETS:=generic + +KERNEL_PATCHVER:=5.4 +KERNEL_TESTING_PATCHVER:=5.10 + +KERNELNAME:=zImage Image dtbs + +GENERIC_BACKPORT_DIR := ${CURDIR}/backport-$(KERNEL_PATCHVER) +GENERIC_PATCH_DIR := ${CURDIR}/pending-$(KERNEL_PATCHVER) +GENERIC_HACK_DIR := ${CURDIR}/hack-$(KERNEL_PATCHVER) +GENERIC_FILES_DIR := ${CURDIR}/files-$(KERNEL_PATCHVER) +GENERIC_LINUX_CONFIG:=${CURDIR}/config-$(KERNEL_PATCHVER)-generic + +include $(INCLUDE_DIR)/target.mk +DEFAULT_PACKAGES += \ + kmod-leds-gpio kmod-gpio-button-hotplug swconfig \ + kmod-ata-ahci kmod-ata-ahci-platform \ + kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport \ + kmod-phy-qcom-ipq806x-usb kmod-usb3 kmod-usb-dwc3-qcom \ + kmod-ath10k-ct wpad-basic-wolfssl \ + uboot-envtools + +$(eval $(call BuildTarget)) diff --git a/ipq806x/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch b/ipq806x/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch new file mode 100644 index 0000000..7ac4f9d --- /dev/null +++ b/ipq806x/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch @@ -0,0 +1,30 @@ +From 13b1ecc3401653a355798eb1dee10cc1608202f4 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +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 +--- + 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/ipq806x/backport-5.4/011-kbuild-export-SUBARCH.patch b/ipq806x/backport-5.4/011-kbuild-export-SUBARCH.patch new file mode 100644 index 0000000..60defa3 --- /dev/null +++ b/ipq806x/backport-5.4/011-kbuild-export-SUBARCH.patch @@ -0,0 +1,21 @@ +From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +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 +--- + Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -493,7 +493,7 @@ KBUILD_LDFLAGS := + GCC_PLUGINS_CFLAGS := + CLANG_FLAGS := + +-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC ++export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC + export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE READELF PAHOLE LEX YACC AWK INSTALLKERNEL + export PERL PYTHON PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX + export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ diff --git a/ipq806x/backport-5.4/030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch b/ipq806x/backport-5.4/030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch new file mode 100644 index 0000000..cf88c0c --- /dev/null +++ b/ipq806x/backport-5.4/030-modpost-add-a-helper-to-get-data-pointed-by-a-symbol.patch @@ -0,0 +1,53 @@ +From afa0459daa7b08c7b2c879705b69d39b734a11d0 Mon Sep 17 00:00:00 2001 +From: Masahiro Yamada +Date: Fri, 15 Nov 2019 02:42:21 +0900 +Subject: [PATCH] modpost: add a helper to get data pointed by a symbol + +When CONFIG_MODULE_REL_CRCS is enabled, the value of __crc_* is not +an absolute value, but the address to the CRC data embedded in the +.rodata section. + +Getting the data pointed by the symbol value is somewhat complex. +Split it out into a new helper, sym_get_data(). + +I will reuse it to refactor namespace_from_kstrtabns() in the next +commit. + +Signed-off-by: Masahiro Yamada +--- + scripts/mod/modpost.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -312,6 +312,18 @@ static const char *sec_name(struct elf_i + return sech_name(elf, &elf->sechdrs[secindex]); + } + ++static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym) ++{ ++ Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx]; ++ unsigned long offset; ++ ++ offset = sym->st_value; ++ if (info->hdr->e_type != ET_REL) ++ offset -= sechdr->sh_addr; ++ ++ return (void *)info->hdr + sechdr->sh_offset + offset; ++} ++ + #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) + + static enum export export_from_secname(struct elf_info *elf, unsigned int sec) +@@ -701,10 +713,7 @@ static void handle_modversions(struct mo + unsigned int *crcp; + + /* symbol points to the CRC in the ELF object */ +- crcp = (void *)info->hdr + sym->st_value + +- info->sechdrs[sym->st_shndx].sh_offset - +- (info->hdr->e_type != ET_REL ? +- info->sechdrs[sym->st_shndx].sh_addr : 0); ++ crcp = sym_get_data(info, sym); + crc = TO_NATIVE(*crcp); + } + sym_update_crc(symname + strlen("__crc_"), mod, crc, diff --git a/ipq806x/backport-5.4/031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch b/ipq806x/backport-5.4/031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch new file mode 100644 index 0000000..230dc6b --- /dev/null +++ b/ipq806x/backport-5.4/031-modpost-refactor-namespace_from_kstrtabns-to-not-har.patch @@ -0,0 +1,62 @@ +From e84f9fbbece1585f45a03ccc11eeabe121cadc1b Mon Sep 17 00:00:00 2001 +From: Masahiro Yamada +Date: Fri, 15 Nov 2019 02:42:22 +0900 +Subject: [PATCH] modpost: refactor namespace_from_kstrtabns() to not hard-code + section name + +Currently, namespace_from_kstrtabns() relies on the fact that +namespace strings are recorded in the __ksymtab_strings section. +Actually, it is coded in include/linux/export.h, but modpost does +not need to hard-code the section name. + +Elf_Sym::st_shndx holds the index of the relevant section. Using it is +a more portable way to get the namespace string. + +Make namespace_from_kstrtabns() simply call sym_get_data(), and delete +the info->ksymtab_strings . + +While I was here, I added more 'const' qualifiers to pointers. + +Signed-off-by: Masahiro Yamada +--- + scripts/mod/modpost.c | 10 +++------- + scripts/mod/modpost.h | 1 - + 2 files changed, 3 insertions(+), 8 deletions(-) + +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -360,10 +360,10 @@ static enum export export_from_sec(struc + return export_unknown; + } + +-static const char *namespace_from_kstrtabns(struct elf_info *info, +- Elf_Sym *kstrtabns) ++static const char *namespace_from_kstrtabns(const struct elf_info *info, ++ const Elf_Sym *sym) + { +- char *value = info->ksymtab_strings + kstrtabns->st_value; ++ const char *value = sym_get_data(info, sym); + return value[0] ? value : NULL; + } + +@@ -605,10 +605,6 @@ static int parse_elf(struct elf_info *in + info->export_unused_gpl_sec = i; + else if (strcmp(secname, "__ksymtab_gpl_future") == 0) + info->export_gpl_future_sec = i; +- else if (strcmp(secname, "__ksymtab_strings") == 0) +- info->ksymtab_strings = (void *)hdr + +- sechdrs[i].sh_offset - +- sechdrs[i].sh_addr; + + if (sechdrs[i].sh_type == SHT_SYMTAB) { + unsigned int sh_link_idx; +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -143,7 +143,6 @@ struct elf_info { + Elf_Section export_gpl_sec; + Elf_Section export_unused_gpl_sec; + Elf_Section export_gpl_future_sec; +- char *ksymtab_strings; + char *strtab; + char *modinfo; + unsigned int modinfo_len; diff --git a/ipq806x/backport-5.4/041-v5.5-arm64-Implement-optimised-checksum-routine.patch b/ipq806x/backport-5.4/041-v5.5-arm64-Implement-optimised-checksum-routine.patch new file mode 100644 index 0000000..00ec7d0 --- /dev/null +++ b/ipq806x/backport-5.4/041-v5.5-arm64-Implement-optimised-checksum-routine.patch @@ -0,0 +1,176 @@ +From: Robin Murphy +Date: Wed, 15 Jan 2020 16:42:39 +0000 +Subject: [PATCH] arm64: Implement optimised checksum routine + +Apparently there exist certain workloads which rely heavily on software +checksumming, for which the generic do_csum() implementation becomes a +significant bottleneck. Therefore let's give arm64 its own optimised +version - for ease of maintenance this foregoes assembly or intrisics, +and is thus not actually arm64-specific, but does rely heavily on C +idioms that translate well to the A64 ISA and the typical load/store +capabilities of most ARMv8 CPU cores. + +The resulting increase in checksum throughput scales nicely with buffer +size, tending towards 4x for a small in-order core (Cortex-A53), and up +to 6x or more for an aggressive big core (Ampere eMAG). + +Reported-by: Lingyan Huang +Tested-by: Lingyan Huang +Signed-off-by: Robin Murphy +Signed-off-by: Will Deacon +--- + create mode 100644 arch/arm64/lib/csum.c + +--- a/arch/arm64/include/asm/checksum.h ++++ b/arch/arm64/include/asm/checksum.h +@@ -36,6 +36,9 @@ static inline __sum16 ip_fast_csum(const + } + #define ip_fast_csum ip_fast_csum + ++extern unsigned int do_csum(const unsigned char *buff, int len); ++#define do_csum do_csum ++ + #include + + #endif /* __ASM_CHECKSUM_H */ +--- a/arch/arm64/lib/Makefile ++++ b/arch/arm64/lib/Makefile +@@ -1,9 +1,9 @@ + # SPDX-License-Identifier: GPL-2.0 + lib-y := clear_user.o delay.o copy_from_user.o \ + copy_to_user.o copy_in_user.o copy_page.o \ +- clear_page.o memchr.o memcpy.o memmove.o memset.o \ +- memcmp.o strcmp.o strncmp.o strlen.o strnlen.o \ +- strchr.o strrchr.o tishift.o ++ clear_page.o csum.o memchr.o memcpy.o memmove.o \ ++ memset.o memcmp.o strcmp.o strncmp.o strlen.o \ ++ strnlen.o strchr.o strrchr.o tishift.o + + ifeq ($(CONFIG_KERNEL_MODE_NEON), y) + obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o +--- /dev/null ++++ b/arch/arm64/lib/csum.c +@@ -0,0 +1,123 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++// Copyright (C) 2019-2020 Arm Ltd. ++ ++#include ++#include ++#include ++ ++#include ++ ++/* Looks dumb, but generates nice-ish code */ ++static u64 accumulate(u64 sum, u64 data) ++{ ++ __uint128_t tmp = (__uint128_t)sum + data; ++ return tmp + (tmp >> 64); ++} ++ ++unsigned int do_csum(const unsigned char *buff, int len) ++{ ++ unsigned int offset, shift, sum; ++ const u64 *ptr; ++ u64 data, sum64 = 0; ++ ++ offset = (unsigned long)buff & 7; ++ /* ++ * This is to all intents and purposes safe, since rounding down cannot ++ * result in a different page or cache line being accessed, and @buff ++ * should absolutely not be pointing to anything read-sensitive. We do, ++ * however, have to be careful not to piss off KASAN, which means using ++ * unchecked reads to accommodate the head and tail, for which we'll ++ * compensate with an explicit check up-front. ++ */ ++ kasan_check_read(buff, len); ++ ptr = (u64 *)(buff - offset); ++ len = len + offset - 8; ++ ++ /* ++ * Head: zero out any excess leading bytes. Shifting back by the same ++ * amount should be at least as fast as any other way of handling the ++ * odd/even alignment, and means we can ignore it until the very end. ++ */ ++ shift = offset * 8; ++ data = READ_ONCE_NOCHECK(*ptr++); ++#ifdef __LITTLE_ENDIAN ++ data = (data >> shift) << shift; ++#else ++ data = (data << shift) >> shift; ++#endif ++ ++ /* ++ * Body: straightforward aligned loads from here on (the paired loads ++ * underlying the quadword type still only need dword alignment). The ++ * main loop strictly excludes the tail, so the second loop will always ++ * run at least once. ++ */ ++ while (unlikely(len > 64)) { ++ __uint128_t tmp1, tmp2, tmp3, tmp4; ++ ++ tmp1 = READ_ONCE_NOCHECK(*(__uint128_t *)ptr); ++ tmp2 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 2)); ++ tmp3 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 4)); ++ tmp4 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 6)); ++ ++ len -= 64; ++ ptr += 8; ++ ++ /* This is the "don't dump the carry flag into a GPR" idiom */ ++ tmp1 += (tmp1 >> 64) | (tmp1 << 64); ++ tmp2 += (tmp2 >> 64) | (tmp2 << 64); ++ tmp3 += (tmp3 >> 64) | (tmp3 << 64); ++ tmp4 += (tmp4 >> 64) | (tmp4 << 64); ++ tmp1 = ((tmp1 >> 64) << 64) | (tmp2 >> 64); ++ tmp1 += (tmp1 >> 64) | (tmp1 << 64); ++ tmp3 = ((tmp3 >> 64) << 64) | (tmp4 >> 64); ++ tmp3 += (tmp3 >> 64) | (tmp3 << 64); ++ tmp1 = ((tmp1 >> 64) << 64) | (tmp3 >> 64); ++ tmp1 += (tmp1 >> 64) | (tmp1 << 64); ++ tmp1 = ((tmp1 >> 64) << 64) | sum64; ++ tmp1 += (tmp1 >> 64) | (tmp1 << 64); ++ sum64 = tmp1 >> 64; ++ } ++ while (len > 8) { ++ __uint128_t tmp; ++ ++ sum64 = accumulate(sum64, data); ++ tmp = READ_ONCE_NOCHECK(*(__uint128_t *)ptr); ++ ++ len -= 16; ++ ptr += 2; ++ ++#ifdef __LITTLE_ENDIAN ++ data = tmp >> 64; ++ sum64 = accumulate(sum64, tmp); ++#else ++ data = tmp; ++ sum64 = accumulate(sum64, tmp >> 64); ++#endif ++ } ++ if (len > 0) { ++ sum64 = accumulate(sum64, data); ++ data = READ_ONCE_NOCHECK(*ptr); ++ len -= 8; ++ } ++ /* ++ * Tail: zero any over-read bytes similarly to the head, again ++ * preserving odd/even alignment. ++ */ ++ shift = len * -8; ++#ifdef __LITTLE_ENDIAN ++ data = (data << shift) >> shift; ++#else ++ data = (data >> shift) << shift; ++#endif ++ sum64 = accumulate(sum64, data); ++ ++ /* Finally, folding */ ++ sum64 += (sum64 >> 32) | (sum64 << 32); ++ sum = sum64 >> 32; ++ sum += (sum >> 16) | (sum << 16); ++ if (offset & 1) ++ return (u16)swab32(sum); ++ ++ return sum >> 16; ++} diff --git a/ipq806x/backport-5.4/042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch b/ipq806x/backport-5.4/042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch new file mode 100644 index 0000000..50b210e --- /dev/null +++ b/ipq806x/backport-5.4/042-v5.5-arm64-csum-Fix-pathological-zero-length-calls.patch @@ -0,0 +1,28 @@ +From: Robin Murphy +Date: Fri, 17 Jan 2020 15:48:39 +0000 +Subject: [PATCH] arm64: csum: Fix pathological zero-length calls + +In validating the checksumming results of the new routine, I sadly +neglected to test its not-checksumming results. Thus it slipped through +that the one case where @buff is already dword-aligned and @len = 0 +manages to defeat the tail-masking logic and behave as if @len = 8. +For a zero length it doesn't make much sense to deference @buff anyway, +so just add an early return (which has essentially zero impact on +performance). + +Signed-off-by: Robin Murphy +Signed-off-by: Will Deacon +--- + +--- a/arch/arm64/lib/csum.c ++++ b/arch/arm64/lib/csum.c +@@ -20,6 +20,9 @@ unsigned int do_csum(const unsigned char + const u64 *ptr; + u64 data, sum64 = 0; + ++ if (unlikely(len == 0)) ++ return 0; ++ + offset = (unsigned long)buff & 7; + /* + * This is to all intents and purposes safe, since rounding down cannot diff --git a/ipq806x/backport-5.4/080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch b/ipq806x/backport-5.4/080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch new file mode 100644 index 0000000..e32e18a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0001-crypto-lib-tidy-up-lib-crypto-Kconfig-and-Makefile.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:07 +0100 +Subject: [PATCH] crypto: lib - tidy up lib/crypto Kconfig and Makefile + +commit 746b2e024c67aa605ac12d135cd7085a49cf9dc4 upstream. + +In preparation of introducing a set of crypto library interfaces, tidy +up the Makefile and split off the Kconfig symbols into a separate file. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/Kconfig | 13 +------------ + lib/crypto/Kconfig | 15 +++++++++++++++ + lib/crypto/Makefile | 16 ++++++++-------- + 3 files changed, 24 insertions(+), 20 deletions(-) + create mode 100644 lib/crypto/Kconfig + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -878,9 +878,6 @@ config CRYPTO_SHA1_PPC_SPE + SHA-1 secure hash standard (DFIPS 180-4) implemented + using powerpc SPE SIMD instruction set. + +-config CRYPTO_LIB_SHA256 +- tristate +- + config CRYPTO_SHA256 + tristate "SHA224 and SHA256 digest algorithm" + select CRYPTO_HASH +@@ -1019,9 +1016,6 @@ config CRYPTO_GHASH_CLMUL_NI_INTEL + + comment "Ciphers" + +-config CRYPTO_LIB_AES +- tristate +- + config CRYPTO_AES + tristate "AES cipher algorithms" + select CRYPTO_ALGAPI +@@ -1150,9 +1144,6 @@ config CRYPTO_ANUBIS + + + +-config CRYPTO_LIB_ARC4 +- tristate +- + config CRYPTO_ARC4 + tristate "ARC4 cipher algorithm" + select CRYPTO_BLKCIPHER +@@ -1339,9 +1330,6 @@ config CRYPTO_CAST6_AVX_X86_64 + This module provides the Cast6 cipher algorithm that processes + eight blocks parallel using the AVX instruction set. + +-config CRYPTO_LIB_DES +- tristate +- + config CRYPTO_DES + tristate "DES and Triple DES EDE cipher algorithms" + select CRYPTO_ALGAPI +@@ -1845,6 +1833,7 @@ config CRYPTO_STATS + config CRYPTO_HASH_INFO + bool + ++source "lib/crypto/Kconfig" + source "drivers/crypto/Kconfig" + source "crypto/asymmetric_keys/Kconfig" + source "certs/Kconfig" +--- /dev/null ++++ b/lib/crypto/Kconfig +@@ -0,0 +1,15 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++comment "Crypto library routines" ++ ++config CRYPTO_LIB_AES ++ tristate ++ ++config CRYPTO_LIB_ARC4 ++ tristate ++ ++config CRYPTO_LIB_DES ++ tristate ++ ++config CRYPTO_LIB_SHA256 ++ tristate +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -1,13 +1,13 @@ + # SPDX-License-Identifier: GPL-2.0 + +-obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o +-libaes-y := aes.o ++obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o ++libaes-y := aes.o + +-obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o +-libarc4-y := arc4.o ++obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o ++libarc4-y := arc4.o + +-obj-$(CONFIG_CRYPTO_LIB_DES) += libdes.o +-libdes-y := des.o ++obj-$(CONFIG_CRYPTO_LIB_DES) += libdes.o ++libdes-y := des.o + +-obj-$(CONFIG_CRYPTO_LIB_SHA256) += libsha256.o +-libsha256-y := sha256.o ++obj-$(CONFIG_CRYPTO_LIB_SHA256) += libsha256.o ++libsha256-y := sha256.o diff --git a/ipq806x/backport-5.4/080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch b/ipq806x/backport-5.4/080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch new file mode 100644 index 0000000..177b584 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0002-crypto-chacha-move-existing-library-code-into-lib-cr.patch @@ -0,0 +1,668 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:08 +0100 +Subject: [PATCH] crypto: chacha - move existing library code into lib/crypto + +commit 5fb8ef25803ef33e2eb60b626435828b937bed75 upstream. + +Currently, our generic ChaCha implementation consists of a permute +function in lib/chacha.c that operates on the 64-byte ChaCha state +directly [and which is always included into the core kernel since it +is used by the /dev/random driver], and the crypto API plumbing to +expose it as a skcipher. + +In order to support in-kernel users that need the ChaCha streamcipher +but have no need [or tolerance] for going through the abstractions of +the crypto API, let's expose the streamcipher bits via a library API +as well, in a way that permits the implementation to be superseded by +an architecture specific one if provided. + +So move the streamcipher code into a separate module in lib/crypto, +and expose the init() and crypt() routines to users of the library. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/chacha-neon-glue.c | 2 +- + arch/arm64/crypto/chacha-neon-glue.c | 2 +- + arch/x86/crypto/chacha_glue.c | 2 +- + crypto/Kconfig | 1 + + crypto/chacha_generic.c | 60 ++-------------------- + include/crypto/chacha.h | 77 ++++++++++++++++++++++------ + include/crypto/internal/chacha.h | 53 +++++++++++++++++++ + lib/Makefile | 3 +- + lib/crypto/Kconfig | 26 ++++++++++ + lib/crypto/Makefile | 4 ++ + lib/{ => crypto}/chacha.c | 20 ++++---- + lib/crypto/libchacha.c | 35 +++++++++++++ + 12 files changed, 199 insertions(+), 86 deletions(-) + create mode 100644 include/crypto/internal/chacha.h + rename lib/{ => crypto}/chacha.c (88%) + create mode 100644 lib/crypto/libchacha.c + +--- a/arch/arm/crypto/chacha-neon-glue.c ++++ b/arch/arm/crypto/chacha-neon-glue.c +@@ -20,7 +20,7 @@ + */ + + #include +-#include ++#include + #include + #include + #include +--- a/arch/arm64/crypto/chacha-neon-glue.c ++++ b/arch/arm64/crypto/chacha-neon-glue.c +@@ -20,7 +20,7 @@ + */ + + #include +-#include ++#include + #include + #include + #include +--- a/arch/x86/crypto/chacha_glue.c ++++ b/arch/x86/crypto/chacha_glue.c +@@ -7,7 +7,7 @@ + */ + + #include +-#include ++#include + #include + #include + #include +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1393,6 +1393,7 @@ config CRYPTO_SALSA20 + + config CRYPTO_CHACHA20 + tristate "ChaCha stream cipher algorithms" ++ select CRYPTO_LIB_CHACHA_GENERIC + select CRYPTO_BLKCIPHER + help + The ChaCha20, XChaCha20, and XChaCha12 stream cipher algorithms. +--- a/crypto/chacha_generic.c ++++ b/crypto/chacha_generic.c +@@ -8,29 +8,10 @@ + + #include + #include +-#include ++#include + #include + #include + +-static void chacha_docrypt(u32 *state, u8 *dst, const u8 *src, +- unsigned int bytes, int nrounds) +-{ +- /* aligned to potentially speed up crypto_xor() */ +- u8 stream[CHACHA_BLOCK_SIZE] __aligned(sizeof(long)); +- +- while (bytes >= CHACHA_BLOCK_SIZE) { +- chacha_block(state, stream, nrounds); +- crypto_xor_cpy(dst, src, stream, CHACHA_BLOCK_SIZE); +- bytes -= CHACHA_BLOCK_SIZE; +- dst += CHACHA_BLOCK_SIZE; +- src += CHACHA_BLOCK_SIZE; +- } +- if (bytes) { +- chacha_block(state, stream, nrounds); +- crypto_xor_cpy(dst, src, stream, bytes); +- } +-} +- + static int chacha_stream_xor(struct skcipher_request *req, + const struct chacha_ctx *ctx, const u8 *iv) + { +@@ -48,8 +29,8 @@ static int chacha_stream_xor(struct skci + if (nbytes < walk.total) + nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE); + +- chacha_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr, +- nbytes, ctx->nrounds); ++ chacha_crypt_generic(state, walk.dst.virt.addr, ++ walk.src.virt.addr, nbytes, ctx->nrounds); + err = skcipher_walk_done(&walk, walk.nbytes - nbytes); + } + +@@ -58,41 +39,10 @@ static int chacha_stream_xor(struct skci + + void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv) + { +- state[0] = 0x61707865; /* "expa" */ +- state[1] = 0x3320646e; /* "nd 3" */ +- state[2] = 0x79622d32; /* "2-by" */ +- state[3] = 0x6b206574; /* "te k" */ +- state[4] = ctx->key[0]; +- state[5] = ctx->key[1]; +- state[6] = ctx->key[2]; +- state[7] = ctx->key[3]; +- state[8] = ctx->key[4]; +- state[9] = ctx->key[5]; +- state[10] = ctx->key[6]; +- state[11] = ctx->key[7]; +- state[12] = get_unaligned_le32(iv + 0); +- state[13] = get_unaligned_le32(iv + 4); +- state[14] = get_unaligned_le32(iv + 8); +- state[15] = get_unaligned_le32(iv + 12); ++ chacha_init_generic(state, ctx->key, iv); + } + EXPORT_SYMBOL_GPL(crypto_chacha_init); + +-static int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize, int nrounds) +-{ +- struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); +- int i; +- +- if (keysize != CHACHA_KEY_SIZE) +- return -EINVAL; +- +- for (i = 0; i < ARRAY_SIZE(ctx->key); i++) +- ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32)); +- +- ctx->nrounds = nrounds; +- return 0; +-} +- + int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int keysize) + { +@@ -126,7 +76,7 @@ int crypto_xchacha_crypt(struct skcipher + + /* Compute the subkey given the original key and first 128 nonce bits */ + crypto_chacha_init(state, ctx, req->iv); +- hchacha_block(state, subctx.key, ctx->nrounds); ++ hchacha_block_generic(state, subctx.key, ctx->nrounds); + subctx.nrounds = ctx->nrounds; + + /* Build the real IV */ +--- a/include/crypto/chacha.h ++++ b/include/crypto/chacha.h +@@ -15,9 +15,8 @@ + #ifndef _CRYPTO_CHACHA_H + #define _CRYPTO_CHACHA_H + +-#include ++#include + #include +-#include + + /* 32-bit stream position, then 96-bit nonce (RFC7539 convention) */ + #define CHACHA_IV_SIZE 16 +@@ -29,26 +28,70 @@ + /* 192-bit nonce, then 64-bit stream position */ + #define XCHACHA_IV_SIZE 32 + +-struct chacha_ctx { +- u32 key[8]; +- int nrounds; +-}; +- +-void chacha_block(u32 *state, u8 *stream, int nrounds); ++void chacha_block_generic(u32 *state, u8 *stream, int nrounds); + static inline void chacha20_block(u32 *state, u8 *stream) + { +- chacha_block(state, stream, 20); ++ chacha_block_generic(state, stream, 20); + } +-void hchacha_block(const u32 *in, u32 *out, int nrounds); + +-void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv); ++void hchacha_block_arch(const u32 *state, u32 *out, int nrounds); ++void hchacha_block_generic(const u32 *state, u32 *out, int nrounds); ++ ++static inline void hchacha_block(const u32 *state, u32 *out, int nrounds) ++{ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA)) ++ hchacha_block_arch(state, out, nrounds); ++ else ++ hchacha_block_generic(state, out, nrounds); ++} + +-int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize); +-int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize); ++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv); ++static inline void chacha_init_generic(u32 *state, const u32 *key, const u8 *iv) ++{ ++ state[0] = 0x61707865; /* "expa" */ ++ state[1] = 0x3320646e; /* "nd 3" */ ++ state[2] = 0x79622d32; /* "2-by" */ ++ state[3] = 0x6b206574; /* "te k" */ ++ state[4] = key[0]; ++ state[5] = key[1]; ++ state[6] = key[2]; ++ state[7] = key[3]; ++ state[8] = key[4]; ++ state[9] = key[5]; ++ state[10] = key[6]; ++ state[11] = key[7]; ++ state[12] = get_unaligned_le32(iv + 0); ++ state[13] = get_unaligned_le32(iv + 4); ++ state[14] = get_unaligned_le32(iv + 8); ++ state[15] = get_unaligned_le32(iv + 12); ++} + +-int crypto_chacha_crypt(struct skcipher_request *req); +-int crypto_xchacha_crypt(struct skcipher_request *req); ++static inline void chacha_init(u32 *state, const u32 *key, const u8 *iv) ++{ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA)) ++ chacha_init_arch(state, key, iv); ++ else ++ chacha_init_generic(state, key, iv); ++} ++ ++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, ++ unsigned int bytes, int nrounds); ++void chacha_crypt_generic(u32 *state, u8 *dst, const u8 *src, ++ unsigned int bytes, int nrounds); ++ ++static inline void chacha_crypt(u32 *state, u8 *dst, const u8 *src, ++ unsigned int bytes, int nrounds) ++{ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA)) ++ chacha_crypt_arch(state, dst, src, bytes, nrounds); ++ else ++ chacha_crypt_generic(state, dst, src, bytes, nrounds); ++} ++ ++static inline void chacha20_crypt(u32 *state, u8 *dst, const u8 *src, ++ unsigned int bytes) ++{ ++ chacha_crypt(state, dst, src, bytes, 20); ++} + + #endif /* _CRYPTO_CHACHA_H */ +--- /dev/null ++++ b/include/crypto/internal/chacha.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef _CRYPTO_INTERNAL_CHACHA_H ++#define _CRYPTO_INTERNAL_CHACHA_H ++ ++#include ++#include ++#include ++ ++struct chacha_ctx { ++ u32 key[8]; ++ int nrounds; ++}; ++ ++void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv); ++ ++static inline int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keysize, int nrounds) ++{ ++ struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); ++ int i; ++ ++ if (keysize != CHACHA_KEY_SIZE) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(ctx->key); i++) ++ ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32)); ++ ++ ctx->nrounds = nrounds; ++ return 0; ++} ++ ++static inline int chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keysize) ++{ ++ return chacha_setkey(tfm, key, keysize, 20); ++} ++ ++static int inline chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keysize) ++{ ++ return chacha_setkey(tfm, key, keysize, 12); ++} ++ ++int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keysize); ++int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keysize); ++ ++int crypto_chacha_crypt(struct skcipher_request *req); ++int crypto_xchacha_crypt(struct skcipher_request *req); ++ ++#endif /* _CRYPTO_CHACHA_H */ +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -26,8 +26,7 @@ endif + + lib-y := ctype.o string.o vsprintf.o cmdline.o \ + rbtree.o radix-tree.o timerqueue.o xarray.o \ +- idr.o extable.o \ +- sha1.o chacha.o irq_regs.o argv_split.o \ ++ idr.o extable.o sha1.o irq_regs.o argv_split.o \ + flex_proportions.o ratelimit.o show_mem.o \ + is_single_threaded.o plist.o decompress.o kobject_uevent.o \ + earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -8,6 +8,32 @@ config CRYPTO_LIB_AES + config CRYPTO_LIB_ARC4 + tristate + ++config CRYPTO_ARCH_HAVE_LIB_CHACHA ++ tristate ++ help ++ Declares whether the architecture provides an arch-specific ++ accelerated implementation of the ChaCha library interface, ++ either builtin or as a module. ++ ++config CRYPTO_LIB_CHACHA_GENERIC ++ tristate ++ select CRYPTO_ALGAPI ++ help ++ This symbol can be depended upon by arch implementations of the ++ ChaCha library interface that require the generic code as a ++ fallback, e.g., for SIMD implementations. If no arch specific ++ implementation is enabled, this implementation serves the users ++ of CRYPTO_LIB_CHACHA. ++ ++config CRYPTO_LIB_CHACHA ++ tristate "ChaCha library interface" ++ depends on CRYPTO_ARCH_HAVE_LIB_CHACHA || !CRYPTO_ARCH_HAVE_LIB_CHACHA ++ select CRYPTO_LIB_CHACHA_GENERIC if CRYPTO_ARCH_HAVE_LIB_CHACHA=n ++ help ++ Enable the ChaCha library interface. This interface may be fulfilled ++ by either the generic implementation or an arch-specific one, if one ++ is available and enabled. ++ + config CRYPTO_LIB_DES + tristate + +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -1,5 +1,9 @@ + # SPDX-License-Identifier: GPL-2.0 + ++# chacha is used by the /dev/random driver which is always builtin ++obj-y += chacha.o ++obj-$(CONFIG_CRYPTO_LIB_CHACHA_GENERIC) += libchacha.o ++ + obj-$(CONFIG_CRYPTO_LIB_AES) += libaes.o + libaes-y := aes.o + +--- a/lib/chacha.c ++++ /dev/null +@@ -1,113 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-or-later +-/* +- * The "hash function" used as the core of the ChaCha stream cipher (RFC7539) +- * +- * Copyright (C) 2015 Martin Willi +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-static void chacha_permute(u32 *x, int nrounds) +-{ +- int i; +- +- /* whitelist the allowed round counts */ +- WARN_ON_ONCE(nrounds != 20 && nrounds != 12); +- +- for (i = 0; i < nrounds; i += 2) { +- x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 16); +- x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 16); +- x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 16); +- x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 16); +- +- x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 12); +- x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 12); +- x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 12); +- x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 12); +- +- x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 8); +- x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 8); +- x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 8); +- x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 8); +- +- x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 7); +- x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 7); +- x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 7); +- x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 7); +- +- x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 16); +- x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 16); +- x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 16); +- x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 16); +- +- x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 12); +- x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 12); +- x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 12); +- x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 12); +- +- x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 8); +- x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 8); +- x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 8); +- x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 8); +- +- x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 7); +- x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 7); +- x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 7); +- x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 7); +- } +-} +- +-/** +- * chacha_block - generate one keystream block and increment block counter +- * @state: input state matrix (16 32-bit words) +- * @stream: output keystream block (64 bytes) +- * @nrounds: number of rounds (20 or 12; 20 is recommended) +- * +- * This is the ChaCha core, a function from 64-byte strings to 64-byte strings. +- * The caller has already converted the endianness of the input. This function +- * also handles incrementing the block counter in the input matrix. +- */ +-void chacha_block(u32 *state, u8 *stream, int nrounds) +-{ +- u32 x[16]; +- int i; +- +- memcpy(x, state, 64); +- +- chacha_permute(x, nrounds); +- +- for (i = 0; i < ARRAY_SIZE(x); i++) +- put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]); +- +- state[12]++; +-} +-EXPORT_SYMBOL(chacha_block); +- +-/** +- * hchacha_block - abbreviated ChaCha core, for XChaCha +- * @in: input state matrix (16 32-bit words) +- * @out: output (8 32-bit words) +- * @nrounds: number of rounds (20 or 12; 20 is recommended) +- * +- * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step +- * towards XChaCha (see https://cr.yp.to/snuffle/xsalsa-20081128.pdf). HChaCha +- * skips the final addition of the initial state, and outputs only certain words +- * of the state. It should not be used for streaming directly. +- */ +-void hchacha_block(const u32 *in, u32 *out, int nrounds) +-{ +- u32 x[16]; +- +- memcpy(x, in, 64); +- +- chacha_permute(x, nrounds); +- +- memcpy(&out[0], &x[0], 16); +- memcpy(&out[4], &x[12], 16); +-} +-EXPORT_SYMBOL(hchacha_block); +--- /dev/null ++++ b/lib/crypto/chacha.c +@@ -0,0 +1,115 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * The "hash function" used as the core of the ChaCha stream cipher (RFC7539) ++ * ++ * Copyright (C) 2015 Martin Willi ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void chacha_permute(u32 *x, int nrounds) ++{ ++ int i; ++ ++ /* whitelist the allowed round counts */ ++ WARN_ON_ONCE(nrounds != 20 && nrounds != 12); ++ ++ for (i = 0; i < nrounds; i += 2) { ++ x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 16); ++ x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 16); ++ x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 16); ++ x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 16); ++ ++ x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 12); ++ x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 12); ++ x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 12); ++ x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 12); ++ ++ x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 8); ++ x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 8); ++ x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 8); ++ x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 8); ++ ++ x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 7); ++ x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 7); ++ x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 7); ++ x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 7); ++ ++ x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 16); ++ x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 16); ++ x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 16); ++ x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 16); ++ ++ x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 12); ++ x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 12); ++ x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 12); ++ x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 12); ++ ++ x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 8); ++ x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 8); ++ x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 8); ++ x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 8); ++ ++ x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 7); ++ x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 7); ++ x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 7); ++ x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 7); ++ } ++} ++ ++/** ++ * chacha_block - generate one keystream block and increment block counter ++ * @state: input state matrix (16 32-bit words) ++ * @stream: output keystream block (64 bytes) ++ * @nrounds: number of rounds (20 or 12; 20 is recommended) ++ * ++ * This is the ChaCha core, a function from 64-byte strings to 64-byte strings. ++ * The caller has already converted the endianness of the input. This function ++ * also handles incrementing the block counter in the input matrix. ++ */ ++void chacha_block_generic(u32 *state, u8 *stream, int nrounds) ++{ ++ u32 x[16]; ++ int i; ++ ++ memcpy(x, state, 64); ++ ++ chacha_permute(x, nrounds); ++ ++ for (i = 0; i < ARRAY_SIZE(x); i++) ++ put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]); ++ ++ state[12]++; ++} ++EXPORT_SYMBOL(chacha_block_generic); ++ ++/** ++ * hchacha_block_generic - abbreviated ChaCha core, for XChaCha ++ * @state: input state matrix (16 32-bit words) ++ * @out: output (8 32-bit words) ++ * @nrounds: number of rounds (20 or 12; 20 is recommended) ++ * ++ * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step ++ * towards XChaCha (see https://cr.yp.to/snuffle/xsalsa-20081128.pdf). HChaCha ++ * skips the final addition of the initial state, and outputs only certain words ++ * of the state. It should not be used for streaming directly. ++ */ ++void hchacha_block_generic(const u32 *state, u32 *stream, int nrounds) ++{ ++ u32 x[16]; ++ ++ memcpy(x, state, 64); ++ ++ chacha_permute(x, nrounds); ++ ++ memcpy(&stream[0], &x[0], 16); ++ memcpy(&stream[4], &x[12], 16); ++} ++EXPORT_SYMBOL(hchacha_block_generic); +--- /dev/null ++++ b/lib/crypto/libchacha.c +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * The ChaCha stream cipher (RFC7539) ++ * ++ * Copyright (C) 2015 Martin Willi ++ */ ++ ++#include ++#include ++#include ++ ++#include // for crypto_xor_cpy ++#include ++ ++void chacha_crypt_generic(u32 *state, u8 *dst, const u8 *src, ++ unsigned int bytes, int nrounds) ++{ ++ /* aligned to potentially speed up crypto_xor() */ ++ u8 stream[CHACHA_BLOCK_SIZE] __aligned(sizeof(long)); ++ ++ while (bytes >= CHACHA_BLOCK_SIZE) { ++ chacha_block_generic(state, stream, nrounds); ++ crypto_xor_cpy(dst, src, stream, CHACHA_BLOCK_SIZE); ++ bytes -= CHACHA_BLOCK_SIZE; ++ dst += CHACHA_BLOCK_SIZE; ++ src += CHACHA_BLOCK_SIZE; ++ } ++ if (bytes) { ++ chacha_block_generic(state, stream, nrounds); ++ crypto_xor_cpy(dst, src, stream, bytes); ++ } ++} ++EXPORT_SYMBOL(chacha_crypt_generic); ++ ++MODULE_LICENSE("GPL"); diff --git a/ipq806x/backport-5.4/080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch b/ipq806x/backport-5.4/080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch new file mode 100644 index 0000000..b1f59cc --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0003-crypto-x86-chacha-depend-on-generic-chacha-library-i.patch @@ -0,0 +1,192 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:09 +0100 +Subject: [PATCH] crypto: x86/chacha - depend on generic chacha library instead + of crypto driver + +commit 28e8d89b1ce8d2e7badfb5f69971dd635acb8863 upstream. + +In preparation of extending the x86 ChaCha driver to also expose the ChaCha +library interface, drop the dependency on the chacha_generic crypto driver +as a non-SIMD fallback, and depend on the generic ChaCha library directly. +This way, we only pull in the code we actually need, without registering +a set of ChaCha skciphers that we will never use. + +Since turning the FPU on and off is cheap these days, simplify the SIMD +routine by dropping the per-page yield, which makes for a cleaner switch +to the library API as well. This also allows use to invoke the skcipher +walk routines in non-atomic mode. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/chacha_glue.c | 90 ++++++++++++++--------------------- + crypto/Kconfig | 2 +- + 2 files changed, 36 insertions(+), 56 deletions(-) + +--- a/arch/x86/crypto/chacha_glue.c ++++ b/arch/x86/crypto/chacha_glue.c +@@ -123,37 +123,38 @@ static void chacha_dosimd(u32 *state, u8 + } + } + +-static int chacha_simd_stream_xor(struct skcipher_walk *walk, ++static int chacha_simd_stream_xor(struct skcipher_request *req, + const struct chacha_ctx *ctx, const u8 *iv) + { + u32 *state, state_buf[16 + 2] __aligned(8); +- int next_yield = 4096; /* bytes until next FPU yield */ +- int err = 0; ++ struct skcipher_walk walk; ++ int err; ++ ++ err = skcipher_walk_virt(&walk, req, false); + + BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16); + state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN); + +- crypto_chacha_init(state, ctx, iv); ++ chacha_init_generic(state, ctx->key, iv); + +- while (walk->nbytes > 0) { +- unsigned int nbytes = walk->nbytes; ++ while (walk.nbytes > 0) { ++ unsigned int nbytes = walk.nbytes; + +- if (nbytes < walk->total) { +- nbytes = round_down(nbytes, walk->stride); +- next_yield -= nbytes; +- } +- +- chacha_dosimd(state, walk->dst.virt.addr, walk->src.virt.addr, +- nbytes, ctx->nrounds); ++ if (nbytes < walk.total) ++ nbytes = round_down(nbytes, walk.stride); + +- if (next_yield <= 0) { +- /* temporarily allow preemption */ +- kernel_fpu_end(); ++ if (!crypto_simd_usable()) { ++ chacha_crypt_generic(state, walk.dst.virt.addr, ++ walk.src.virt.addr, nbytes, ++ ctx->nrounds); ++ } else { + kernel_fpu_begin(); +- next_yield = 4096; ++ chacha_dosimd(state, walk.dst.virt.addr, ++ walk.src.virt.addr, nbytes, ++ ctx->nrounds); ++ kernel_fpu_end(); + } +- +- err = skcipher_walk_done(walk, walk->nbytes - nbytes); ++ err = skcipher_walk_done(&walk, walk.nbytes - nbytes); + } + + return err; +@@ -163,55 +164,34 @@ static int chacha_simd(struct skcipher_r + { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct skcipher_walk walk; +- int err; +- +- if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) +- return crypto_chacha_crypt(req); + +- err = skcipher_walk_virt(&walk, req, true); +- if (err) +- return err; +- +- kernel_fpu_begin(); +- err = chacha_simd_stream_xor(&walk, ctx, req->iv); +- kernel_fpu_end(); +- return err; ++ return chacha_simd_stream_xor(req, ctx, req->iv); + } + + static int xchacha_simd(struct skcipher_request *req) + { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct skcipher_walk walk; +- struct chacha_ctx subctx; + u32 *state, state_buf[16 + 2] __aligned(8); ++ struct chacha_ctx subctx; + u8 real_iv[16]; +- int err; +- +- if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) +- return crypto_xchacha_crypt(req); +- +- err = skcipher_walk_virt(&walk, req, true); +- if (err) +- return err; + + BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16); + state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN); +- crypto_chacha_init(state, ctx, req->iv); ++ chacha_init_generic(state, ctx->key, req->iv); + +- kernel_fpu_begin(); +- +- hchacha_block_ssse3(state, subctx.key, ctx->nrounds); ++ if (req->cryptlen > CHACHA_BLOCK_SIZE && crypto_simd_usable()) { ++ kernel_fpu_begin(); ++ hchacha_block_ssse3(state, subctx.key, ctx->nrounds); ++ kernel_fpu_end(); ++ } else { ++ hchacha_block_generic(state, subctx.key, ctx->nrounds); ++ } + subctx.nrounds = ctx->nrounds; + + memcpy(&real_iv[0], req->iv + 24, 8); + memcpy(&real_iv[8], req->iv + 16, 8); +- err = chacha_simd_stream_xor(&walk, &subctx, real_iv); +- +- kernel_fpu_end(); +- +- return err; ++ return chacha_simd_stream_xor(req, &subctx, real_iv); + } + + static struct skcipher_alg algs[] = { +@@ -227,7 +207,7 @@ static struct skcipher_alg algs[] = { + .max_keysize = CHACHA_KEY_SIZE, + .ivsize = CHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, ++ .setkey = chacha20_setkey, + .encrypt = chacha_simd, + .decrypt = chacha_simd, + }, { +@@ -242,7 +222,7 @@ static struct skcipher_alg algs[] = { + .max_keysize = CHACHA_KEY_SIZE, + .ivsize = XCHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, ++ .setkey = chacha20_setkey, + .encrypt = xchacha_simd, + .decrypt = xchacha_simd, + }, { +@@ -257,7 +237,7 @@ static struct skcipher_alg algs[] = { + .max_keysize = CHACHA_KEY_SIZE, + .ivsize = XCHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha12_setkey, ++ .setkey = chacha12_setkey, + .encrypt = xchacha_simd, + .decrypt = xchacha_simd, + }, +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1417,7 +1417,7 @@ config CRYPTO_CHACHA20_X86_64 + tristate "ChaCha stream cipher algorithms (x86_64/SSSE3/AVX2/AVX-512VL)" + depends on X86 && 64BIT + select CRYPTO_BLKCIPHER +- select CRYPTO_CHACHA20 ++ select CRYPTO_LIB_CHACHA_GENERIC + help + SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20, + XChaCha20, and XChaCha12 stream ciphers. diff --git a/ipq806x/backport-5.4/080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch b/ipq806x/backport-5.4/080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch new file mode 100644 index 0000000..0e54628 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0004-crypto-x86-chacha-expose-SIMD-ChaCha-routine-as-libr.patch @@ -0,0 +1,205 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:10 +0100 +Subject: [PATCH] crypto: x86/chacha - expose SIMD ChaCha routine as library + function + +commit 84e03fa39fbe95a5567d43bff458c6d3b3a23ad1 upstream. + +Wire the existing x86 SIMD ChaCha code into the new ChaCha library +interface, so that users of the library interface will get the +accelerated version when available. + +Given that calls into the library API will always go through the +routines in this module if it is enabled, switch to static keys +to select the optimal implementation available (which may be none +at all, in which case we defer to the generic implementation for +all invocations). + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/chacha_glue.c | 91 +++++++++++++++++++++++++---------- + crypto/Kconfig | 1 + + include/crypto/chacha.h | 6 +++ + 3 files changed, 73 insertions(+), 25 deletions(-) + +--- a/arch/x86/crypto/chacha_glue.c ++++ b/arch/x86/crypto/chacha_glue.c +@@ -21,24 +21,24 @@ asmlinkage void chacha_block_xor_ssse3(u + asmlinkage void chacha_4block_xor_ssse3(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); + asmlinkage void hchacha_block_ssse3(const u32 *state, u32 *out, int nrounds); +-#ifdef CONFIG_AS_AVX2 ++ + asmlinkage void chacha_2block_xor_avx2(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); + asmlinkage void chacha_4block_xor_avx2(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); + asmlinkage void chacha_8block_xor_avx2(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); +-static bool chacha_use_avx2; +-#ifdef CONFIG_AS_AVX512 ++ + asmlinkage void chacha_2block_xor_avx512vl(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); + asmlinkage void chacha_4block_xor_avx512vl(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); + asmlinkage void chacha_8block_xor_avx512vl(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); +-static bool chacha_use_avx512vl; +-#endif +-#endif ++ ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_simd); ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx2); ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(chacha_use_avx512vl); + + static unsigned int chacha_advance(unsigned int len, unsigned int maxblocks) + { +@@ -49,9 +49,8 @@ static unsigned int chacha_advance(unsig + static void chacha_dosimd(u32 *state, u8 *dst, const u8 *src, + unsigned int bytes, int nrounds) + { +-#ifdef CONFIG_AS_AVX2 +-#ifdef CONFIG_AS_AVX512 +- if (chacha_use_avx512vl) { ++ if (IS_ENABLED(CONFIG_AS_AVX512) && ++ static_branch_likely(&chacha_use_avx512vl)) { + while (bytes >= CHACHA_BLOCK_SIZE * 8) { + chacha_8block_xor_avx512vl(state, dst, src, bytes, + nrounds); +@@ -79,8 +78,9 @@ static void chacha_dosimd(u32 *state, u8 + return; + } + } +-#endif +- if (chacha_use_avx2) { ++ ++ if (IS_ENABLED(CONFIG_AS_AVX2) && ++ static_branch_likely(&chacha_use_avx2)) { + while (bytes >= CHACHA_BLOCK_SIZE * 8) { + chacha_8block_xor_avx2(state, dst, src, bytes, nrounds); + bytes -= CHACHA_BLOCK_SIZE * 8; +@@ -104,7 +104,7 @@ static void chacha_dosimd(u32 *state, u8 + return; + } + } +-#endif ++ + while (bytes >= CHACHA_BLOCK_SIZE * 4) { + chacha_4block_xor_ssse3(state, dst, src, bytes, nrounds); + bytes -= CHACHA_BLOCK_SIZE * 4; +@@ -123,6 +123,43 @@ static void chacha_dosimd(u32 *state, u8 + } + } + ++void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds) ++{ ++ state = PTR_ALIGN(state, CHACHA_STATE_ALIGN); ++ ++ if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable()) { ++ hchacha_block_generic(state, stream, nrounds); ++ } else { ++ kernel_fpu_begin(); ++ hchacha_block_ssse3(state, stream, nrounds); ++ kernel_fpu_end(); ++ } ++} ++EXPORT_SYMBOL(hchacha_block_arch); ++ ++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv) ++{ ++ state = PTR_ALIGN(state, CHACHA_STATE_ALIGN); ++ ++ chacha_init_generic(state, key, iv); ++} ++EXPORT_SYMBOL(chacha_init_arch); ++ ++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes, ++ int nrounds) ++{ ++ state = PTR_ALIGN(state, CHACHA_STATE_ALIGN); ++ ++ if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable() || ++ bytes <= CHACHA_BLOCK_SIZE) ++ return chacha_crypt_generic(state, dst, src, bytes, nrounds); ++ ++ kernel_fpu_begin(); ++ chacha_dosimd(state, dst, src, bytes, nrounds); ++ kernel_fpu_end(); ++} ++EXPORT_SYMBOL(chacha_crypt_arch); ++ + static int chacha_simd_stream_xor(struct skcipher_request *req, + const struct chacha_ctx *ctx, const u8 *iv) + { +@@ -143,7 +180,8 @@ static int chacha_simd_stream_xor(struct + if (nbytes < walk.total) + nbytes = round_down(nbytes, walk.stride); + +- if (!crypto_simd_usable()) { ++ if (!static_branch_likely(&chacha_use_simd) || ++ !crypto_simd_usable()) { + chacha_crypt_generic(state, walk.dst.virt.addr, + walk.src.virt.addr, nbytes, + ctx->nrounds); +@@ -246,18 +284,21 @@ static struct skcipher_alg algs[] = { + static int __init chacha_simd_mod_init(void) + { + if (!boot_cpu_has(X86_FEATURE_SSSE3)) +- return -ENODEV; ++ return 0; + +-#ifdef CONFIG_AS_AVX2 +- chacha_use_avx2 = boot_cpu_has(X86_FEATURE_AVX) && +- boot_cpu_has(X86_FEATURE_AVX2) && +- cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL); +-#ifdef CONFIG_AS_AVX512 +- chacha_use_avx512vl = chacha_use_avx2 && +- boot_cpu_has(X86_FEATURE_AVX512VL) && +- boot_cpu_has(X86_FEATURE_AVX512BW); /* kmovq */ +-#endif +-#endif ++ static_branch_enable(&chacha_use_simd); ++ ++ if (IS_ENABLED(CONFIG_AS_AVX2) && ++ boot_cpu_has(X86_FEATURE_AVX) && ++ boot_cpu_has(X86_FEATURE_AVX2) && ++ cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) { ++ static_branch_enable(&chacha_use_avx2); ++ ++ if (IS_ENABLED(CONFIG_AS_AVX512) && ++ boot_cpu_has(X86_FEATURE_AVX512VL) && ++ boot_cpu_has(X86_FEATURE_AVX512BW)) /* kmovq */ ++ static_branch_enable(&chacha_use_avx512vl); ++ } + return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); + } + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1418,6 +1418,7 @@ config CRYPTO_CHACHA20_X86_64 + depends on X86 && 64BIT + select CRYPTO_BLKCIPHER + select CRYPTO_LIB_CHACHA_GENERIC ++ select CRYPTO_ARCH_HAVE_LIB_CHACHA + help + SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20, + XChaCha20, and XChaCha12 stream ciphers. +--- a/include/crypto/chacha.h ++++ b/include/crypto/chacha.h +@@ -25,6 +25,12 @@ + #define CHACHA_BLOCK_SIZE 64 + #define CHACHAPOLY_IV_SIZE 12 + ++#ifdef CONFIG_X86_64 ++#define CHACHA_STATE_WORDS ((CHACHA_BLOCK_SIZE + 12) / sizeof(u32)) ++#else ++#define CHACHA_STATE_WORDS (CHACHA_BLOCK_SIZE / sizeof(u32)) ++#endif ++ + /* 192-bit nonce, then 64-bit stream position */ + #define XCHACHA_IV_SIZE 32 + diff --git a/ipq806x/backport-5.4/080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch b/ipq806x/backport-5.4/080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch new file mode 100644 index 0000000..10e49c1 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0005-crypto-arm64-chacha-depend-on-generic-chacha-library.patch @@ -0,0 +1,129 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:11 +0100 +Subject: [PATCH] crypto: arm64/chacha - depend on generic chacha library + instead of crypto driver + +commit c77da4867cbb7841177275dbb250f5c09679fae4 upstream. + +Depend on the generic ChaCha library routines instead of pulling in the +generic ChaCha skcipher driver, which is more than we need, and makes +managing the dependencies between the generic library, generic driver, +accelerated library and driver more complicated. + +While at it, drop the logic to prefer the scalar code on short inputs. +Turning the NEON on and off is cheap these days, and one major use case +for ChaCha20 is ChaCha20-Poly1305, which is guaranteed to hit the scalar +path upon every invocation (when doing the Poly1305 nonce generation) + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm64/crypto/Kconfig | 2 +- + arch/arm64/crypto/chacha-neon-glue.c | 40 +++++++++++++++------------- + 2 files changed, 23 insertions(+), 19 deletions(-) + +--- a/arch/arm64/crypto/Kconfig ++++ b/arch/arm64/crypto/Kconfig +@@ -103,7 +103,7 @@ config CRYPTO_CHACHA20_NEON + tristate "ChaCha20, XChaCha20, and XChaCha12 stream ciphers using NEON instructions" + depends on KERNEL_MODE_NEON + select CRYPTO_BLKCIPHER +- select CRYPTO_CHACHA20 ++ select CRYPTO_LIB_CHACHA_GENERIC + + config CRYPTO_NHPOLY1305_NEON + tristate "NHPoly1305 hash function using NEON instructions (for Adiantum)" +--- a/arch/arm64/crypto/chacha-neon-glue.c ++++ b/arch/arm64/crypto/chacha-neon-glue.c +@@ -68,7 +68,7 @@ static int chacha_neon_stream_xor(struct + + err = skcipher_walk_virt(&walk, req, false); + +- crypto_chacha_init(state, ctx, iv); ++ chacha_init_generic(state, ctx->key, iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; +@@ -76,10 +76,16 @@ static int chacha_neon_stream_xor(struct + if (nbytes < walk.total) + nbytes = rounddown(nbytes, walk.stride); + +- kernel_neon_begin(); +- chacha_doneon(state, walk.dst.virt.addr, walk.src.virt.addr, +- nbytes, ctx->nrounds); +- kernel_neon_end(); ++ if (!crypto_simd_usable()) { ++ chacha_crypt_generic(state, walk.dst.virt.addr, ++ walk.src.virt.addr, nbytes, ++ ctx->nrounds); ++ } else { ++ kernel_neon_begin(); ++ chacha_doneon(state, walk.dst.virt.addr, ++ walk.src.virt.addr, nbytes, ctx->nrounds); ++ kernel_neon_end(); ++ } + err = skcipher_walk_done(&walk, walk.nbytes - nbytes); + } + +@@ -91,9 +97,6 @@ static int chacha_neon(struct skcipher_r + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); + +- if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) +- return crypto_chacha_crypt(req); +- + return chacha_neon_stream_xor(req, ctx, req->iv); + } + +@@ -105,14 +108,15 @@ static int xchacha_neon(struct skcipher_ + u32 state[16]; + u8 real_iv[16]; + +- if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) +- return crypto_xchacha_crypt(req); +- +- crypto_chacha_init(state, ctx, req->iv); ++ chacha_init_generic(state, ctx->key, req->iv); + +- kernel_neon_begin(); +- hchacha_block_neon(state, subctx.key, ctx->nrounds); +- kernel_neon_end(); ++ if (crypto_simd_usable()) { ++ kernel_neon_begin(); ++ hchacha_block_neon(state, subctx.key, ctx->nrounds); ++ kernel_neon_end(); ++ } else { ++ hchacha_block_generic(state, subctx.key, ctx->nrounds); ++ } + subctx.nrounds = ctx->nrounds; + + memcpy(&real_iv[0], req->iv + 24, 8); +@@ -134,7 +138,7 @@ static struct skcipher_alg algs[] = { + .ivsize = CHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, + .walksize = 5 * CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, ++ .setkey = chacha20_setkey, + .encrypt = chacha_neon, + .decrypt = chacha_neon, + }, { +@@ -150,7 +154,7 @@ static struct skcipher_alg algs[] = { + .ivsize = XCHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, + .walksize = 5 * CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, ++ .setkey = chacha20_setkey, + .encrypt = xchacha_neon, + .decrypt = xchacha_neon, + }, { +@@ -166,7 +170,7 @@ static struct skcipher_alg algs[] = { + .ivsize = XCHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, + .walksize = 5 * CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha12_setkey, ++ .setkey = chacha12_setkey, + .encrypt = xchacha_neon, + .decrypt = xchacha_neon, + } diff --git a/ipq806x/backport-5.4/080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch b/ipq806x/backport-5.4/080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch new file mode 100644 index 0000000..71665e8 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0006-crypto-arm64-chacha-expose-arm64-ChaCha-routine-as-l.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:12 +0100 +Subject: [PATCH] crypto: arm64/chacha - expose arm64 ChaCha routine as library + function + +commit b3aad5bad26a01a4bd8c49a5c5f52aec665f3b7c upstream. + +Expose the accelerated NEON ChaCha routine directly as a symbol +export so that users of the ChaCha library API can use it directly. + +Given that calls into the library API will always go through the +routines in this module if it is enabled, switch to static keys +to select the optimal implementation available (which may be none +at all, in which case we defer to the generic implementation for +all invocations). + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm64/crypto/Kconfig | 1 + + arch/arm64/crypto/chacha-neon-glue.c | 53 ++++++++++++++++++++++------ + 2 files changed, 43 insertions(+), 11 deletions(-) + +--- a/arch/arm64/crypto/Kconfig ++++ b/arch/arm64/crypto/Kconfig +@@ -104,6 +104,7 @@ config CRYPTO_CHACHA20_NEON + depends on KERNEL_MODE_NEON + select CRYPTO_BLKCIPHER + select CRYPTO_LIB_CHACHA_GENERIC ++ select CRYPTO_ARCH_HAVE_LIB_CHACHA + + config CRYPTO_NHPOLY1305_NEON + tristate "NHPoly1305 hash function using NEON instructions (for Adiantum)" +--- a/arch/arm64/crypto/chacha-neon-glue.c ++++ b/arch/arm64/crypto/chacha-neon-glue.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -36,6 +37,8 @@ asmlinkage void chacha_4block_xor_neon(u + int nrounds, int bytes); + asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds); + ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); ++ + static void chacha_doneon(u32 *state, u8 *dst, const u8 *src, + int bytes, int nrounds) + { +@@ -59,6 +62,37 @@ static void chacha_doneon(u32 *state, u8 + } + } + ++void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds) ++{ ++ if (!static_branch_likely(&have_neon) || !crypto_simd_usable()) { ++ hchacha_block_generic(state, stream, nrounds); ++ } else { ++ kernel_neon_begin(); ++ hchacha_block_neon(state, stream, nrounds); ++ kernel_neon_end(); ++ } ++} ++EXPORT_SYMBOL(hchacha_block_arch); ++ ++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv) ++{ ++ chacha_init_generic(state, key, iv); ++} ++EXPORT_SYMBOL(chacha_init_arch); ++ ++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes, ++ int nrounds) ++{ ++ if (!static_branch_likely(&have_neon) || bytes <= CHACHA_BLOCK_SIZE || ++ !crypto_simd_usable()) ++ return chacha_crypt_generic(state, dst, src, bytes, nrounds); ++ ++ kernel_neon_begin(); ++ chacha_doneon(state, dst, src, bytes, nrounds); ++ kernel_neon_end(); ++} ++EXPORT_SYMBOL(chacha_crypt_arch); ++ + static int chacha_neon_stream_xor(struct skcipher_request *req, + const struct chacha_ctx *ctx, const u8 *iv) + { +@@ -76,7 +110,8 @@ static int chacha_neon_stream_xor(struct + if (nbytes < walk.total) + nbytes = rounddown(nbytes, walk.stride); + +- if (!crypto_simd_usable()) { ++ if (!static_branch_likely(&have_neon) || ++ !crypto_simd_usable()) { + chacha_crypt_generic(state, walk.dst.virt.addr, + walk.src.virt.addr, nbytes, + ctx->nrounds); +@@ -109,14 +144,7 @@ static int xchacha_neon(struct skcipher_ + u8 real_iv[16]; + + chacha_init_generic(state, ctx->key, req->iv); +- +- if (crypto_simd_usable()) { +- kernel_neon_begin(); +- hchacha_block_neon(state, subctx.key, ctx->nrounds); +- kernel_neon_end(); +- } else { +- hchacha_block_generic(state, subctx.key, ctx->nrounds); +- } ++ hchacha_block_arch(state, subctx.key, ctx->nrounds); + subctx.nrounds = ctx->nrounds; + + memcpy(&real_iv[0], req->iv + 24, 8); +@@ -179,14 +207,17 @@ static struct skcipher_alg algs[] = { + static int __init chacha_simd_mod_init(void) + { + if (!cpu_have_named_feature(ASIMD)) +- return -ENODEV; ++ return 0; ++ ++ static_branch_enable(&have_neon); + + return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); + } + + static void __exit chacha_simd_mod_fini(void) + { +- crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); ++ if (cpu_have_named_feature(ASIMD)) ++ crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); + } + + module_init(chacha_simd_mod_init); diff --git a/ipq806x/backport-5.4/080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch b/ipq806x/backport-5.4/080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch new file mode 100644 index 0000000..978f2f5 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0007-crypto-arm-chacha-import-Eric-Biggers-s-scalar-accel.patch @@ -0,0 +1,480 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:13 +0100 +Subject: [PATCH] crypto: arm/chacha - import Eric Biggers's scalar accelerated + ChaCha code + +commit 29621d099f9c642b22a69dc8e7e20c108473a392 upstream. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/chacha-scalar-core.S | 461 +++++++++++++++++++++++++++ + 1 file changed, 461 insertions(+) + create mode 100644 arch/arm/crypto/chacha-scalar-core.S + +--- /dev/null ++++ b/arch/arm/crypto/chacha-scalar-core.S +@@ -0,0 +1,461 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018 Google, Inc. ++ */ ++ ++#include ++#include ++ ++/* ++ * Design notes: ++ * ++ * 16 registers would be needed to hold the state matrix, but only 14 are ++ * available because 'sp' and 'pc' cannot be used. So we spill the elements ++ * (x8, x9) to the stack and swap them out with (x10, x11). This adds one ++ * 'ldrd' and one 'strd' instruction per round. ++ * ++ * All rotates are performed using the implicit rotate operand accepted by the ++ * 'add' and 'eor' instructions. This is faster than using explicit rotate ++ * instructions. To make this work, we allow the values in the second and last ++ * rows of the ChaCha state matrix (rows 'b' and 'd') to temporarily have the ++ * wrong rotation amount. The rotation amount is then fixed up just in time ++ * when the values are used. 'brot' is the number of bits the values in row 'b' ++ * need to be rotated right to arrive at the correct values, and 'drot' ++ * similarly for row 'd'. (brot, drot) start out as (0, 0) but we make it such ++ * that they end up as (25, 24) after every round. ++ */ ++ ++ // ChaCha state registers ++ X0 .req r0 ++ X1 .req r1 ++ X2 .req r2 ++ X3 .req r3 ++ X4 .req r4 ++ X5 .req r5 ++ X6 .req r6 ++ X7 .req r7 ++ X8_X10 .req r8 // shared by x8 and x10 ++ X9_X11 .req r9 // shared by x9 and x11 ++ X12 .req r10 ++ X13 .req r11 ++ X14 .req r12 ++ X15 .req r14 ++ ++.Lexpand_32byte_k: ++ // "expand 32-byte k" ++ .word 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 ++ ++#ifdef __thumb2__ ++# define adrl adr ++#endif ++ ++.macro __rev out, in, t0, t1, t2 ++.if __LINUX_ARM_ARCH__ >= 6 ++ rev \out, \in ++.else ++ lsl \t0, \in, #24 ++ and \t1, \in, #0xff00 ++ and \t2, \in, #0xff0000 ++ orr \out, \t0, \in, lsr #24 ++ orr \out, \out, \t1, lsl #8 ++ orr \out, \out, \t2, lsr #8 ++.endif ++.endm ++ ++.macro _le32_bswap x, t0, t1, t2 ++#ifdef __ARMEB__ ++ __rev \x, \x, \t0, \t1, \t2 ++#endif ++.endm ++ ++.macro _le32_bswap_4x a, b, c, d, t0, t1, t2 ++ _le32_bswap \a, \t0, \t1, \t2 ++ _le32_bswap \b, \t0, \t1, \t2 ++ _le32_bswap \c, \t0, \t1, \t2 ++ _le32_bswap \d, \t0, \t1, \t2 ++.endm ++ ++.macro __ldrd a, b, src, offset ++#if __LINUX_ARM_ARCH__ >= 6 ++ ldrd \a, \b, [\src, #\offset] ++#else ++ ldr \a, [\src, #\offset] ++ ldr \b, [\src, #\offset + 4] ++#endif ++.endm ++ ++.macro __strd a, b, dst, offset ++#if __LINUX_ARM_ARCH__ >= 6 ++ strd \a, \b, [\dst, #\offset] ++#else ++ str \a, [\dst, #\offset] ++ str \b, [\dst, #\offset + 4] ++#endif ++.endm ++ ++.macro _halfround a1, b1, c1, d1, a2, b2, c2, d2 ++ ++ // a += b; d ^= a; d = rol(d, 16); ++ add \a1, \a1, \b1, ror #brot ++ add \a2, \a2, \b2, ror #brot ++ eor \d1, \a1, \d1, ror #drot ++ eor \d2, \a2, \d2, ror #drot ++ // drot == 32 - 16 == 16 ++ ++ // c += d; b ^= c; b = rol(b, 12); ++ add \c1, \c1, \d1, ror #16 ++ add \c2, \c2, \d2, ror #16 ++ eor \b1, \c1, \b1, ror #brot ++ eor \b2, \c2, \b2, ror #brot ++ // brot == 32 - 12 == 20 ++ ++ // a += b; d ^= a; d = rol(d, 8); ++ add \a1, \a1, \b1, ror #20 ++ add \a2, \a2, \b2, ror #20 ++ eor \d1, \a1, \d1, ror #16 ++ eor \d2, \a2, \d2, ror #16 ++ // drot == 32 - 8 == 24 ++ ++ // c += d; b ^= c; b = rol(b, 7); ++ add \c1, \c1, \d1, ror #24 ++ add \c2, \c2, \d2, ror #24 ++ eor \b1, \c1, \b1, ror #20 ++ eor \b2, \c2, \b2, ror #20 ++ // brot == 32 - 7 == 25 ++.endm ++ ++.macro _doubleround ++ ++ // column round ++ ++ // quarterrounds: (x0, x4, x8, x12) and (x1, x5, x9, x13) ++ _halfround X0, X4, X8_X10, X12, X1, X5, X9_X11, X13 ++ ++ // save (x8, x9); restore (x10, x11) ++ __strd X8_X10, X9_X11, sp, 0 ++ __ldrd X8_X10, X9_X11, sp, 8 ++ ++ // quarterrounds: (x2, x6, x10, x14) and (x3, x7, x11, x15) ++ _halfround X2, X6, X8_X10, X14, X3, X7, X9_X11, X15 ++ ++ .set brot, 25 ++ .set drot, 24 ++ ++ // diagonal round ++ ++ // quarterrounds: (x0, x5, x10, x15) and (x1, x6, x11, x12) ++ _halfround X0, X5, X8_X10, X15, X1, X6, X9_X11, X12 ++ ++ // save (x10, x11); restore (x8, x9) ++ __strd X8_X10, X9_X11, sp, 8 ++ __ldrd X8_X10, X9_X11, sp, 0 ++ ++ // quarterrounds: (x2, x7, x8, x13) and (x3, x4, x9, x14) ++ _halfround X2, X7, X8_X10, X13, X3, X4, X9_X11, X14 ++.endm ++ ++.macro _chacha_permute nrounds ++ .set brot, 0 ++ .set drot, 0 ++ .rept \nrounds / 2 ++ _doubleround ++ .endr ++.endm ++ ++.macro _chacha nrounds ++ ++.Lnext_block\@: ++ // Stack: unused0-unused1 x10-x11 x0-x15 OUT IN LEN ++ // Registers contain x0-x9,x12-x15. ++ ++ // Do the core ChaCha permutation to update x0-x15. ++ _chacha_permute \nrounds ++ ++ add sp, #8 ++ // Stack: x10-x11 orig_x0-orig_x15 OUT IN LEN ++ // Registers contain x0-x9,x12-x15. ++ // x4-x7 are rotated by 'brot'; x12-x15 are rotated by 'drot'. ++ ++ // Free up some registers (r8-r12,r14) by pushing (x8-x9,x12-x15). ++ push {X8_X10, X9_X11, X12, X13, X14, X15} ++ ++ // Load (OUT, IN, LEN). ++ ldr r14, [sp, #96] ++ ldr r12, [sp, #100] ++ ldr r11, [sp, #104] ++ ++ orr r10, r14, r12 ++ ++ // Use slow path if fewer than 64 bytes remain. ++ cmp r11, #64 ++ blt .Lxor_slowpath\@ ++ ++ // Use slow path if IN and/or OUT isn't 4-byte aligned. Needed even on ++ // ARMv6+, since ldmia and stmia (used below) still require alignment. ++ tst r10, #3 ++ bne .Lxor_slowpath\@ ++ ++ // Fast path: XOR 64 bytes of aligned data. ++ ++ // Stack: x8-x9 x12-x15 x10-x11 orig_x0-orig_x15 OUT IN LEN ++ // Registers: r0-r7 are x0-x7; r8-r11 are free; r12 is IN; r14 is OUT. ++ // x4-x7 are rotated by 'brot'; x12-x15 are rotated by 'drot'. ++ ++ // x0-x3 ++ __ldrd r8, r9, sp, 32 ++ __ldrd r10, r11, sp, 40 ++ add X0, X0, r8 ++ add X1, X1, r9 ++ add X2, X2, r10 ++ add X3, X3, r11 ++ _le32_bswap_4x X0, X1, X2, X3, r8, r9, r10 ++ ldmia r12!, {r8-r11} ++ eor X0, X0, r8 ++ eor X1, X1, r9 ++ eor X2, X2, r10 ++ eor X3, X3, r11 ++ stmia r14!, {X0-X3} ++ ++ // x4-x7 ++ __ldrd r8, r9, sp, 48 ++ __ldrd r10, r11, sp, 56 ++ add X4, r8, X4, ror #brot ++ add X5, r9, X5, ror #brot ++ ldmia r12!, {X0-X3} ++ add X6, r10, X6, ror #brot ++ add X7, r11, X7, ror #brot ++ _le32_bswap_4x X4, X5, X6, X7, r8, r9, r10 ++ eor X4, X4, X0 ++ eor X5, X5, X1 ++ eor X6, X6, X2 ++ eor X7, X7, X3 ++ stmia r14!, {X4-X7} ++ ++ // x8-x15 ++ pop {r0-r7} // (x8-x9,x12-x15,x10-x11) ++ __ldrd r8, r9, sp, 32 ++ __ldrd r10, r11, sp, 40 ++ add r0, r0, r8 // x8 ++ add r1, r1, r9 // x9 ++ add r6, r6, r10 // x10 ++ add r7, r7, r11 // x11 ++ _le32_bswap_4x r0, r1, r6, r7, r8, r9, r10 ++ ldmia r12!, {r8-r11} ++ eor r0, r0, r8 // x8 ++ eor r1, r1, r9 // x9 ++ eor r6, r6, r10 // x10 ++ eor r7, r7, r11 // x11 ++ stmia r14!, {r0,r1,r6,r7} ++ ldmia r12!, {r0,r1,r6,r7} ++ __ldrd r8, r9, sp, 48 ++ __ldrd r10, r11, sp, 56 ++ add r2, r8, r2, ror #drot // x12 ++ add r3, r9, r3, ror #drot // x13 ++ add r4, r10, r4, ror #drot // x14 ++ add r5, r11, r5, ror #drot // x15 ++ _le32_bswap_4x r2, r3, r4, r5, r9, r10, r11 ++ ldr r9, [sp, #72] // load LEN ++ eor r2, r2, r0 // x12 ++ eor r3, r3, r1 // x13 ++ eor r4, r4, r6 // x14 ++ eor r5, r5, r7 // x15 ++ subs r9, #64 // decrement and check LEN ++ stmia r14!, {r2-r5} ++ ++ beq .Ldone\@ ++ ++.Lprepare_for_next_block\@: ++ ++ // Stack: x0-x15 OUT IN LEN ++ ++ // Increment block counter (x12) ++ add r8, #1 ++ ++ // Store updated (OUT, IN, LEN) ++ str r14, [sp, #64] ++ str r12, [sp, #68] ++ str r9, [sp, #72] ++ ++ mov r14, sp ++ ++ // Store updated block counter (x12) ++ str r8, [sp, #48] ++ ++ sub sp, #16 ++ ++ // Reload state and do next block ++ ldmia r14!, {r0-r11} // load x0-x11 ++ __strd r10, r11, sp, 8 // store x10-x11 before state ++ ldmia r14, {r10-r12,r14} // load x12-x15 ++ b .Lnext_block\@ ++ ++.Lxor_slowpath\@: ++ // Slow path: < 64 bytes remaining, or unaligned input or output buffer. ++ // We handle it by storing the 64 bytes of keystream to the stack, then ++ // XOR-ing the needed portion with the data. ++ ++ // Allocate keystream buffer ++ sub sp, #64 ++ mov r14, sp ++ ++ // Stack: ks0-ks15 x8-x9 x12-x15 x10-x11 orig_x0-orig_x15 OUT IN LEN ++ // Registers: r0-r7 are x0-x7; r8-r11 are free; r12 is IN; r14 is &ks0. ++ // x4-x7 are rotated by 'brot'; x12-x15 are rotated by 'drot'. ++ ++ // Save keystream for x0-x3 ++ __ldrd r8, r9, sp, 96 ++ __ldrd r10, r11, sp, 104 ++ add X0, X0, r8 ++ add X1, X1, r9 ++ add X2, X2, r10 ++ add X3, X3, r11 ++ _le32_bswap_4x X0, X1, X2, X3, r8, r9, r10 ++ stmia r14!, {X0-X3} ++ ++ // Save keystream for x4-x7 ++ __ldrd r8, r9, sp, 112 ++ __ldrd r10, r11, sp, 120 ++ add X4, r8, X4, ror #brot ++ add X5, r9, X5, ror #brot ++ add X6, r10, X6, ror #brot ++ add X7, r11, X7, ror #brot ++ _le32_bswap_4x X4, X5, X6, X7, r8, r9, r10 ++ add r8, sp, #64 ++ stmia r14!, {X4-X7} ++ ++ // Save keystream for x8-x15 ++ ldm r8, {r0-r7} // (x8-x9,x12-x15,x10-x11) ++ __ldrd r8, r9, sp, 128 ++ __ldrd r10, r11, sp, 136 ++ add r0, r0, r8 // x8 ++ add r1, r1, r9 // x9 ++ add r6, r6, r10 // x10 ++ add r7, r7, r11 // x11 ++ _le32_bswap_4x r0, r1, r6, r7, r8, r9, r10 ++ stmia r14!, {r0,r1,r6,r7} ++ __ldrd r8, r9, sp, 144 ++ __ldrd r10, r11, sp, 152 ++ add r2, r8, r2, ror #drot // x12 ++ add r3, r9, r3, ror #drot // x13 ++ add r4, r10, r4, ror #drot // x14 ++ add r5, r11, r5, ror #drot // x15 ++ _le32_bswap_4x r2, r3, r4, r5, r9, r10, r11 ++ stmia r14, {r2-r5} ++ ++ // Stack: ks0-ks15 unused0-unused7 x0-x15 OUT IN LEN ++ // Registers: r8 is block counter, r12 is IN. ++ ++ ldr r9, [sp, #168] // LEN ++ ldr r14, [sp, #160] // OUT ++ cmp r9, #64 ++ mov r0, sp ++ movle r1, r9 ++ movgt r1, #64 ++ // r1 is number of bytes to XOR, in range [1, 64] ++ ++.if __LINUX_ARM_ARCH__ < 6 ++ orr r2, r12, r14 ++ tst r2, #3 // IN or OUT misaligned? ++ bne .Lxor_next_byte\@ ++.endif ++ ++ // XOR a word at a time ++.rept 16 ++ subs r1, #4 ++ blt .Lxor_words_done\@ ++ ldr r2, [r12], #4 ++ ldr r3, [r0], #4 ++ eor r2, r2, r3 ++ str r2, [r14], #4 ++.endr ++ b .Lxor_slowpath_done\@ ++.Lxor_words_done\@: ++ ands r1, r1, #3 ++ beq .Lxor_slowpath_done\@ ++ ++ // XOR a byte at a time ++.Lxor_next_byte\@: ++ ldrb r2, [r12], #1 ++ ldrb r3, [r0], #1 ++ eor r2, r2, r3 ++ strb r2, [r14], #1 ++ subs r1, #1 ++ bne .Lxor_next_byte\@ ++ ++.Lxor_slowpath_done\@: ++ subs r9, #64 ++ add sp, #96 ++ bgt .Lprepare_for_next_block\@ ++ ++.Ldone\@: ++.endm // _chacha ++ ++/* ++ * void chacha20_arm(u8 *out, const u8 *in, size_t len, const u32 key[8], ++ * const u32 iv[4]); ++ */ ++ENTRY(chacha20_arm) ++ cmp r2, #0 // len == 0? ++ reteq lr ++ ++ push {r0-r2,r4-r11,lr} ++ ++ // Push state x0-x15 onto stack. ++ // Also store an extra copy of x10-x11 just before the state. ++ ++ ldr r4, [sp, #48] // iv ++ mov r0, sp ++ sub sp, #80 ++ ++ // iv: x12-x15 ++ ldm r4, {X12,X13,X14,X15} ++ stmdb r0!, {X12,X13,X14,X15} ++ ++ // key: x4-x11 ++ __ldrd X8_X10, X9_X11, r3, 24 ++ __strd X8_X10, X9_X11, sp, 8 ++ stmdb r0!, {X8_X10, X9_X11} ++ ldm r3, {X4-X9_X11} ++ stmdb r0!, {X4-X9_X11} ++ ++ // constants: x0-x3 ++ adrl X3, .Lexpand_32byte_k ++ ldm X3, {X0-X3} ++ __strd X0, X1, sp, 16 ++ __strd X2, X3, sp, 24 ++ ++ _chacha 20 ++ ++ add sp, #76 ++ pop {r4-r11, pc} ++ENDPROC(chacha20_arm) ++ ++/* ++ * void hchacha20_arm(const u32 state[16], u32 out[8]); ++ */ ++ENTRY(hchacha20_arm) ++ push {r1,r4-r11,lr} ++ ++ mov r14, r0 ++ ldmia r14!, {r0-r11} // load x0-x11 ++ push {r10-r11} // store x10-x11 to stack ++ ldm r14, {r10-r12,r14} // load x12-x15 ++ sub sp, #8 ++ ++ _chacha_permute 20 ++ ++ // Skip over (unused0-unused1, x10-x11) ++ add sp, #16 ++ ++ // Fix up rotations of x12-x15 ++ ror X12, X12, #drot ++ ror X13, X13, #drot ++ pop {r4} // load 'out' ++ ror X14, X14, #drot ++ ror X15, X15, #drot ++ ++ // Store (x0-x3,x12-x15) to 'out' ++ stm r4, {X0,X1,X2,X3,X12,X13,X14,X15} ++ ++ pop {r4-r11,pc} ++ENDPROC(hchacha20_arm) diff --git a/ipq806x/backport-5.4/080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch b/ipq806x/backport-5.4/080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch new file mode 100644 index 0000000..88c9738 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0008-crypto-arm-chacha-remove-dependency-on-generic-ChaCh.patch @@ -0,0 +1,691 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:14 +0100 +Subject: [PATCH] crypto: arm/chacha - remove dependency on generic ChaCha + driver + +commit b36d8c09e710c71f6a9690b6586fea2d1c9e1e27 upstream. + +Instead of falling back to the generic ChaCha skcipher driver for +non-SIMD cases, use a fast scalar implementation for ARM authored +by Eric Biggers. This removes the module dependency on chacha-generic +altogether, which also simplifies things when we expose the ChaCha +library interface from this module. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/Kconfig | 4 +- + arch/arm/crypto/Makefile | 3 +- + arch/arm/crypto/chacha-glue.c | 304 +++++++++++++++++++++++++++ + arch/arm/crypto/chacha-neon-glue.c | 202 ------------------ + arch/arm/crypto/chacha-scalar-core.S | 65 +++--- + arch/arm64/crypto/chacha-neon-glue.c | 2 +- + 6 files changed, 340 insertions(+), 240 deletions(-) + create mode 100644 arch/arm/crypto/chacha-glue.c + delete mode 100644 arch/arm/crypto/chacha-neon-glue.c + +--- a/arch/arm/crypto/Kconfig ++++ b/arch/arm/crypto/Kconfig +@@ -127,10 +127,8 @@ config CRYPTO_CRC32_ARM_CE + select CRYPTO_HASH + + config CRYPTO_CHACHA20_NEON +- tristate "NEON accelerated ChaCha stream cipher algorithms" +- depends on KERNEL_MODE_NEON ++ tristate "NEON and scalar accelerated ChaCha stream cipher algorithms" + select CRYPTO_BLKCIPHER +- select CRYPTO_CHACHA20 + + config CRYPTO_NHPOLY1305_NEON + tristate "NEON accelerated NHPoly1305 hash function (for Adiantum)" +--- a/arch/arm/crypto/Makefile ++++ b/arch/arm/crypto/Makefile +@@ -53,7 +53,8 @@ aes-arm-ce-y := aes-ce-core.o aes-ce-glu + ghash-arm-ce-y := ghash-ce-core.o ghash-ce-glue.o + crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o + crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o +-chacha-neon-y := chacha-neon-core.o chacha-neon-glue.o ++chacha-neon-y := chacha-scalar-core.o chacha-glue.o ++chacha-neon-$(CONFIG_KERNEL_MODE_NEON) += chacha-neon-core.o + nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o + + ifdef REGENERATE_ARM_CRYPTO +--- /dev/null ++++ b/arch/arm/crypto/chacha-glue.c +@@ -0,0 +1,304 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * ARM NEON accelerated ChaCha and XChaCha stream ciphers, ++ * including ChaCha20 (RFC7539) ++ * ++ * Copyright (C) 2016-2019 Linaro, Ltd. ++ * Copyright (C) 2015 Martin Willi ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src, ++ int nrounds); ++asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src, ++ int nrounds); ++asmlinkage void hchacha_block_arm(const u32 *state, u32 *out, int nrounds); ++asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds); ++ ++asmlinkage void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes, ++ const u32 *state, int nrounds); ++ ++static inline bool neon_usable(void) ++{ ++ return crypto_simd_usable(); ++} ++ ++static void chacha_doneon(u32 *state, u8 *dst, const u8 *src, ++ unsigned int bytes, int nrounds) ++{ ++ u8 buf[CHACHA_BLOCK_SIZE]; ++ ++ while (bytes >= CHACHA_BLOCK_SIZE * 4) { ++ chacha_4block_xor_neon(state, dst, src, nrounds); ++ bytes -= CHACHA_BLOCK_SIZE * 4; ++ src += CHACHA_BLOCK_SIZE * 4; ++ dst += CHACHA_BLOCK_SIZE * 4; ++ state[12] += 4; ++ } ++ while (bytes >= CHACHA_BLOCK_SIZE) { ++ chacha_block_xor_neon(state, dst, src, nrounds); ++ bytes -= CHACHA_BLOCK_SIZE; ++ src += CHACHA_BLOCK_SIZE; ++ dst += CHACHA_BLOCK_SIZE; ++ state[12]++; ++ } ++ if (bytes) { ++ memcpy(buf, src, bytes); ++ chacha_block_xor_neon(state, buf, buf, nrounds); ++ memcpy(dst, buf, bytes); ++ } ++} ++ ++static int chacha_stream_xor(struct skcipher_request *req, ++ const struct chacha_ctx *ctx, const u8 *iv, ++ bool neon) ++{ ++ struct skcipher_walk walk; ++ u32 state[16]; ++ int err; ++ ++ err = skcipher_walk_virt(&walk, req, false); ++ ++ chacha_init_generic(state, ctx->key, iv); ++ ++ while (walk.nbytes > 0) { ++ unsigned int nbytes = walk.nbytes; ++ ++ if (nbytes < walk.total) ++ nbytes = round_down(nbytes, walk.stride); ++ ++ if (!neon) { ++ chacha_doarm(walk.dst.virt.addr, walk.src.virt.addr, ++ nbytes, state, ctx->nrounds); ++ state[12] += DIV_ROUND_UP(nbytes, CHACHA_BLOCK_SIZE); ++ } else { ++ kernel_neon_begin(); ++ chacha_doneon(state, walk.dst.virt.addr, ++ walk.src.virt.addr, nbytes, ctx->nrounds); ++ kernel_neon_end(); ++ } ++ err = skcipher_walk_done(&walk, walk.nbytes - nbytes); ++ } ++ ++ return err; ++} ++ ++static int do_chacha(struct skcipher_request *req, bool neon) ++{ ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); ++ struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); ++ ++ return chacha_stream_xor(req, ctx, req->iv, neon); ++} ++ ++static int chacha_arm(struct skcipher_request *req) ++{ ++ return do_chacha(req, false); ++} ++ ++static int chacha_neon(struct skcipher_request *req) ++{ ++ return do_chacha(req, neon_usable()); ++} ++ ++static int do_xchacha(struct skcipher_request *req, bool neon) ++{ ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); ++ struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); ++ struct chacha_ctx subctx; ++ u32 state[16]; ++ u8 real_iv[16]; ++ ++ chacha_init_generic(state, ctx->key, req->iv); ++ ++ if (!neon) { ++ hchacha_block_arm(state, subctx.key, ctx->nrounds); ++ } else { ++ kernel_neon_begin(); ++ hchacha_block_neon(state, subctx.key, ctx->nrounds); ++ kernel_neon_end(); ++ } ++ subctx.nrounds = ctx->nrounds; ++ ++ memcpy(&real_iv[0], req->iv + 24, 8); ++ memcpy(&real_iv[8], req->iv + 16, 8); ++ return chacha_stream_xor(req, &subctx, real_iv, neon); ++} ++ ++static int xchacha_arm(struct skcipher_request *req) ++{ ++ return do_xchacha(req, false); ++} ++ ++static int xchacha_neon(struct skcipher_request *req) ++{ ++ return do_xchacha(req, neon_usable()); ++} ++ ++static struct skcipher_alg arm_algs[] = { ++ { ++ .base.cra_name = "chacha20", ++ .base.cra_driver_name = "chacha20-arm", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = CHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .setkey = chacha20_setkey, ++ .encrypt = chacha_arm, ++ .decrypt = chacha_arm, ++ }, { ++ .base.cra_name = "xchacha20", ++ .base.cra_driver_name = "xchacha20-arm", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = XCHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .setkey = chacha20_setkey, ++ .encrypt = xchacha_arm, ++ .decrypt = xchacha_arm, ++ }, { ++ .base.cra_name = "xchacha12", ++ .base.cra_driver_name = "xchacha12-arm", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = XCHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .setkey = chacha12_setkey, ++ .encrypt = xchacha_arm, ++ .decrypt = xchacha_arm, ++ }, ++}; ++ ++static struct skcipher_alg neon_algs[] = { ++ { ++ .base.cra_name = "chacha20", ++ .base.cra_driver_name = "chacha20-neon", ++ .base.cra_priority = 300, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = CHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .walksize = 4 * CHACHA_BLOCK_SIZE, ++ .setkey = chacha20_setkey, ++ .encrypt = chacha_neon, ++ .decrypt = chacha_neon, ++ }, { ++ .base.cra_name = "xchacha20", ++ .base.cra_driver_name = "xchacha20-neon", ++ .base.cra_priority = 300, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = XCHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .walksize = 4 * CHACHA_BLOCK_SIZE, ++ .setkey = chacha20_setkey, ++ .encrypt = xchacha_neon, ++ .decrypt = xchacha_neon, ++ }, { ++ .base.cra_name = "xchacha12", ++ .base.cra_driver_name = "xchacha12-neon", ++ .base.cra_priority = 300, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = XCHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .walksize = 4 * CHACHA_BLOCK_SIZE, ++ .setkey = chacha12_setkey, ++ .encrypt = xchacha_neon, ++ .decrypt = xchacha_neon, ++ } ++}; ++ ++static int __init chacha_simd_mod_init(void) ++{ ++ int err; ++ ++ err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); ++ if (err) ++ return err; ++ ++ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) { ++ int i; ++ ++ switch (read_cpuid_part()) { ++ case ARM_CPU_PART_CORTEX_A7: ++ case ARM_CPU_PART_CORTEX_A5: ++ /* ++ * The Cortex-A7 and Cortex-A5 do not perform well with ++ * the NEON implementation but do incredibly with the ++ * scalar one and use less power. ++ */ ++ for (i = 0; i < ARRAY_SIZE(neon_algs); i++) ++ neon_algs[i].base.cra_priority = 0; ++ break; ++ } ++ ++ err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs)); ++ if (err) ++ crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); ++ } ++ return err; ++} ++ ++static void __exit chacha_simd_mod_fini(void) ++{ ++ crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); ++ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) ++ crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs)); ++} ++ ++module_init(chacha_simd_mod_init); ++module_exit(chacha_simd_mod_fini); ++ ++MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (scalar and NEON accelerated)"); ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_CRYPTO("chacha20"); ++MODULE_ALIAS_CRYPTO("chacha20-arm"); ++MODULE_ALIAS_CRYPTO("xchacha20"); ++MODULE_ALIAS_CRYPTO("xchacha20-arm"); ++MODULE_ALIAS_CRYPTO("xchacha12"); ++MODULE_ALIAS_CRYPTO("xchacha12-arm"); ++#ifdef CONFIG_KERNEL_MODE_NEON ++MODULE_ALIAS_CRYPTO("chacha20-neon"); ++MODULE_ALIAS_CRYPTO("xchacha20-neon"); ++MODULE_ALIAS_CRYPTO("xchacha12-neon"); ++#endif +--- a/arch/arm/crypto/chacha-neon-glue.c ++++ /dev/null +@@ -1,202 +0,0 @@ +-/* +- * ARM NEON accelerated ChaCha and XChaCha stream ciphers, +- * including ChaCha20 (RFC7539) +- * +- * Copyright (C) 2016 Linaro, Ltd. +- * +- * 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. +- * +- * Based on: +- * ChaCha20 256-bit cipher algorithm, RFC7539, SIMD glue code +- * +- * Copyright (C) 2015 Martin Willi +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src, +- int nrounds); +-asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src, +- int nrounds); +-asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds); +- +-static void chacha_doneon(u32 *state, u8 *dst, const u8 *src, +- unsigned int bytes, int nrounds) +-{ +- u8 buf[CHACHA_BLOCK_SIZE]; +- +- while (bytes >= CHACHA_BLOCK_SIZE * 4) { +- chacha_4block_xor_neon(state, dst, src, nrounds); +- bytes -= CHACHA_BLOCK_SIZE * 4; +- src += CHACHA_BLOCK_SIZE * 4; +- dst += CHACHA_BLOCK_SIZE * 4; +- state[12] += 4; +- } +- while (bytes >= CHACHA_BLOCK_SIZE) { +- chacha_block_xor_neon(state, dst, src, nrounds); +- bytes -= CHACHA_BLOCK_SIZE; +- src += CHACHA_BLOCK_SIZE; +- dst += CHACHA_BLOCK_SIZE; +- state[12]++; +- } +- if (bytes) { +- memcpy(buf, src, bytes); +- chacha_block_xor_neon(state, buf, buf, nrounds); +- memcpy(dst, buf, bytes); +- } +-} +- +-static int chacha_neon_stream_xor(struct skcipher_request *req, +- const struct chacha_ctx *ctx, const u8 *iv) +-{ +- struct skcipher_walk walk; +- u32 state[16]; +- int err; +- +- err = skcipher_walk_virt(&walk, req, false); +- +- crypto_chacha_init(state, ctx, iv); +- +- while (walk.nbytes > 0) { +- unsigned int nbytes = walk.nbytes; +- +- if (nbytes < walk.total) +- nbytes = round_down(nbytes, walk.stride); +- +- kernel_neon_begin(); +- chacha_doneon(state, walk.dst.virt.addr, walk.src.virt.addr, +- nbytes, ctx->nrounds); +- kernel_neon_end(); +- err = skcipher_walk_done(&walk, walk.nbytes - nbytes); +- } +- +- return err; +-} +- +-static int chacha_neon(struct skcipher_request *req) +-{ +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); +- +- if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) +- return crypto_chacha_crypt(req); +- +- return chacha_neon_stream_xor(req, ctx, req->iv); +-} +- +-static int xchacha_neon(struct skcipher_request *req) +-{ +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct chacha_ctx subctx; +- u32 state[16]; +- u8 real_iv[16]; +- +- if (req->cryptlen <= CHACHA_BLOCK_SIZE || !crypto_simd_usable()) +- return crypto_xchacha_crypt(req); +- +- crypto_chacha_init(state, ctx, req->iv); +- +- kernel_neon_begin(); +- hchacha_block_neon(state, subctx.key, ctx->nrounds); +- kernel_neon_end(); +- subctx.nrounds = ctx->nrounds; +- +- memcpy(&real_iv[0], req->iv + 24, 8); +- memcpy(&real_iv[8], req->iv + 16, 8); +- return chacha_neon_stream_xor(req, &subctx, real_iv); +-} +- +-static struct skcipher_alg algs[] = { +- { +- .base.cra_name = "chacha20", +- .base.cra_driver_name = "chacha20-neon", +- .base.cra_priority = 300, +- .base.cra_blocksize = 1, +- .base.cra_ctxsize = sizeof(struct chacha_ctx), +- .base.cra_module = THIS_MODULE, +- +- .min_keysize = CHACHA_KEY_SIZE, +- .max_keysize = CHACHA_KEY_SIZE, +- .ivsize = CHACHA_IV_SIZE, +- .chunksize = CHACHA_BLOCK_SIZE, +- .walksize = 4 * CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, +- .encrypt = chacha_neon, +- .decrypt = chacha_neon, +- }, { +- .base.cra_name = "xchacha20", +- .base.cra_driver_name = "xchacha20-neon", +- .base.cra_priority = 300, +- .base.cra_blocksize = 1, +- .base.cra_ctxsize = sizeof(struct chacha_ctx), +- .base.cra_module = THIS_MODULE, +- +- .min_keysize = CHACHA_KEY_SIZE, +- .max_keysize = CHACHA_KEY_SIZE, +- .ivsize = XCHACHA_IV_SIZE, +- .chunksize = CHACHA_BLOCK_SIZE, +- .walksize = 4 * CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, +- .encrypt = xchacha_neon, +- .decrypt = xchacha_neon, +- }, { +- .base.cra_name = "xchacha12", +- .base.cra_driver_name = "xchacha12-neon", +- .base.cra_priority = 300, +- .base.cra_blocksize = 1, +- .base.cra_ctxsize = sizeof(struct chacha_ctx), +- .base.cra_module = THIS_MODULE, +- +- .min_keysize = CHACHA_KEY_SIZE, +- .max_keysize = CHACHA_KEY_SIZE, +- .ivsize = XCHACHA_IV_SIZE, +- .chunksize = CHACHA_BLOCK_SIZE, +- .walksize = 4 * CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha12_setkey, +- .encrypt = xchacha_neon, +- .decrypt = xchacha_neon, +- } +-}; +- +-static int __init chacha_simd_mod_init(void) +-{ +- if (!(elf_hwcap & HWCAP_NEON)) +- return -ENODEV; +- +- return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); +-} +- +-static void __exit chacha_simd_mod_fini(void) +-{ +- crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); +-} +- +-module_init(chacha_simd_mod_init); +-module_exit(chacha_simd_mod_fini); +- +-MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (NEON accelerated)"); +-MODULE_AUTHOR("Ard Biesheuvel "); +-MODULE_LICENSE("GPL v2"); +-MODULE_ALIAS_CRYPTO("chacha20"); +-MODULE_ALIAS_CRYPTO("chacha20-neon"); +-MODULE_ALIAS_CRYPTO("xchacha20"); +-MODULE_ALIAS_CRYPTO("xchacha20-neon"); +-MODULE_ALIAS_CRYPTO("xchacha12"); +-MODULE_ALIAS_CRYPTO("xchacha12-neon"); +--- a/arch/arm/crypto/chacha-scalar-core.S ++++ b/arch/arm/crypto/chacha-scalar-core.S +@@ -41,14 +41,6 @@ + X14 .req r12 + X15 .req r14 + +-.Lexpand_32byte_k: +- // "expand 32-byte k" +- .word 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 +- +-#ifdef __thumb2__ +-# define adrl adr +-#endif +- + .macro __rev out, in, t0, t1, t2 + .if __LINUX_ARM_ARCH__ >= 6 + rev \out, \in +@@ -391,61 +383,65 @@ + .endm // _chacha + + /* +- * void chacha20_arm(u8 *out, const u8 *in, size_t len, const u32 key[8], +- * const u32 iv[4]); ++ * void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes, ++ * const u32 *state, int nrounds); + */ +-ENTRY(chacha20_arm) ++ENTRY(chacha_doarm) + cmp r2, #0 // len == 0? + reteq lr + ++ ldr ip, [sp] ++ cmp ip, #12 ++ + push {r0-r2,r4-r11,lr} + + // Push state x0-x15 onto stack. + // Also store an extra copy of x10-x11 just before the state. + +- ldr r4, [sp, #48] // iv +- mov r0, sp +- sub sp, #80 +- +- // iv: x12-x15 +- ldm r4, {X12,X13,X14,X15} +- stmdb r0!, {X12,X13,X14,X15} ++ add X12, r3, #48 ++ ldm X12, {X12,X13,X14,X15} ++ push {X12,X13,X14,X15} ++ sub sp, sp, #64 + +- // key: x4-x11 +- __ldrd X8_X10, X9_X11, r3, 24 ++ __ldrd X8_X10, X9_X11, r3, 40 + __strd X8_X10, X9_X11, sp, 8 +- stmdb r0!, {X8_X10, X9_X11} +- ldm r3, {X4-X9_X11} +- stmdb r0!, {X4-X9_X11} +- +- // constants: x0-x3 +- adrl X3, .Lexpand_32byte_k +- ldm X3, {X0-X3} ++ __strd X8_X10, X9_X11, sp, 56 ++ ldm r3, {X0-X9_X11} + __strd X0, X1, sp, 16 + __strd X2, X3, sp, 24 ++ __strd X4, X5, sp, 32 ++ __strd X6, X7, sp, 40 ++ __strd X8_X10, X9_X11, sp, 48 + ++ beq 1f + _chacha 20 + +- add sp, #76 ++0: add sp, #76 + pop {r4-r11, pc} +-ENDPROC(chacha20_arm) ++ ++1: _chacha 12 ++ b 0b ++ENDPROC(chacha_doarm) + + /* +- * void hchacha20_arm(const u32 state[16], u32 out[8]); ++ * void hchacha_block_arm(const u32 state[16], u32 out[8], int nrounds); + */ +-ENTRY(hchacha20_arm) ++ENTRY(hchacha_block_arm) + push {r1,r4-r11,lr} + ++ cmp r2, #12 // ChaCha12 ? ++ + mov r14, r0 + ldmia r14!, {r0-r11} // load x0-x11 + push {r10-r11} // store x10-x11 to stack + ldm r14, {r10-r12,r14} // load x12-x15 + sub sp, #8 + ++ beq 1f + _chacha_permute 20 + + // Skip over (unused0-unused1, x10-x11) +- add sp, #16 ++0: add sp, #16 + + // Fix up rotations of x12-x15 + ror X12, X12, #drot +@@ -458,4 +454,7 @@ ENTRY(hchacha20_arm) + stm r4, {X0,X1,X2,X3,X12,X13,X14,X15} + + pop {r4-r11,pc} +-ENDPROC(hchacha20_arm) ++ ++1: _chacha_permute 12 ++ b 0b ++ENDPROC(hchacha_block_arm) +--- a/arch/arm64/crypto/chacha-neon-glue.c ++++ b/arch/arm64/crypto/chacha-neon-glue.c +@@ -1,5 +1,5 @@ + /* +- * ARM NEON accelerated ChaCha and XChaCha stream ciphers, ++ * ARM NEON and scalar accelerated ChaCha and XChaCha stream ciphers, + * including ChaCha20 (RFC7539) + * + * Copyright (C) 2016 - 2017 Linaro, Ltd. diff --git a/ipq806x/backport-5.4/080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch b/ipq806x/backport-5.4/080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch new file mode 100644 index 0000000..4006dc6 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0009-crypto-arm-chacha-expose-ARM-ChaCha-routine-as-libra.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:15 +0100 +Subject: [PATCH] crypto: arm/chacha - expose ARM ChaCha routine as library + function + +commit a44a3430d71bad4ee56788a59fff099b291ea54c upstream. + +Expose the accelerated NEON ChaCha routine directly as a symbol +export so that users of the ChaCha library API can use it directly. + +Given that calls into the library API will always go through the +routines in this module if it is enabled, switch to static keys +to select the optimal implementation available (which may be none +at all, in which case we defer to the generic implementation for +all invocations). + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/Kconfig | 1 + + arch/arm/crypto/chacha-glue.c | 41 ++++++++++++++++++++++++++++++++++- + 2 files changed, 41 insertions(+), 1 deletion(-) + +--- a/arch/arm/crypto/Kconfig ++++ b/arch/arm/crypto/Kconfig +@@ -129,6 +129,7 @@ config CRYPTO_CRC32_ARM_CE + config CRYPTO_CHACHA20_NEON + tristate "NEON and scalar accelerated ChaCha stream cipher algorithms" + select CRYPTO_BLKCIPHER ++ select CRYPTO_ARCH_HAVE_LIB_CHACHA + + config CRYPTO_NHPOLY1305_NEON + tristate "NEON accelerated NHPoly1305 hash function (for Adiantum)" +--- a/arch/arm/crypto/chacha-glue.c ++++ b/arch/arm/crypto/chacha-glue.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -29,9 +30,11 @@ asmlinkage void hchacha_block_neon(const + asmlinkage void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes, + const u32 *state, int nrounds); + ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(use_neon); ++ + static inline bool neon_usable(void) + { +- return crypto_simd_usable(); ++ return static_branch_likely(&use_neon) && crypto_simd_usable(); + } + + static void chacha_doneon(u32 *state, u8 *dst, const u8 *src, +@@ -60,6 +63,40 @@ static void chacha_doneon(u32 *state, u8 + } + } + ++void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds) ++{ ++ if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable()) { ++ hchacha_block_arm(state, stream, nrounds); ++ } else { ++ kernel_neon_begin(); ++ hchacha_block_neon(state, stream, nrounds); ++ kernel_neon_end(); ++ } ++} ++EXPORT_SYMBOL(hchacha_block_arch); ++ ++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv) ++{ ++ chacha_init_generic(state, key, iv); ++} ++EXPORT_SYMBOL(chacha_init_arch); ++ ++void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes, ++ int nrounds) ++{ ++ if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable() || ++ bytes <= CHACHA_BLOCK_SIZE) { ++ chacha_doarm(dst, src, bytes, state, nrounds); ++ state[12] += DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE); ++ return; ++ } ++ ++ kernel_neon_begin(); ++ chacha_doneon(state, dst, src, bytes, nrounds); ++ kernel_neon_end(); ++} ++EXPORT_SYMBOL(chacha_crypt_arch); ++ + static int chacha_stream_xor(struct skcipher_request *req, + const struct chacha_ctx *ctx, const u8 *iv, + bool neon) +@@ -269,6 +306,8 @@ static int __init chacha_simd_mod_init(v + for (i = 0; i < ARRAY_SIZE(neon_algs); i++) + neon_algs[i].base.cra_priority = 0; + break; ++ default: ++ static_branch_enable(&use_neon); + } + + err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs)); diff --git a/ipq806x/backport-5.4/080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch b/ipq806x/backport-5.4/080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch new file mode 100644 index 0000000..0a2b4c4 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0010-crypto-mips-chacha-import-32r2-ChaCha-code-from-Zinc.patch @@ -0,0 +1,451 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 8 Nov 2019 13:22:16 +0100 +Subject: [PATCH] crypto: mips/chacha - import 32r2 ChaCha code from Zinc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 49aa7c00eddf8d8f462b0256bd82e81762d7b0c6 upstream. + +This imports the accelerated MIPS 32r2 ChaCha20 implementation from the +Zinc patch set. + +Co-developed-by: René van Dorst +Signed-off-by: René van Dorst +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/mips/crypto/chacha-core.S | 424 +++++++++++++++++++++++++++++++++ + 1 file changed, 424 insertions(+) + create mode 100644 arch/mips/crypto/chacha-core.S + +--- /dev/null ++++ b/arch/mips/crypto/chacha-core.S +@@ -0,0 +1,424 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2016-2018 René van Dorst . All Rights Reserved. ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#define MASK_U32 0x3c ++#define CHACHA20_BLOCK_SIZE 64 ++#define STACK_SIZE 32 ++ ++#define X0 $t0 ++#define X1 $t1 ++#define X2 $t2 ++#define X3 $t3 ++#define X4 $t4 ++#define X5 $t5 ++#define X6 $t6 ++#define X7 $t7 ++#define X8 $t8 ++#define X9 $t9 ++#define X10 $v1 ++#define X11 $s6 ++#define X12 $s5 ++#define X13 $s4 ++#define X14 $s3 ++#define X15 $s2 ++/* Use regs which are overwritten on exit for Tx so we don't leak clear data. */ ++#define T0 $s1 ++#define T1 $s0 ++#define T(n) T ## n ++#define X(n) X ## n ++ ++/* Input arguments */ ++#define STATE $a0 ++#define OUT $a1 ++#define IN $a2 ++#define BYTES $a3 ++ ++/* Output argument */ ++/* NONCE[0] is kept in a register and not in memory. ++ * We don't want to touch original value in memory. ++ * Must be incremented every loop iteration. ++ */ ++#define NONCE_0 $v0 ++ ++/* SAVED_X and SAVED_CA are set in the jump table. ++ * Use regs which are overwritten on exit else we don't leak clear data. ++ * They are used to handling the last bytes which are not multiple of 4. ++ */ ++#define SAVED_X X15 ++#define SAVED_CA $s7 ++ ++#define IS_UNALIGNED $s7 ++ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++#define MSB 0 ++#define LSB 3 ++#define ROTx rotl ++#define ROTR(n) rotr n, 24 ++#define CPU_TO_LE32(n) \ ++ wsbh n; \ ++ rotr n, 16; ++#else ++#define MSB 3 ++#define LSB 0 ++#define ROTx rotr ++#define CPU_TO_LE32(n) ++#define ROTR(n) ++#endif ++ ++#define FOR_EACH_WORD(x) \ ++ x( 0); \ ++ x( 1); \ ++ x( 2); \ ++ x( 3); \ ++ x( 4); \ ++ x( 5); \ ++ x( 6); \ ++ x( 7); \ ++ x( 8); \ ++ x( 9); \ ++ x(10); \ ++ x(11); \ ++ x(12); \ ++ x(13); \ ++ x(14); \ ++ x(15); ++ ++#define FOR_EACH_WORD_REV(x) \ ++ x(15); \ ++ x(14); \ ++ x(13); \ ++ x(12); \ ++ x(11); \ ++ x(10); \ ++ x( 9); \ ++ x( 8); \ ++ x( 7); \ ++ x( 6); \ ++ x( 5); \ ++ x( 4); \ ++ x( 3); \ ++ x( 2); \ ++ x( 1); \ ++ x( 0); ++ ++#define PLUS_ONE_0 1 ++#define PLUS_ONE_1 2 ++#define PLUS_ONE_2 3 ++#define PLUS_ONE_3 4 ++#define PLUS_ONE_4 5 ++#define PLUS_ONE_5 6 ++#define PLUS_ONE_6 7 ++#define PLUS_ONE_7 8 ++#define PLUS_ONE_8 9 ++#define PLUS_ONE_9 10 ++#define PLUS_ONE_10 11 ++#define PLUS_ONE_11 12 ++#define PLUS_ONE_12 13 ++#define PLUS_ONE_13 14 ++#define PLUS_ONE_14 15 ++#define PLUS_ONE_15 16 ++#define PLUS_ONE(x) PLUS_ONE_ ## x ++#define _CONCAT3(a,b,c) a ## b ## c ++#define CONCAT3(a,b,c) _CONCAT3(a,b,c) ++ ++#define STORE_UNALIGNED(x) \ ++CONCAT3(.Lchacha20_mips_xor_unaligned_, PLUS_ONE(x), _b: ;) \ ++ .if (x != 12); \ ++ lw T0, (x*4)(STATE); \ ++ .endif; \ ++ lwl T1, (x*4)+MSB ## (IN); \ ++ lwr T1, (x*4)+LSB ## (IN); \ ++ .if (x == 12); \ ++ addu X ## x, NONCE_0; \ ++ .else; \ ++ addu X ## x, T0; \ ++ .endif; \ ++ CPU_TO_LE32(X ## x); \ ++ xor X ## x, T1; \ ++ swl X ## x, (x*4)+MSB ## (OUT); \ ++ swr X ## x, (x*4)+LSB ## (OUT); ++ ++#define STORE_ALIGNED(x) \ ++CONCAT3(.Lchacha20_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \ ++ .if (x != 12); \ ++ lw T0, (x*4)(STATE); \ ++ .endif; \ ++ lw T1, (x*4) ## (IN); \ ++ .if (x == 12); \ ++ addu X ## x, NONCE_0; \ ++ .else; \ ++ addu X ## x, T0; \ ++ .endif; \ ++ CPU_TO_LE32(X ## x); \ ++ xor X ## x, T1; \ ++ sw X ## x, (x*4) ## (OUT); ++ ++/* Jump table macro. ++ * Used for setup and handling the last bytes, which are not multiple of 4. ++ * X15 is free to store Xn ++ * Every jumptable entry must be equal in size. ++ */ ++#define JMPTBL_ALIGNED(x) \ ++.Lchacha20_mips_jmptbl_aligned_ ## x: ; \ ++ .set noreorder; \ ++ b .Lchacha20_mips_xor_aligned_ ## x ## _b; \ ++ .if (x == 12); \ ++ addu SAVED_X, X ## x, NONCE_0; \ ++ .else; \ ++ addu SAVED_X, X ## x, SAVED_CA; \ ++ .endif; \ ++ .set reorder ++ ++#define JMPTBL_UNALIGNED(x) \ ++.Lchacha20_mips_jmptbl_unaligned_ ## x: ; \ ++ .set noreorder; \ ++ b .Lchacha20_mips_xor_unaligned_ ## x ## _b; \ ++ .if (x == 12); \ ++ addu SAVED_X, X ## x, NONCE_0; \ ++ .else; \ ++ addu SAVED_X, X ## x, SAVED_CA; \ ++ .endif; \ ++ .set reorder ++ ++#define AXR(A, B, C, D, K, L, M, N, V, W, Y, Z, S) \ ++ addu X(A), X(K); \ ++ addu X(B), X(L); \ ++ addu X(C), X(M); \ ++ addu X(D), X(N); \ ++ xor X(V), X(A); \ ++ xor X(W), X(B); \ ++ xor X(Y), X(C); \ ++ xor X(Z), X(D); \ ++ rotl X(V), S; \ ++ rotl X(W), S; \ ++ rotl X(Y), S; \ ++ rotl X(Z), S; ++ ++.text ++.set reorder ++.set noat ++.globl chacha20_mips ++.ent chacha20_mips ++chacha20_mips: ++ .frame $sp, STACK_SIZE, $ra ++ ++ addiu $sp, -STACK_SIZE ++ ++ /* Return bytes = 0. */ ++ beqz BYTES, .Lchacha20_mips_end ++ ++ lw NONCE_0, 48(STATE) ++ ++ /* Save s0-s7 */ ++ sw $s0, 0($sp) ++ sw $s1, 4($sp) ++ sw $s2, 8($sp) ++ sw $s3, 12($sp) ++ sw $s4, 16($sp) ++ sw $s5, 20($sp) ++ sw $s6, 24($sp) ++ sw $s7, 28($sp) ++ ++ /* Test IN or OUT is unaligned. ++ * IS_UNALIGNED = ( IN | OUT ) & 0x00000003 ++ */ ++ or IS_UNALIGNED, IN, OUT ++ andi IS_UNALIGNED, 0x3 ++ ++ /* Set number of rounds */ ++ li $at, 20 ++ ++ b .Lchacha20_rounds_start ++ ++.align 4 ++.Loop_chacha20_rounds: ++ addiu IN, CHACHA20_BLOCK_SIZE ++ addiu OUT, CHACHA20_BLOCK_SIZE ++ addiu NONCE_0, 1 ++ ++.Lchacha20_rounds_start: ++ lw X0, 0(STATE) ++ lw X1, 4(STATE) ++ lw X2, 8(STATE) ++ lw X3, 12(STATE) ++ ++ lw X4, 16(STATE) ++ lw X5, 20(STATE) ++ lw X6, 24(STATE) ++ lw X7, 28(STATE) ++ lw X8, 32(STATE) ++ lw X9, 36(STATE) ++ lw X10, 40(STATE) ++ lw X11, 44(STATE) ++ ++ move X12, NONCE_0 ++ lw X13, 52(STATE) ++ lw X14, 56(STATE) ++ lw X15, 60(STATE) ++ ++.Loop_chacha20_xor_rounds: ++ addiu $at, -2 ++ AXR( 0, 1, 2, 3, 4, 5, 6, 7, 12,13,14,15, 16); ++ AXR( 8, 9,10,11, 12,13,14,15, 4, 5, 6, 7, 12); ++ AXR( 0, 1, 2, 3, 4, 5, 6, 7, 12,13,14,15, 8); ++ AXR( 8, 9,10,11, 12,13,14,15, 4, 5, 6, 7, 7); ++ AXR( 0, 1, 2, 3, 5, 6, 7, 4, 15,12,13,14, 16); ++ AXR(10,11, 8, 9, 15,12,13,14, 5, 6, 7, 4, 12); ++ AXR( 0, 1, 2, 3, 5, 6, 7, 4, 15,12,13,14, 8); ++ AXR(10,11, 8, 9, 15,12,13,14, 5, 6, 7, 4, 7); ++ bnez $at, .Loop_chacha20_xor_rounds ++ ++ addiu BYTES, -(CHACHA20_BLOCK_SIZE) ++ ++ /* Is data src/dst unaligned? Jump */ ++ bnez IS_UNALIGNED, .Loop_chacha20_unaligned ++ ++ /* Set number rounds here to fill delayslot. */ ++ li $at, 20 ++ ++ /* BYTES < 0, it has no full block. */ ++ bltz BYTES, .Lchacha20_mips_no_full_block_aligned ++ ++ FOR_EACH_WORD_REV(STORE_ALIGNED) ++ ++ /* BYTES > 0? Loop again. */ ++ bgtz BYTES, .Loop_chacha20_rounds ++ ++ /* Place this here to fill delay slot */ ++ addiu NONCE_0, 1 ++ ++ /* BYTES < 0? Handle last bytes */ ++ bltz BYTES, .Lchacha20_mips_xor_bytes ++ ++.Lchacha20_mips_xor_done: ++ /* Restore used registers */ ++ lw $s0, 0($sp) ++ lw $s1, 4($sp) ++ lw $s2, 8($sp) ++ lw $s3, 12($sp) ++ lw $s4, 16($sp) ++ lw $s5, 20($sp) ++ lw $s6, 24($sp) ++ lw $s7, 28($sp) ++ ++ /* Write NONCE_0 back to right location in state */ ++ sw NONCE_0, 48(STATE) ++ ++.Lchacha20_mips_end: ++ addiu $sp, STACK_SIZE ++ jr $ra ++ ++.Lchacha20_mips_no_full_block_aligned: ++ /* Restore the offset on BYTES */ ++ addiu BYTES, CHACHA20_BLOCK_SIZE ++ ++ /* Get number of full WORDS */ ++ andi $at, BYTES, MASK_U32 ++ ++ /* Load upper half of jump table addr */ ++ lui T0, %hi(.Lchacha20_mips_jmptbl_aligned_0) ++ ++ /* Calculate lower half jump table offset */ ++ ins T0, $at, 1, 6 ++ ++ /* Add offset to STATE */ ++ addu T1, STATE, $at ++ ++ /* Add lower half jump table addr */ ++ addiu T0, %lo(.Lchacha20_mips_jmptbl_aligned_0) ++ ++ /* Read value from STATE */ ++ lw SAVED_CA, 0(T1) ++ ++ /* Store remaining bytecounter as negative value */ ++ subu BYTES, $at, BYTES ++ ++ jr T0 ++ ++ /* Jump table */ ++ FOR_EACH_WORD(JMPTBL_ALIGNED) ++ ++ ++.Loop_chacha20_unaligned: ++ /* Set number rounds here to fill delayslot. */ ++ li $at, 20 ++ ++ /* BYTES > 0, it has no full block. */ ++ bltz BYTES, .Lchacha20_mips_no_full_block_unaligned ++ ++ FOR_EACH_WORD_REV(STORE_UNALIGNED) ++ ++ /* BYTES > 0? Loop again. */ ++ bgtz BYTES, .Loop_chacha20_rounds ++ ++ /* Write NONCE_0 back to right location in state */ ++ sw NONCE_0, 48(STATE) ++ ++ .set noreorder ++ /* Fall through to byte handling */ ++ bgez BYTES, .Lchacha20_mips_xor_done ++.Lchacha20_mips_xor_unaligned_0_b: ++.Lchacha20_mips_xor_aligned_0_b: ++ /* Place this here to fill delay slot */ ++ addiu NONCE_0, 1 ++ .set reorder ++ ++.Lchacha20_mips_xor_bytes: ++ addu IN, $at ++ addu OUT, $at ++ /* First byte */ ++ lbu T1, 0(IN) ++ addiu $at, BYTES, 1 ++ CPU_TO_LE32(SAVED_X) ++ ROTR(SAVED_X) ++ xor T1, SAVED_X ++ sb T1, 0(OUT) ++ beqz $at, .Lchacha20_mips_xor_done ++ /* Second byte */ ++ lbu T1, 1(IN) ++ addiu $at, BYTES, 2 ++ ROTx SAVED_X, 8 ++ xor T1, SAVED_X ++ sb T1, 1(OUT) ++ beqz $at, .Lchacha20_mips_xor_done ++ /* Third byte */ ++ lbu T1, 2(IN) ++ ROTx SAVED_X, 8 ++ xor T1, SAVED_X ++ sb T1, 2(OUT) ++ b .Lchacha20_mips_xor_done ++ ++.Lchacha20_mips_no_full_block_unaligned: ++ /* Restore the offset on BYTES */ ++ addiu BYTES, CHACHA20_BLOCK_SIZE ++ ++ /* Get number of full WORDS */ ++ andi $at, BYTES, MASK_U32 ++ ++ /* Load upper half of jump table addr */ ++ lui T0, %hi(.Lchacha20_mips_jmptbl_unaligned_0) ++ ++ /* Calculate lower half jump table offset */ ++ ins T0, $at, 1, 6 ++ ++ /* Add offset to STATE */ ++ addu T1, STATE, $at ++ ++ /* Add lower half jump table addr */ ++ addiu T0, %lo(.Lchacha20_mips_jmptbl_unaligned_0) ++ ++ /* Read value from STATE */ ++ lw SAVED_CA, 0(T1) ++ ++ /* Store remaining bytecounter as negative value */ ++ subu BYTES, $at, BYTES ++ ++ jr T0 ++ ++ /* Jump table */ ++ FOR_EACH_WORD(JMPTBL_UNALIGNED) ++.end chacha20_mips ++.set at diff --git a/ipq806x/backport-5.4/080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch b/ipq806x/backport-5.4/080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch new file mode 100644 index 0000000..0d24ce2 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0011-crypto-mips-chacha-wire-up-accelerated-32r2-code-fro.patch @@ -0,0 +1,559 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:17 +0100 +Subject: [PATCH] crypto: mips/chacha - wire up accelerated 32r2 code from Zinc +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 3a2f58f3ba4f6f44e33d1a48240d5eadb882cb59 upstream. + +This integrates the accelerated MIPS 32r2 implementation of ChaCha +into both the API and library interfaces of the kernel crypto stack. + +The significance of this is that, in addition to becoming available +as an accelerated library implementation, it can also be used by +existing crypto API code such as Adiantum (for block encryption on +ultra low performance cores) or IPsec using chacha20poly1305. These +are use cases that have already opted into using the abstract crypto +API. In order to support Adiantum, the core assembler routine has +been adapted to take the round count as a function argument rather +than hardcoding it to 20. + +Co-developed-by: René van Dorst +Signed-off-by: René van Dorst +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/mips/Makefile | 2 +- + arch/mips/crypto/Makefile | 4 + + arch/mips/crypto/chacha-core.S | 159 ++++++++++++++++++++++++--------- + arch/mips/crypto/chacha-glue.c | 150 +++++++++++++++++++++++++++++++ + crypto/Kconfig | 6 ++ + 5 files changed, 277 insertions(+), 44 deletions(-) + create mode 100644 arch/mips/crypto/chacha-glue.c + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -334,7 +334,7 @@ libs-$(CONFIG_MIPS_FP_SUPPORT) += arch/m + # See arch/mips/Kbuild for content of core part of the kernel + core-y += arch/mips/ + +-drivers-$(CONFIG_MIPS_CRC_SUPPORT) += arch/mips/crypto/ ++drivers-y += arch/mips/crypto/ + drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/ + + # suspend and hibernation support +--- a/arch/mips/crypto/Makefile ++++ b/arch/mips/crypto/Makefile +@@ -4,3 +4,7 @@ + # + + obj-$(CONFIG_CRYPTO_CRC32_MIPS) += crc32-mips.o ++ ++obj-$(CONFIG_CRYPTO_CHACHA_MIPS) += chacha-mips.o ++chacha-mips-y := chacha-core.o chacha-glue.o ++AFLAGS_chacha-core.o += -O2 # needed to fill branch delay slots +--- a/arch/mips/crypto/chacha-core.S ++++ b/arch/mips/crypto/chacha-core.S +@@ -125,7 +125,7 @@ + #define CONCAT3(a,b,c) _CONCAT3(a,b,c) + + #define STORE_UNALIGNED(x) \ +-CONCAT3(.Lchacha20_mips_xor_unaligned_, PLUS_ONE(x), _b: ;) \ ++CONCAT3(.Lchacha_mips_xor_unaligned_, PLUS_ONE(x), _b: ;) \ + .if (x != 12); \ + lw T0, (x*4)(STATE); \ + .endif; \ +@@ -142,7 +142,7 @@ CONCAT3(.Lchacha20_mips_xor_unaligned_, + swr X ## x, (x*4)+LSB ## (OUT); + + #define STORE_ALIGNED(x) \ +-CONCAT3(.Lchacha20_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \ ++CONCAT3(.Lchacha_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \ + .if (x != 12); \ + lw T0, (x*4)(STATE); \ + .endif; \ +@@ -162,9 +162,9 @@ CONCAT3(.Lchacha20_mips_xor_aligned_, PL + * Every jumptable entry must be equal in size. + */ + #define JMPTBL_ALIGNED(x) \ +-.Lchacha20_mips_jmptbl_aligned_ ## x: ; \ ++.Lchacha_mips_jmptbl_aligned_ ## x: ; \ + .set noreorder; \ +- b .Lchacha20_mips_xor_aligned_ ## x ## _b; \ ++ b .Lchacha_mips_xor_aligned_ ## x ## _b; \ + .if (x == 12); \ + addu SAVED_X, X ## x, NONCE_0; \ + .else; \ +@@ -173,9 +173,9 @@ CONCAT3(.Lchacha20_mips_xor_aligned_, PL + .set reorder + + #define JMPTBL_UNALIGNED(x) \ +-.Lchacha20_mips_jmptbl_unaligned_ ## x: ; \ ++.Lchacha_mips_jmptbl_unaligned_ ## x: ; \ + .set noreorder; \ +- b .Lchacha20_mips_xor_unaligned_ ## x ## _b; \ ++ b .Lchacha_mips_xor_unaligned_ ## x ## _b; \ + .if (x == 12); \ + addu SAVED_X, X ## x, NONCE_0; \ + .else; \ +@@ -200,15 +200,18 @@ CONCAT3(.Lchacha20_mips_xor_aligned_, PL + .text + .set reorder + .set noat +-.globl chacha20_mips +-.ent chacha20_mips +-chacha20_mips: ++.globl chacha_crypt_arch ++.ent chacha_crypt_arch ++chacha_crypt_arch: + .frame $sp, STACK_SIZE, $ra + ++ /* Load number of rounds */ ++ lw $at, 16($sp) ++ + addiu $sp, -STACK_SIZE + + /* Return bytes = 0. */ +- beqz BYTES, .Lchacha20_mips_end ++ beqz BYTES, .Lchacha_mips_end + + lw NONCE_0, 48(STATE) + +@@ -228,18 +231,15 @@ chacha20_mips: + or IS_UNALIGNED, IN, OUT + andi IS_UNALIGNED, 0x3 + +- /* Set number of rounds */ +- li $at, 20 +- +- b .Lchacha20_rounds_start ++ b .Lchacha_rounds_start + + .align 4 +-.Loop_chacha20_rounds: ++.Loop_chacha_rounds: + addiu IN, CHACHA20_BLOCK_SIZE + addiu OUT, CHACHA20_BLOCK_SIZE + addiu NONCE_0, 1 + +-.Lchacha20_rounds_start: ++.Lchacha_rounds_start: + lw X0, 0(STATE) + lw X1, 4(STATE) + lw X2, 8(STATE) +@@ -259,7 +259,7 @@ chacha20_mips: + lw X14, 56(STATE) + lw X15, 60(STATE) + +-.Loop_chacha20_xor_rounds: ++.Loop_chacha_xor_rounds: + addiu $at, -2 + AXR( 0, 1, 2, 3, 4, 5, 6, 7, 12,13,14,15, 16); + AXR( 8, 9,10,11, 12,13,14,15, 4, 5, 6, 7, 12); +@@ -269,31 +269,31 @@ chacha20_mips: + AXR(10,11, 8, 9, 15,12,13,14, 5, 6, 7, 4, 12); + AXR( 0, 1, 2, 3, 5, 6, 7, 4, 15,12,13,14, 8); + AXR(10,11, 8, 9, 15,12,13,14, 5, 6, 7, 4, 7); +- bnez $at, .Loop_chacha20_xor_rounds ++ bnez $at, .Loop_chacha_xor_rounds + + addiu BYTES, -(CHACHA20_BLOCK_SIZE) + + /* Is data src/dst unaligned? Jump */ +- bnez IS_UNALIGNED, .Loop_chacha20_unaligned ++ bnez IS_UNALIGNED, .Loop_chacha_unaligned + + /* Set number rounds here to fill delayslot. */ +- li $at, 20 ++ lw $at, (STACK_SIZE+16)($sp) + + /* BYTES < 0, it has no full block. */ +- bltz BYTES, .Lchacha20_mips_no_full_block_aligned ++ bltz BYTES, .Lchacha_mips_no_full_block_aligned + + FOR_EACH_WORD_REV(STORE_ALIGNED) + + /* BYTES > 0? Loop again. */ +- bgtz BYTES, .Loop_chacha20_rounds ++ bgtz BYTES, .Loop_chacha_rounds + + /* Place this here to fill delay slot */ + addiu NONCE_0, 1 + + /* BYTES < 0? Handle last bytes */ +- bltz BYTES, .Lchacha20_mips_xor_bytes ++ bltz BYTES, .Lchacha_mips_xor_bytes + +-.Lchacha20_mips_xor_done: ++.Lchacha_mips_xor_done: + /* Restore used registers */ + lw $s0, 0($sp) + lw $s1, 4($sp) +@@ -307,11 +307,11 @@ chacha20_mips: + /* Write NONCE_0 back to right location in state */ + sw NONCE_0, 48(STATE) + +-.Lchacha20_mips_end: ++.Lchacha_mips_end: + addiu $sp, STACK_SIZE + jr $ra + +-.Lchacha20_mips_no_full_block_aligned: ++.Lchacha_mips_no_full_block_aligned: + /* Restore the offset on BYTES */ + addiu BYTES, CHACHA20_BLOCK_SIZE + +@@ -319,7 +319,7 @@ chacha20_mips: + andi $at, BYTES, MASK_U32 + + /* Load upper half of jump table addr */ +- lui T0, %hi(.Lchacha20_mips_jmptbl_aligned_0) ++ lui T0, %hi(.Lchacha_mips_jmptbl_aligned_0) + + /* Calculate lower half jump table offset */ + ins T0, $at, 1, 6 +@@ -328,7 +328,7 @@ chacha20_mips: + addu T1, STATE, $at + + /* Add lower half jump table addr */ +- addiu T0, %lo(.Lchacha20_mips_jmptbl_aligned_0) ++ addiu T0, %lo(.Lchacha_mips_jmptbl_aligned_0) + + /* Read value from STATE */ + lw SAVED_CA, 0(T1) +@@ -342,31 +342,31 @@ chacha20_mips: + FOR_EACH_WORD(JMPTBL_ALIGNED) + + +-.Loop_chacha20_unaligned: ++.Loop_chacha_unaligned: + /* Set number rounds here to fill delayslot. */ +- li $at, 20 ++ lw $at, (STACK_SIZE+16)($sp) + + /* BYTES > 0, it has no full block. */ +- bltz BYTES, .Lchacha20_mips_no_full_block_unaligned ++ bltz BYTES, .Lchacha_mips_no_full_block_unaligned + + FOR_EACH_WORD_REV(STORE_UNALIGNED) + + /* BYTES > 0? Loop again. */ +- bgtz BYTES, .Loop_chacha20_rounds ++ bgtz BYTES, .Loop_chacha_rounds + + /* Write NONCE_0 back to right location in state */ + sw NONCE_0, 48(STATE) + + .set noreorder + /* Fall through to byte handling */ +- bgez BYTES, .Lchacha20_mips_xor_done +-.Lchacha20_mips_xor_unaligned_0_b: +-.Lchacha20_mips_xor_aligned_0_b: ++ bgez BYTES, .Lchacha_mips_xor_done ++.Lchacha_mips_xor_unaligned_0_b: ++.Lchacha_mips_xor_aligned_0_b: + /* Place this here to fill delay slot */ + addiu NONCE_0, 1 + .set reorder + +-.Lchacha20_mips_xor_bytes: ++.Lchacha_mips_xor_bytes: + addu IN, $at + addu OUT, $at + /* First byte */ +@@ -376,22 +376,22 @@ chacha20_mips: + ROTR(SAVED_X) + xor T1, SAVED_X + sb T1, 0(OUT) +- beqz $at, .Lchacha20_mips_xor_done ++ beqz $at, .Lchacha_mips_xor_done + /* Second byte */ + lbu T1, 1(IN) + addiu $at, BYTES, 2 + ROTx SAVED_X, 8 + xor T1, SAVED_X + sb T1, 1(OUT) +- beqz $at, .Lchacha20_mips_xor_done ++ beqz $at, .Lchacha_mips_xor_done + /* Third byte */ + lbu T1, 2(IN) + ROTx SAVED_X, 8 + xor T1, SAVED_X + sb T1, 2(OUT) +- b .Lchacha20_mips_xor_done ++ b .Lchacha_mips_xor_done + +-.Lchacha20_mips_no_full_block_unaligned: ++.Lchacha_mips_no_full_block_unaligned: + /* Restore the offset on BYTES */ + addiu BYTES, CHACHA20_BLOCK_SIZE + +@@ -399,7 +399,7 @@ chacha20_mips: + andi $at, BYTES, MASK_U32 + + /* Load upper half of jump table addr */ +- lui T0, %hi(.Lchacha20_mips_jmptbl_unaligned_0) ++ lui T0, %hi(.Lchacha_mips_jmptbl_unaligned_0) + + /* Calculate lower half jump table offset */ + ins T0, $at, 1, 6 +@@ -408,7 +408,7 @@ chacha20_mips: + addu T1, STATE, $at + + /* Add lower half jump table addr */ +- addiu T0, %lo(.Lchacha20_mips_jmptbl_unaligned_0) ++ addiu T0, %lo(.Lchacha_mips_jmptbl_unaligned_0) + + /* Read value from STATE */ + lw SAVED_CA, 0(T1) +@@ -420,5 +420,78 @@ chacha20_mips: + + /* Jump table */ + FOR_EACH_WORD(JMPTBL_UNALIGNED) +-.end chacha20_mips ++.end chacha_crypt_arch ++.set at ++ ++/* Input arguments ++ * STATE $a0 ++ * OUT $a1 ++ * NROUND $a2 ++ */ ++ ++#undef X12 ++#undef X13 ++#undef X14 ++#undef X15 ++ ++#define X12 $a3 ++#define X13 $at ++#define X14 $v0 ++#define X15 STATE ++ ++.set noat ++.globl hchacha_block_arch ++.ent hchacha_block_arch ++hchacha_block_arch: ++ .frame $sp, STACK_SIZE, $ra ++ ++ addiu $sp, -STACK_SIZE ++ ++ /* Save X11(s6) */ ++ sw X11, 0($sp) ++ ++ lw X0, 0(STATE) ++ lw X1, 4(STATE) ++ lw X2, 8(STATE) ++ lw X3, 12(STATE) ++ lw X4, 16(STATE) ++ lw X5, 20(STATE) ++ lw X6, 24(STATE) ++ lw X7, 28(STATE) ++ lw X8, 32(STATE) ++ lw X9, 36(STATE) ++ lw X10, 40(STATE) ++ lw X11, 44(STATE) ++ lw X12, 48(STATE) ++ lw X13, 52(STATE) ++ lw X14, 56(STATE) ++ lw X15, 60(STATE) ++ ++.Loop_hchacha_xor_rounds: ++ addiu $a2, -2 ++ AXR( 0, 1, 2, 3, 4, 5, 6, 7, 12,13,14,15, 16); ++ AXR( 8, 9,10,11, 12,13,14,15, 4, 5, 6, 7, 12); ++ AXR( 0, 1, 2, 3, 4, 5, 6, 7, 12,13,14,15, 8); ++ AXR( 8, 9,10,11, 12,13,14,15, 4, 5, 6, 7, 7); ++ AXR( 0, 1, 2, 3, 5, 6, 7, 4, 15,12,13,14, 16); ++ AXR(10,11, 8, 9, 15,12,13,14, 5, 6, 7, 4, 12); ++ AXR( 0, 1, 2, 3, 5, 6, 7, 4, 15,12,13,14, 8); ++ AXR(10,11, 8, 9, 15,12,13,14, 5, 6, 7, 4, 7); ++ bnez $a2, .Loop_hchacha_xor_rounds ++ ++ /* Restore used register */ ++ lw X11, 0($sp) ++ ++ sw X0, 0(OUT) ++ sw X1, 4(OUT) ++ sw X2, 8(OUT) ++ sw X3, 12(OUT) ++ sw X12, 16(OUT) ++ sw X13, 20(OUT) ++ sw X14, 24(OUT) ++ sw X15, 28(OUT) ++ ++ addiu $sp, STACK_SIZE ++ jr $ra ++.end hchacha_block_arch + .set at +--- /dev/null ++++ b/arch/mips/crypto/chacha-glue.c +@@ -0,0 +1,150 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * MIPS accelerated ChaCha and XChaCha stream ciphers, ++ * including ChaCha20 (RFC7539) ++ * ++ * Copyright (C) 2019 Linaro, Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++asmlinkage void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, ++ unsigned int bytes, int nrounds); ++EXPORT_SYMBOL(chacha_crypt_arch); ++ ++asmlinkage void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds); ++EXPORT_SYMBOL(hchacha_block_arch); ++ ++void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv) ++{ ++ chacha_init_generic(state, key, iv); ++} ++EXPORT_SYMBOL(chacha_init_arch); ++ ++static int chacha_mips_stream_xor(struct skcipher_request *req, ++ const struct chacha_ctx *ctx, const u8 *iv) ++{ ++ struct skcipher_walk walk; ++ u32 state[16]; ++ int err; ++ ++ err = skcipher_walk_virt(&walk, req, false); ++ ++ chacha_init_generic(state, ctx->key, iv); ++ ++ while (walk.nbytes > 0) { ++ unsigned int nbytes = walk.nbytes; ++ ++ if (nbytes < walk.total) ++ nbytes = round_down(nbytes, walk.stride); ++ ++ chacha_crypt(state, walk.dst.virt.addr, walk.src.virt.addr, ++ nbytes, ctx->nrounds); ++ err = skcipher_walk_done(&walk, walk.nbytes - nbytes); ++ } ++ ++ return err; ++} ++ ++static int chacha_mips(struct skcipher_request *req) ++{ ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); ++ struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); ++ ++ return chacha_mips_stream_xor(req, ctx, req->iv); ++} ++ ++static int xchacha_mips(struct skcipher_request *req) ++{ ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); ++ struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); ++ struct chacha_ctx subctx; ++ u32 state[16]; ++ u8 real_iv[16]; ++ ++ chacha_init_generic(state, ctx->key, req->iv); ++ ++ hchacha_block(state, subctx.key, ctx->nrounds); ++ subctx.nrounds = ctx->nrounds; ++ ++ memcpy(&real_iv[0], req->iv + 24, 8); ++ memcpy(&real_iv[8], req->iv + 16, 8); ++ return chacha_mips_stream_xor(req, &subctx, real_iv); ++} ++ ++static struct skcipher_alg algs[] = { ++ { ++ .base.cra_name = "chacha20", ++ .base.cra_driver_name = "chacha20-mips", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = CHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .setkey = chacha20_setkey, ++ .encrypt = chacha_mips, ++ .decrypt = chacha_mips, ++ }, { ++ .base.cra_name = "xchacha20", ++ .base.cra_driver_name = "xchacha20-mips", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = XCHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .setkey = chacha20_setkey, ++ .encrypt = xchacha_mips, ++ .decrypt = xchacha_mips, ++ }, { ++ .base.cra_name = "xchacha12", ++ .base.cra_driver_name = "xchacha12-mips", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = 1, ++ .base.cra_ctxsize = sizeof(struct chacha_ctx), ++ .base.cra_module = THIS_MODULE, ++ ++ .min_keysize = CHACHA_KEY_SIZE, ++ .max_keysize = CHACHA_KEY_SIZE, ++ .ivsize = XCHACHA_IV_SIZE, ++ .chunksize = CHACHA_BLOCK_SIZE, ++ .setkey = chacha12_setkey, ++ .encrypt = xchacha_mips, ++ .decrypt = xchacha_mips, ++ } ++}; ++ ++static int __init chacha_simd_mod_init(void) ++{ ++ return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); ++} ++ ++static void __exit chacha_simd_mod_fini(void) ++{ ++ crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); ++} ++ ++module_init(chacha_simd_mod_init); ++module_exit(chacha_simd_mod_fini); ++ ++MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (MIPS accelerated)"); ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_CRYPTO("chacha20"); ++MODULE_ALIAS_CRYPTO("chacha20-mips"); ++MODULE_ALIAS_CRYPTO("xchacha20"); ++MODULE_ALIAS_CRYPTO("xchacha20-mips"); ++MODULE_ALIAS_CRYPTO("xchacha12"); ++MODULE_ALIAS_CRYPTO("xchacha12-mips"); +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -1423,6 +1423,12 @@ config CRYPTO_CHACHA20_X86_64 + SSSE3, AVX2, and AVX-512VL optimized implementations of the ChaCha20, + XChaCha20, and XChaCha12 stream ciphers. + ++config CRYPTO_CHACHA_MIPS ++ tristate "ChaCha stream cipher algorithms (MIPS 32r2 optimized)" ++ depends on CPU_MIPS32_R2 ++ select CRYPTO_BLKCIPHER ++ select CRYPTO_ARCH_HAVE_LIB_CHACHA ++ + config CRYPTO_SEED + tristate "SEED cipher algorithm" + select CRYPTO_ALGAPI diff --git a/ipq806x/backport-5.4/080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch b/ipq806x/backport-5.4/080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch new file mode 100644 index 0000000..d06f47a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0012-crypto-chacha-unexport-chacha_generic-routines.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:18 +0100 +Subject: [PATCH] crypto: chacha - unexport chacha_generic routines + +commit 22cf705360707ced15f9fe5423938f313c7df536 upstream. + +Now that all users of generic ChaCha code have moved to the core library, +there is no longer a need for the generic ChaCha skcpiher driver to +export parts of it implementation for reuse by other drivers. So drop +the exports, and make the symbols static. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/chacha_generic.c | 26 ++++++++------------------ + include/crypto/internal/chacha.h | 10 ---------- + 2 files changed, 8 insertions(+), 28 deletions(-) + +--- a/crypto/chacha_generic.c ++++ b/crypto/chacha_generic.c +@@ -21,7 +21,7 @@ static int chacha_stream_xor(struct skci + + err = skcipher_walk_virt(&walk, req, false); + +- crypto_chacha_init(state, ctx, iv); ++ chacha_init_generic(state, ctx->key, iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; +@@ -37,36 +37,27 @@ static int chacha_stream_xor(struct skci + return err; + } + +-void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv) +-{ +- chacha_init_generic(state, ctx->key, iv); +-} +-EXPORT_SYMBOL_GPL(crypto_chacha_init); +- +-int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize) ++static int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keysize) + { + return chacha_setkey(tfm, key, keysize, 20); + } +-EXPORT_SYMBOL_GPL(crypto_chacha20_setkey); + +-int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize) ++static int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, ++ unsigned int keysize) + { + return chacha_setkey(tfm, key, keysize, 12); + } +-EXPORT_SYMBOL_GPL(crypto_chacha12_setkey); + +-int crypto_chacha_crypt(struct skcipher_request *req) ++static int crypto_chacha_crypt(struct skcipher_request *req) + { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); + + return chacha_stream_xor(req, ctx, req->iv); + } +-EXPORT_SYMBOL_GPL(crypto_chacha_crypt); + +-int crypto_xchacha_crypt(struct skcipher_request *req) ++static int crypto_xchacha_crypt(struct skcipher_request *req) + { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); +@@ -75,7 +66,7 @@ int crypto_xchacha_crypt(struct skcipher + u8 real_iv[16]; + + /* Compute the subkey given the original key and first 128 nonce bits */ +- crypto_chacha_init(state, ctx, req->iv); ++ chacha_init_generic(state, ctx->key, req->iv); + hchacha_block_generic(state, subctx.key, ctx->nrounds); + subctx.nrounds = ctx->nrounds; + +@@ -86,7 +77,6 @@ int crypto_xchacha_crypt(struct skcipher + /* Generate the stream and XOR it with the data */ + return chacha_stream_xor(req, &subctx, real_iv); + } +-EXPORT_SYMBOL_GPL(crypto_xchacha_crypt); + + static struct skcipher_alg algs[] = { + { +--- a/include/crypto/internal/chacha.h ++++ b/include/crypto/internal/chacha.h +@@ -12,8 +12,6 @@ struct chacha_ctx { + int nrounds; + }; + +-void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv); +- + static inline int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int keysize, int nrounds) + { +@@ -42,12 +40,4 @@ static int inline chacha12_setkey(struct + return chacha_setkey(tfm, key, keysize, 12); + } + +-int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize); +-int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize); +- +-int crypto_chacha_crypt(struct skcipher_request *req); +-int crypto_xchacha_crypt(struct skcipher_request *req); +- + #endif /* _CRYPTO_CHACHA_H */ diff --git a/ipq806x/backport-5.4/080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch b/ipq806x/backport-5.4/080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch new file mode 100644 index 0000000..960300d --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0013-crypto-poly1305-move-core-routines-into-a-separate-l.patch @@ -0,0 +1,649 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:19 +0100 +Subject: [PATCH] crypto: poly1305 - move core routines into a separate library + +commit 48ea8c6ebc96bc0990e12ee1c43d0832c23576bb upstream. + +Move the core Poly1305 routines shared between the generic Poly1305 +shash driver and the Adiantum and NHPoly1305 drivers into a separate +library so that using just this pieces does not pull in the crypto +API pieces of the generic Poly1305 routine. + +In a subsequent patch, we will augment this generic library with +init/update/final routines so that Poyl1305 algorithm can be used +directly without the need for using the crypto API's shash abstraction. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305_glue.c | 2 +- + crypto/Kconfig | 5 +- + crypto/adiantum.c | 5 +- + crypto/nhpoly1305.c | 3 +- + crypto/poly1305_generic.c | 195 ++--------------------------- + include/crypto/internal/poly1305.h | 67 ++++++++++ + include/crypto/poly1305.h | 23 ---- + lib/crypto/Kconfig | 3 + + lib/crypto/Makefile | 3 + + lib/crypto/poly1305.c | 158 +++++++++++++++++++++++ + 10 files changed, 248 insertions(+), 216 deletions(-) + create mode 100644 include/crypto/internal/poly1305.h + create mode 100644 lib/crypto/poly1305.c + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -7,8 +7,8 @@ + + #include + #include ++#include + #include +-#include + #include + #include + #include +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -446,7 +446,7 @@ config CRYPTO_KEYWRAP + config CRYPTO_NHPOLY1305 + tristate + select CRYPTO_HASH +- select CRYPTO_POLY1305 ++ select CRYPTO_LIB_POLY1305_GENERIC + + config CRYPTO_NHPOLY1305_SSE2 + tristate "NHPoly1305 hash function (x86_64 SSE2 implementation)" +@@ -467,7 +467,7 @@ config CRYPTO_NHPOLY1305_AVX2 + config CRYPTO_ADIANTUM + tristate "Adiantum support" + select CRYPTO_CHACHA20 +- select CRYPTO_POLY1305 ++ select CRYPTO_LIB_POLY1305_GENERIC + select CRYPTO_NHPOLY1305 + select CRYPTO_MANAGER + help +@@ -686,6 +686,7 @@ config CRYPTO_GHASH + config CRYPTO_POLY1305 + tristate "Poly1305 authenticator algorithm" + select CRYPTO_HASH ++ select CRYPTO_LIB_POLY1305_GENERIC + help + Poly1305 authenticator algorithm, RFC7539. + +--- a/crypto/adiantum.c ++++ b/crypto/adiantum.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -242,11 +243,11 @@ static void adiantum_hash_header(struct + + BUILD_BUG_ON(sizeof(header) % POLY1305_BLOCK_SIZE != 0); + poly1305_core_blocks(&state, &tctx->header_hash_key, +- &header, sizeof(header) / POLY1305_BLOCK_SIZE); ++ &header, sizeof(header) / POLY1305_BLOCK_SIZE, 1); + + BUILD_BUG_ON(TWEAK_SIZE % POLY1305_BLOCK_SIZE != 0); + poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv, +- TWEAK_SIZE / POLY1305_BLOCK_SIZE); ++ TWEAK_SIZE / POLY1305_BLOCK_SIZE, 1); + + poly1305_core_emit(&state, &rctx->header_hash); + } +--- a/crypto/nhpoly1305.c ++++ b/crypto/nhpoly1305.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -78,7 +79,7 @@ static void process_nh_hash_value(struct + BUILD_BUG_ON(NH_HASH_BYTES % POLY1305_BLOCK_SIZE != 0); + + poly1305_core_blocks(&state->poly_state, &key->poly_key, state->nh_hash, +- NH_HASH_BYTES / POLY1305_BLOCK_SIZE); ++ NH_HASH_BYTES / POLY1305_BLOCK_SIZE, 1); + } + + /* +--- a/crypto/poly1305_generic.c ++++ b/crypto/poly1305_generic.c +@@ -13,27 +13,12 @@ + + #include + #include +-#include ++#include + #include + #include + #include + #include + +-static inline u64 mlt(u64 a, u64 b) +-{ +- return a * b; +-} +- +-static inline u32 sr(u64 v, u_char n) +-{ +- return v >> n; +-} +- +-static inline u32 and(u32 v, u32 mask) +-{ +- return v & mask; +-} +- + int crypto_poly1305_init(struct shash_desc *desc) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); +@@ -47,124 +32,8 @@ int crypto_poly1305_init(struct shash_de + } + EXPORT_SYMBOL_GPL(crypto_poly1305_init); + +-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key) +-{ +- /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ +- key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff; +- key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03; +- key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff; +- key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff; +- key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff; +-} +-EXPORT_SYMBOL_GPL(poly1305_core_setkey); +- +-/* +- * Poly1305 requires a unique key for each tag, which implies that we can't set +- * it on the tfm that gets accessed by multiple users simultaneously. Instead we +- * expect the key as the first 32 bytes in the update() call. +- */ +-unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, +- const u8 *src, unsigned int srclen) +-{ +- if (!dctx->sset) { +- if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_core_setkey(&dctx->r, src); +- src += POLY1305_BLOCK_SIZE; +- srclen -= POLY1305_BLOCK_SIZE; +- dctx->rset = true; +- } +- if (srclen >= POLY1305_BLOCK_SIZE) { +- dctx->s[0] = get_unaligned_le32(src + 0); +- dctx->s[1] = get_unaligned_le32(src + 4); +- dctx->s[2] = get_unaligned_le32(src + 8); +- dctx->s[3] = get_unaligned_le32(src + 12); +- src += POLY1305_BLOCK_SIZE; +- srclen -= POLY1305_BLOCK_SIZE; +- dctx->sset = true; +- } +- } +- return srclen; +-} +-EXPORT_SYMBOL_GPL(crypto_poly1305_setdesckey); +- +-static void poly1305_blocks_internal(struct poly1305_state *state, +- const struct poly1305_key *key, +- const void *src, unsigned int nblocks, +- u32 hibit) +-{ +- u32 r0, r1, r2, r3, r4; +- u32 s1, s2, s3, s4; +- u32 h0, h1, h2, h3, h4; +- u64 d0, d1, d2, d3, d4; +- +- if (!nblocks) +- return; +- +- r0 = key->r[0]; +- r1 = key->r[1]; +- r2 = key->r[2]; +- r3 = key->r[3]; +- r4 = key->r[4]; +- +- s1 = r1 * 5; +- s2 = r2 * 5; +- s3 = r3 * 5; +- s4 = r4 * 5; +- +- h0 = state->h[0]; +- h1 = state->h[1]; +- h2 = state->h[2]; +- h3 = state->h[3]; +- h4 = state->h[4]; +- +- do { +- /* h += m[i] */ +- h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff; +- h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; +- h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff; +- h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff; +- h4 += (get_unaligned_le32(src + 12) >> 8) | hibit; +- +- /* h *= r */ +- d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + +- mlt(h3, s2) + mlt(h4, s1); +- d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + +- mlt(h3, s3) + mlt(h4, s2); +- d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + +- mlt(h3, s4) + mlt(h4, s3); +- d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + +- mlt(h3, r0) + mlt(h4, s4); +- d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + +- mlt(h3, r1) + mlt(h4, r0); +- +- /* (partial) h %= p */ +- d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff); +- d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff); +- d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff); +- d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff); +- h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff); +- h1 += h0 >> 26; h0 = h0 & 0x3ffffff; +- +- src += POLY1305_BLOCK_SIZE; +- } while (--nblocks); +- +- state->h[0] = h0; +- state->h[1] = h1; +- state->h[2] = h2; +- state->h[3] = h3; +- state->h[4] = h4; +-} +- +-void poly1305_core_blocks(struct poly1305_state *state, +- const struct poly1305_key *key, +- const void *src, unsigned int nblocks) +-{ +- poly1305_blocks_internal(state, key, src, nblocks, 1 << 24); +-} +-EXPORT_SYMBOL_GPL(poly1305_core_blocks); +- +-static void poly1305_blocks(struct poly1305_desc_ctx *dctx, +- const u8 *src, unsigned int srclen, u32 hibit) ++static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, ++ unsigned int srclen) + { + unsigned int datalen; + +@@ -174,8 +43,8 @@ static void poly1305_blocks(struct poly1 + srclen = datalen; + } + +- poly1305_blocks_internal(&dctx->h, &dctx->r, +- src, srclen / POLY1305_BLOCK_SIZE, hibit); ++ poly1305_core_blocks(&dctx->h, &dctx->r, src, ++ srclen / POLY1305_BLOCK_SIZE, 1); + } + + int crypto_poly1305_update(struct shash_desc *desc, +@@ -193,13 +62,13 @@ int crypto_poly1305_update(struct shash_ + + if (dctx->buflen == POLY1305_BLOCK_SIZE) { + poly1305_blocks(dctx, dctx->buf, +- POLY1305_BLOCK_SIZE, 1 << 24); ++ POLY1305_BLOCK_SIZE); + dctx->buflen = 0; + } + } + + if (likely(srclen >= POLY1305_BLOCK_SIZE)) { +- poly1305_blocks(dctx, src, srclen, 1 << 24); ++ poly1305_blocks(dctx, src, srclen); + src += srclen - (srclen % POLY1305_BLOCK_SIZE); + srclen %= POLY1305_BLOCK_SIZE; + } +@@ -213,54 +82,6 @@ int crypto_poly1305_update(struct shash_ + } + EXPORT_SYMBOL_GPL(crypto_poly1305_update); + +-void poly1305_core_emit(const struct poly1305_state *state, void *dst) +-{ +- u32 h0, h1, h2, h3, h4; +- u32 g0, g1, g2, g3, g4; +- u32 mask; +- +- /* fully carry h */ +- h0 = state->h[0]; +- h1 = state->h[1]; +- h2 = state->h[2]; +- h3 = state->h[3]; +- h4 = state->h[4]; +- +- h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; +- h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; +- h4 += (h3 >> 26); h3 = h3 & 0x3ffffff; +- h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff; +- h1 += (h0 >> 26); h0 = h0 & 0x3ffffff; +- +- /* compute h + -p */ +- g0 = h0 + 5; +- g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff; +- g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff; +- g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff; +- g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff; +- +- /* select h if h < p, or h + -p if h >= p */ +- mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; +- g0 &= mask; +- g1 &= mask; +- g2 &= mask; +- g3 &= mask; +- g4 &= mask; +- mask = ~mask; +- h0 = (h0 & mask) | g0; +- h1 = (h1 & mask) | g1; +- h2 = (h2 & mask) | g2; +- h3 = (h3 & mask) | g3; +- h4 = (h4 & mask) | g4; +- +- /* h = h % (2^128) */ +- put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0); +- put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4); +- put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8); +- put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12); +-} +-EXPORT_SYMBOL_GPL(poly1305_core_emit); +- + int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); +@@ -274,7 +95,7 @@ int crypto_poly1305_final(struct shash_d + dctx->buf[dctx->buflen++] = 1; + memset(dctx->buf + dctx->buflen, 0, + POLY1305_BLOCK_SIZE - dctx->buflen); +- poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 0); ++ poly1305_core_blocks(&dctx->h, &dctx->r, dctx->buf, 1, 0); + } + + poly1305_core_emit(&dctx->h, digest); +--- /dev/null ++++ b/include/crypto/internal/poly1305.h +@@ -0,0 +1,67 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Common values for the Poly1305 algorithm ++ */ ++ ++#ifndef _CRYPTO_INTERNAL_POLY1305_H ++#define _CRYPTO_INTERNAL_POLY1305_H ++ ++#include ++#include ++#include ++ ++struct shash_desc; ++ ++/* ++ * Poly1305 core functions. These implement the ε-almost-∆-universal hash ++ * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce ++ * ("s key") at the end. They also only support block-aligned inputs. ++ */ ++void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key); ++static inline void poly1305_core_init(struct poly1305_state *state) ++{ ++ *state = (struct poly1305_state){}; ++} ++ ++void poly1305_core_blocks(struct poly1305_state *state, ++ const struct poly1305_key *key, const void *src, ++ unsigned int nblocks, u32 hibit); ++void poly1305_core_emit(const struct poly1305_state *state, void *dst); ++ ++/* Crypto API helper functions for the Poly1305 MAC */ ++int crypto_poly1305_init(struct shash_desc *desc); ++ ++int crypto_poly1305_update(struct shash_desc *desc, ++ const u8 *src, unsigned int srclen); ++int crypto_poly1305_final(struct shash_desc *desc, u8 *dst); ++ ++/* ++ * Poly1305 requires a unique key for each tag, which implies that we can't set ++ * it on the tfm that gets accessed by multiple users simultaneously. Instead we ++ * expect the key as the first 32 bytes in the update() call. ++ */ ++static inline ++unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, ++ const u8 *src, unsigned int srclen) ++{ ++ if (!dctx->sset) { ++ if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { ++ poly1305_core_setkey(&dctx->r, src); ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ dctx->rset = true; ++ } ++ if (srclen >= POLY1305_BLOCK_SIZE) { ++ dctx->s[0] = get_unaligned_le32(src + 0); ++ dctx->s[1] = get_unaligned_le32(src + 4); ++ dctx->s[2] = get_unaligned_le32(src + 8); ++ dctx->s[3] = get_unaligned_le32(src + 12); ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ dctx->sset = true; ++ } ++ } ++ return srclen; ++} ++ ++#endif +--- a/include/crypto/poly1305.h ++++ b/include/crypto/poly1305.h +@@ -38,27 +38,4 @@ struct poly1305_desc_ctx { + bool sset; + }; + +-/* +- * Poly1305 core functions. These implement the ε-almost-∆-universal hash +- * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce +- * ("s key") at the end. They also only support block-aligned inputs. +- */ +-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key); +-static inline void poly1305_core_init(struct poly1305_state *state) +-{ +- memset(state->h, 0, sizeof(state->h)); +-} +-void poly1305_core_blocks(struct poly1305_state *state, +- const struct poly1305_key *key, +- const void *src, unsigned int nblocks); +-void poly1305_core_emit(const struct poly1305_state *state, void *dst); +- +-/* Crypto API helper functions for the Poly1305 MAC */ +-int crypto_poly1305_init(struct shash_desc *desc); +-unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, +- const u8 *src, unsigned int srclen); +-int crypto_poly1305_update(struct shash_desc *desc, +- const u8 *src, unsigned int srclen); +-int crypto_poly1305_final(struct shash_desc *desc, u8 *dst); +- + #endif +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -37,5 +37,8 @@ config CRYPTO_LIB_CHACHA + config CRYPTO_LIB_DES + tristate + ++config CRYPTO_LIB_POLY1305_GENERIC ++ tristate ++ + config CRYPTO_LIB_SHA256 + tristate +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -13,5 +13,8 @@ libarc4-y := arc4.o + obj-$(CONFIG_CRYPTO_LIB_DES) += libdes.o + libdes-y := des.o + ++obj-$(CONFIG_CRYPTO_LIB_POLY1305_GENERIC) += libpoly1305.o ++libpoly1305-y := poly1305.o ++ + obj-$(CONFIG_CRYPTO_LIB_SHA256) += libsha256.o + libsha256-y := sha256.o +--- /dev/null ++++ b/lib/crypto/poly1305.c +@@ -0,0 +1,158 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Poly1305 authenticator algorithm, RFC7539 ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * Based on public domain code by Andrew Moon and Daniel J. Bernstein. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static inline u64 mlt(u64 a, u64 b) ++{ ++ return a * b; ++} ++ ++static inline u32 sr(u64 v, u_char n) ++{ ++ return v >> n; ++} ++ ++static inline u32 and(u32 v, u32 mask) ++{ ++ return v & mask; ++} ++ ++void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key) ++{ ++ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ ++ key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff; ++ key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03; ++ key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff; ++ key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff; ++ key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff; ++} ++EXPORT_SYMBOL_GPL(poly1305_core_setkey); ++ ++void poly1305_core_blocks(struct poly1305_state *state, ++ const struct poly1305_key *key, const void *src, ++ unsigned int nblocks, u32 hibit) ++{ ++ u32 r0, r1, r2, r3, r4; ++ u32 s1, s2, s3, s4; ++ u32 h0, h1, h2, h3, h4; ++ u64 d0, d1, d2, d3, d4; ++ ++ if (!nblocks) ++ return; ++ ++ r0 = key->r[0]; ++ r1 = key->r[1]; ++ r2 = key->r[2]; ++ r3 = key->r[3]; ++ r4 = key->r[4]; ++ ++ s1 = r1 * 5; ++ s2 = r2 * 5; ++ s3 = r3 * 5; ++ s4 = r4 * 5; ++ ++ h0 = state->h[0]; ++ h1 = state->h[1]; ++ h2 = state->h[2]; ++ h3 = state->h[3]; ++ h4 = state->h[4]; ++ ++ do { ++ /* h += m[i] */ ++ h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff; ++ h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; ++ h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff; ++ h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff; ++ h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24); ++ ++ /* h *= r */ ++ d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + ++ mlt(h3, s2) + mlt(h4, s1); ++ d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + ++ mlt(h3, s3) + mlt(h4, s2); ++ d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + ++ mlt(h3, s4) + mlt(h4, s3); ++ d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + ++ mlt(h3, r0) + mlt(h4, s4); ++ d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + ++ mlt(h3, r1) + mlt(h4, r0); ++ ++ /* (partial) h %= p */ ++ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff); ++ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff); ++ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff); ++ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff); ++ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff); ++ h1 += h0 >> 26; h0 = h0 & 0x3ffffff; ++ ++ src += POLY1305_BLOCK_SIZE; ++ } while (--nblocks); ++ ++ state->h[0] = h0; ++ state->h[1] = h1; ++ state->h[2] = h2; ++ state->h[3] = h3; ++ state->h[4] = h4; ++} ++EXPORT_SYMBOL_GPL(poly1305_core_blocks); ++ ++void poly1305_core_emit(const struct poly1305_state *state, void *dst) ++{ ++ u32 h0, h1, h2, h3, h4; ++ u32 g0, g1, g2, g3, g4; ++ u32 mask; ++ ++ /* fully carry h */ ++ h0 = state->h[0]; ++ h1 = state->h[1]; ++ h2 = state->h[2]; ++ h3 = state->h[3]; ++ h4 = state->h[4]; ++ ++ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; ++ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; ++ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff; ++ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff; ++ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff; ++ ++ /* compute h + -p */ ++ g0 = h0 + 5; ++ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff; ++ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff; ++ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff; ++ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff; ++ ++ /* select h if h < p, or h + -p if h >= p */ ++ mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; ++ g0 &= mask; ++ g1 &= mask; ++ g2 &= mask; ++ g3 &= mask; ++ g4 &= mask; ++ mask = ~mask; ++ h0 = (h0 & mask) | g0; ++ h1 = (h1 & mask) | g1; ++ h2 = (h2 & mask) | g2; ++ h3 = (h3 & mask) | g3; ++ h4 = (h4 & mask) | g4; ++ ++ /* h = h % (2^128) */ ++ put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0); ++ put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4); ++ put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8); ++ put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12); ++} ++EXPORT_SYMBOL_GPL(poly1305_core_emit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Martin Willi "); diff --git a/ipq806x/backport-5.4/080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch b/ipq806x/backport-5.4/080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch new file mode 100644 index 0000000..7d23754 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0014-crypto-x86-poly1305-unify-Poly1305-state-struct-with.patch @@ -0,0 +1,251 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:20 +0100 +Subject: [PATCH] crypto: x86/poly1305 - unify Poly1305 state struct with + generic code + +commit ad8f5b88383ea685f2b8df2a12ee3e08089a1287 upstream. + +In preparation of exposing a Poly1305 library interface directly from +the accelerated x86 driver, align the state descriptor of the x86 code +with the one used by the generic driver. This is needed to make the +library interface unified between all implementations. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305_glue.c | 88 ++++++++++-------------------- + crypto/poly1305_generic.c | 6 +- + include/crypto/internal/poly1305.h | 4 +- + include/crypto/poly1305.h | 18 +++--- + 4 files changed, 43 insertions(+), 73 deletions(-) + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -14,40 +14,14 @@ + #include + #include + +-struct poly1305_simd_desc_ctx { +- struct poly1305_desc_ctx base; +- /* derived key u set? */ +- bool uset; +-#ifdef CONFIG_AS_AVX2 +- /* derived keys r^3, r^4 set? */ +- bool wset; +-#endif +- /* derived Poly1305 key r^2 */ +- u32 u[5]; +- /* ... silently appended r^3 and r^4 when using AVX2 */ +-}; +- + asmlinkage void poly1305_block_sse2(u32 *h, const u8 *src, + const u32 *r, unsigned int blocks); + asmlinkage void poly1305_2block_sse2(u32 *h, const u8 *src, const u32 *r, + unsigned int blocks, const u32 *u); +-#ifdef CONFIG_AS_AVX2 + asmlinkage void poly1305_4block_avx2(u32 *h, const u8 *src, const u32 *r, + unsigned int blocks, const u32 *u); +-static bool poly1305_use_avx2; +-#endif + +-static int poly1305_simd_init(struct shash_desc *desc) +-{ +- struct poly1305_simd_desc_ctx *sctx = shash_desc_ctx(desc); +- +- sctx->uset = false; +-#ifdef CONFIG_AS_AVX2 +- sctx->wset = false; +-#endif +- +- return crypto_poly1305_init(desc); +-} ++static bool poly1305_use_avx2 __ro_after_init; + + static void poly1305_simd_mult(u32 *a, const u32 *b) + { +@@ -63,53 +37,49 @@ static void poly1305_simd_mult(u32 *a, c + static unsigned int poly1305_simd_blocks(struct poly1305_desc_ctx *dctx, + const u8 *src, unsigned int srclen) + { +- struct poly1305_simd_desc_ctx *sctx; + unsigned int blocks, datalen; + +- BUILD_BUG_ON(offsetof(struct poly1305_simd_desc_ctx, base)); +- sctx = container_of(dctx, struct poly1305_simd_desc_ctx, base); +- + if (unlikely(!dctx->sset)) { + datalen = crypto_poly1305_setdesckey(dctx, src, srclen); + src += srclen - datalen; + srclen = datalen; + } + +-#ifdef CONFIG_AS_AVX2 +- if (poly1305_use_avx2 && srclen >= POLY1305_BLOCK_SIZE * 4) { +- if (unlikely(!sctx->wset)) { +- if (!sctx->uset) { +- memcpy(sctx->u, dctx->r.r, sizeof(sctx->u)); +- poly1305_simd_mult(sctx->u, dctx->r.r); +- sctx->uset = true; ++ if (IS_ENABLED(CONFIG_AS_AVX2) && ++ poly1305_use_avx2 && ++ srclen >= POLY1305_BLOCK_SIZE * 4) { ++ if (unlikely(dctx->rset < 4)) { ++ if (dctx->rset < 2) { ++ dctx->r[1] = dctx->r[0]; ++ poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r); + } +- memcpy(sctx->u + 5, sctx->u, sizeof(sctx->u)); +- poly1305_simd_mult(sctx->u + 5, dctx->r.r); +- memcpy(sctx->u + 10, sctx->u + 5, sizeof(sctx->u)); +- poly1305_simd_mult(sctx->u + 10, dctx->r.r); +- sctx->wset = true; ++ dctx->r[2] = dctx->r[1]; ++ poly1305_simd_mult(dctx->r[2].r, dctx->r[0].r); ++ dctx->r[3] = dctx->r[2]; ++ poly1305_simd_mult(dctx->r[3].r, dctx->r[0].r); ++ dctx->rset = 4; + } + blocks = srclen / (POLY1305_BLOCK_SIZE * 4); +- poly1305_4block_avx2(dctx->h.h, src, dctx->r.r, blocks, +- sctx->u); ++ poly1305_4block_avx2(dctx->h.h, src, dctx->r[0].r, blocks, ++ dctx->r[1].r); + src += POLY1305_BLOCK_SIZE * 4 * blocks; + srclen -= POLY1305_BLOCK_SIZE * 4 * blocks; + } +-#endif ++ + if (likely(srclen >= POLY1305_BLOCK_SIZE * 2)) { +- if (unlikely(!sctx->uset)) { +- memcpy(sctx->u, dctx->r.r, sizeof(sctx->u)); +- poly1305_simd_mult(sctx->u, dctx->r.r); +- sctx->uset = true; ++ if (unlikely(dctx->rset < 2)) { ++ dctx->r[1] = dctx->r[0]; ++ poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r); ++ dctx->rset = 2; + } + blocks = srclen / (POLY1305_BLOCK_SIZE * 2); +- poly1305_2block_sse2(dctx->h.h, src, dctx->r.r, blocks, +- sctx->u); ++ poly1305_2block_sse2(dctx->h.h, src, dctx->r[0].r, ++ blocks, dctx->r[1].r); + src += POLY1305_BLOCK_SIZE * 2 * blocks; + srclen -= POLY1305_BLOCK_SIZE * 2 * blocks; + } + if (srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_block_sse2(dctx->h.h, src, dctx->r.r, 1); ++ poly1305_block_sse2(dctx->h.h, src, dctx->r[0].r, 1); + srclen -= POLY1305_BLOCK_SIZE; + } + return srclen; +@@ -159,10 +129,10 @@ static int poly1305_simd_update(struct s + + static struct shash_alg alg = { + .digestsize = POLY1305_DIGEST_SIZE, +- .init = poly1305_simd_init, ++ .init = crypto_poly1305_init, + .update = poly1305_simd_update, + .final = crypto_poly1305_final, +- .descsize = sizeof(struct poly1305_simd_desc_ctx), ++ .descsize = sizeof(struct poly1305_desc_ctx), + .base = { + .cra_name = "poly1305", + .cra_driver_name = "poly1305-simd", +@@ -177,14 +147,14 @@ static int __init poly1305_simd_mod_init + if (!boot_cpu_has(X86_FEATURE_XMM2)) + return -ENODEV; + +-#ifdef CONFIG_AS_AVX2 +- poly1305_use_avx2 = boot_cpu_has(X86_FEATURE_AVX) && ++ poly1305_use_avx2 = IS_ENABLED(CONFIG_AS_AVX2) && ++ boot_cpu_has(X86_FEATURE_AVX) && + boot_cpu_has(X86_FEATURE_AVX2) && + cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL); +- alg.descsize = sizeof(struct poly1305_simd_desc_ctx); ++ alg.descsize = sizeof(struct poly1305_desc_ctx) + 5 * sizeof(u32); + if (poly1305_use_avx2) + alg.descsize += 10 * sizeof(u32); +-#endif ++ + return crypto_register_shash(&alg); + } + +--- a/crypto/poly1305_generic.c ++++ b/crypto/poly1305_generic.c +@@ -25,7 +25,7 @@ int crypto_poly1305_init(struct shash_de + + poly1305_core_init(&dctx->h); + dctx->buflen = 0; +- dctx->rset = false; ++ dctx->rset = 0; + dctx->sset = false; + + return 0; +@@ -43,7 +43,7 @@ static void poly1305_blocks(struct poly1 + srclen = datalen; + } + +- poly1305_core_blocks(&dctx->h, &dctx->r, src, ++ poly1305_core_blocks(&dctx->h, dctx->r, src, + srclen / POLY1305_BLOCK_SIZE, 1); + } + +@@ -95,7 +95,7 @@ int crypto_poly1305_final(struct shash_d + dctx->buf[dctx->buflen++] = 1; + memset(dctx->buf + dctx->buflen, 0, + POLY1305_BLOCK_SIZE - dctx->buflen); +- poly1305_core_blocks(&dctx->h, &dctx->r, dctx->buf, 1, 0); ++ poly1305_core_blocks(&dctx->h, dctx->r, dctx->buf, 1, 0); + } + + poly1305_core_emit(&dctx->h, digest); +--- a/include/crypto/internal/poly1305.h ++++ b/include/crypto/internal/poly1305.h +@@ -46,10 +46,10 @@ unsigned int crypto_poly1305_setdesckey( + { + if (!dctx->sset) { + if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_core_setkey(&dctx->r, src); ++ poly1305_core_setkey(dctx->r, src); + src += POLY1305_BLOCK_SIZE; + srclen -= POLY1305_BLOCK_SIZE; +- dctx->rset = true; ++ dctx->rset = 1; + } + if (srclen >= POLY1305_BLOCK_SIZE) { + dctx->s[0] = get_unaligned_le32(src + 0); +--- a/include/crypto/poly1305.h ++++ b/include/crypto/poly1305.h +@@ -22,20 +22,20 @@ struct poly1305_state { + }; + + struct poly1305_desc_ctx { +- /* key */ +- struct poly1305_key r; +- /* finalize key */ +- u32 s[4]; +- /* accumulator */ +- struct poly1305_state h; + /* partial buffer */ + u8 buf[POLY1305_BLOCK_SIZE]; + /* bytes used in partial buffer */ + unsigned int buflen; +- /* r key has been set */ +- bool rset; +- /* s key has been set */ ++ /* how many keys have been set in r[] */ ++ unsigned short rset; ++ /* whether s[] has been set */ + bool sset; ++ /* finalize key */ ++ u32 s[4]; ++ /* accumulator */ ++ struct poly1305_state h; ++ /* key */ ++ struct poly1305_key r[1]; + }; + + #endif diff --git a/ipq806x/backport-5.4/080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch b/ipq806x/backport-5.4/080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch new file mode 100644 index 0000000..bf8e90b --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0015-crypto-poly1305-expose-init-update-final-library-int.patch @@ -0,0 +1,224 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:21 +0100 +Subject: [PATCH] crypto: poly1305 - expose init/update/final library interface + +commit a1d93064094cc5e24d64e35cf093e7191d0c9344 upstream. + +Expose the existing generic Poly1305 code via a init/update/final +library interface so that callers are not required to go through +the crypto API's shash abstraction to access it. At the same time, +make some preparations so that the library implementation can be +superseded by an accelerated arch-specific version in the future. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/poly1305_generic.c | 22 +----------- + include/crypto/poly1305.h | 38 +++++++++++++++++++- + lib/crypto/Kconfig | 26 ++++++++++++++ + lib/crypto/poly1305.c | 74 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 138 insertions(+), 22 deletions(-) + +--- a/crypto/poly1305_generic.c ++++ b/crypto/poly1305_generic.c +@@ -85,31 +85,11 @@ EXPORT_SYMBOL_GPL(crypto_poly1305_update + int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); +- __le32 digest[4]; +- u64 f = 0; + + if (unlikely(!dctx->sset)) + return -ENOKEY; + +- if (unlikely(dctx->buflen)) { +- dctx->buf[dctx->buflen++] = 1; +- memset(dctx->buf + dctx->buflen, 0, +- POLY1305_BLOCK_SIZE - dctx->buflen); +- poly1305_core_blocks(&dctx->h, dctx->r, dctx->buf, 1, 0); +- } +- +- poly1305_core_emit(&dctx->h, digest); +- +- /* mac = (h + s) % (2^128) */ +- f = (f >> 32) + le32_to_cpu(digest[0]) + dctx->s[0]; +- put_unaligned_le32(f, dst + 0); +- f = (f >> 32) + le32_to_cpu(digest[1]) + dctx->s[1]; +- put_unaligned_le32(f, dst + 4); +- f = (f >> 32) + le32_to_cpu(digest[2]) + dctx->s[2]; +- put_unaligned_le32(f, dst + 8); +- f = (f >> 32) + le32_to_cpu(digest[3]) + dctx->s[3]; +- put_unaligned_le32(f, dst + 12); +- ++ poly1305_final_generic(dctx, dst); + return 0; + } + EXPORT_SYMBOL_GPL(crypto_poly1305_final); +--- a/include/crypto/poly1305.h ++++ b/include/crypto/poly1305.h +@@ -35,7 +35,43 @@ struct poly1305_desc_ctx { + /* accumulator */ + struct poly1305_state h; + /* key */ +- struct poly1305_key r[1]; ++ struct poly1305_key r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE]; + }; + ++void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key); ++void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key); ++ ++static inline void poly1305_init(struct poly1305_desc_ctx *desc, const u8 *key) ++{ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305)) ++ poly1305_init_arch(desc, key); ++ else ++ poly1305_init_generic(desc, key); ++} ++ ++void poly1305_update_arch(struct poly1305_desc_ctx *desc, const u8 *src, ++ unsigned int nbytes); ++void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src, ++ unsigned int nbytes); ++ ++static inline void poly1305_update(struct poly1305_desc_ctx *desc, ++ const u8 *src, unsigned int nbytes) ++{ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305)) ++ poly1305_update_arch(desc, src, nbytes); ++ else ++ poly1305_update_generic(desc, src, nbytes); ++} ++ ++void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *digest); ++void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *digest); ++ ++static inline void poly1305_final(struct poly1305_desc_ctx *desc, u8 *digest) ++{ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305)) ++ poly1305_final_arch(desc, digest); ++ else ++ poly1305_final_generic(desc, digest); ++} ++ + #endif +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -37,8 +37,34 @@ config CRYPTO_LIB_CHACHA + config CRYPTO_LIB_DES + tristate + ++config CRYPTO_LIB_POLY1305_RSIZE ++ int ++ default 1 ++ ++config CRYPTO_ARCH_HAVE_LIB_POLY1305 ++ tristate ++ help ++ Declares whether the architecture provides an arch-specific ++ accelerated implementation of the Poly1305 library interface, ++ either builtin or as a module. ++ + config CRYPTO_LIB_POLY1305_GENERIC + tristate ++ help ++ This symbol can be depended upon by arch implementations of the ++ Poly1305 library interface that require the generic code as a ++ fallback, e.g., for SIMD implementations. If no arch specific ++ implementation is enabled, this implementation serves the users ++ of CRYPTO_LIB_POLY1305. ++ ++config CRYPTO_LIB_POLY1305 ++ tristate "Poly1305 library interface" ++ depends on CRYPTO_ARCH_HAVE_LIB_POLY1305 || !CRYPTO_ARCH_HAVE_LIB_POLY1305 ++ select CRYPTO_LIB_POLY1305_GENERIC if CRYPTO_ARCH_HAVE_LIB_POLY1305=n ++ help ++ Enable the Poly1305 library interface. This interface may be fulfilled ++ by either the generic implementation or an arch-specific one, if one ++ is available and enabled. + + config CRYPTO_LIB_SHA256 + tristate +--- a/lib/crypto/poly1305.c ++++ b/lib/crypto/poly1305.c +@@ -154,5 +154,79 @@ void poly1305_core_emit(const struct pol + } + EXPORT_SYMBOL_GPL(poly1305_core_emit); + ++void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key) ++{ ++ poly1305_core_setkey(desc->r, key); ++ desc->s[0] = get_unaligned_le32(key + 16); ++ desc->s[1] = get_unaligned_le32(key + 20); ++ desc->s[2] = get_unaligned_le32(key + 24); ++ desc->s[3] = get_unaligned_le32(key + 28); ++ poly1305_core_init(&desc->h); ++ desc->buflen = 0; ++ desc->sset = true; ++ desc->rset = 1; ++} ++EXPORT_SYMBOL_GPL(poly1305_init_generic); ++ ++void poly1305_update_generic(struct poly1305_desc_ctx *desc, const u8 *src, ++ unsigned int nbytes) ++{ ++ unsigned int bytes; ++ ++ if (unlikely(desc->buflen)) { ++ bytes = min(nbytes, POLY1305_BLOCK_SIZE - desc->buflen); ++ memcpy(desc->buf + desc->buflen, src, bytes); ++ src += bytes; ++ nbytes -= bytes; ++ desc->buflen += bytes; ++ ++ if (desc->buflen == POLY1305_BLOCK_SIZE) { ++ poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 1); ++ desc->buflen = 0; ++ } ++ } ++ ++ if (likely(nbytes >= POLY1305_BLOCK_SIZE)) { ++ poly1305_core_blocks(&desc->h, desc->r, src, ++ nbytes / POLY1305_BLOCK_SIZE, 1); ++ src += nbytes - (nbytes % POLY1305_BLOCK_SIZE); ++ nbytes %= POLY1305_BLOCK_SIZE; ++ } ++ ++ if (unlikely(nbytes)) { ++ desc->buflen = nbytes; ++ memcpy(desc->buf, src, nbytes); ++ } ++} ++EXPORT_SYMBOL_GPL(poly1305_update_generic); ++ ++void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst) ++{ ++ __le32 digest[4]; ++ u64 f = 0; ++ ++ if (unlikely(desc->buflen)) { ++ desc->buf[desc->buflen++] = 1; ++ memset(desc->buf + desc->buflen, 0, ++ POLY1305_BLOCK_SIZE - desc->buflen); ++ poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 0); ++ } ++ ++ poly1305_core_emit(&desc->h, digest); ++ ++ /* mac = (h + s) % (2^128) */ ++ f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0]; ++ put_unaligned_le32(f, dst + 0); ++ f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1]; ++ put_unaligned_le32(f, dst + 4); ++ f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2]; ++ put_unaligned_le32(f, dst + 8); ++ f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3]; ++ put_unaligned_le32(f, dst + 12); ++ ++ *desc = (struct poly1305_desc_ctx){}; ++} ++EXPORT_SYMBOL_GPL(poly1305_final_generic); ++ + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Martin Willi "); diff --git a/ipq806x/backport-5.4/080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch b/ipq806x/backport-5.4/080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch new file mode 100644 index 0000000..8ea63f3 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0016-crypto-x86-poly1305-depend-on-generic-library-not-ge.patch @@ -0,0 +1,217 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:22 +0100 +Subject: [PATCH] crypto: x86/poly1305 - depend on generic library not generic + shash + +commit 1b2c6a5120489d41c8ea3b8dacd0b4586289b158 upstream. + +Remove the dependency on the generic Poly1305 driver. Instead, depend +on the generic library so that we only reuse code without pulling in +the generic skcipher implementation as well. + +While at it, remove the logic that prefers the non-SIMD path for short +inputs - this is no longer necessary after recent FPU handling changes +on x86. + +Since this removes the last remaining user of the routines exported +by the generic shash driver, unexport them and make them static. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305_glue.c | 66 +++++++++++++++++++++++++----- + crypto/Kconfig | 2 +- + crypto/poly1305_generic.c | 11 ++--- + include/crypto/internal/poly1305.h | 9 ---- + 4 files changed, 60 insertions(+), 28 deletions(-) + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -34,6 +34,24 @@ static void poly1305_simd_mult(u32 *a, c + poly1305_block_sse2(a, m, b, 1); + } + ++static unsigned int poly1305_scalar_blocks(struct poly1305_desc_ctx *dctx, ++ const u8 *src, unsigned int srclen) ++{ ++ unsigned int datalen; ++ ++ if (unlikely(!dctx->sset)) { ++ datalen = crypto_poly1305_setdesckey(dctx, src, srclen); ++ src += srclen - datalen; ++ srclen = datalen; ++ } ++ if (srclen >= POLY1305_BLOCK_SIZE) { ++ poly1305_core_blocks(&dctx->h, dctx->r, src, ++ srclen / POLY1305_BLOCK_SIZE, 1); ++ srclen %= POLY1305_BLOCK_SIZE; ++ } ++ return srclen; ++} ++ + static unsigned int poly1305_simd_blocks(struct poly1305_desc_ctx *dctx, + const u8 *src, unsigned int srclen) + { +@@ -91,12 +109,6 @@ static int poly1305_simd_update(struct s + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + unsigned int bytes; + +- /* kernel_fpu_begin/end is costly, use fallback for small updates */ +- if (srclen <= 288 || !crypto_simd_usable()) +- return crypto_poly1305_update(desc, src, srclen); +- +- kernel_fpu_begin(); +- + if (unlikely(dctx->buflen)) { + bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen); + memcpy(dctx->buf + dctx->buflen, src, bytes); +@@ -105,25 +117,57 @@ static int poly1305_simd_update(struct s + dctx->buflen += bytes; + + if (dctx->buflen == POLY1305_BLOCK_SIZE) { +- poly1305_simd_blocks(dctx, dctx->buf, +- POLY1305_BLOCK_SIZE); ++ if (likely(crypto_simd_usable())) { ++ kernel_fpu_begin(); ++ poly1305_simd_blocks(dctx, dctx->buf, ++ POLY1305_BLOCK_SIZE); ++ kernel_fpu_end(); ++ } else { ++ poly1305_scalar_blocks(dctx, dctx->buf, ++ POLY1305_BLOCK_SIZE); ++ } + dctx->buflen = 0; + } + } + + if (likely(srclen >= POLY1305_BLOCK_SIZE)) { +- bytes = poly1305_simd_blocks(dctx, src, srclen); ++ if (likely(crypto_simd_usable())) { ++ kernel_fpu_begin(); ++ bytes = poly1305_simd_blocks(dctx, src, srclen); ++ kernel_fpu_end(); ++ } else { ++ bytes = poly1305_scalar_blocks(dctx, src, srclen); ++ } + src += srclen - bytes; + srclen = bytes; + } + +- kernel_fpu_end(); +- + if (unlikely(srclen)) { + dctx->buflen = srclen; + memcpy(dctx->buf, src, srclen); + } ++} ++ ++static int crypto_poly1305_init(struct shash_desc *desc) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ poly1305_core_init(&dctx->h); ++ dctx->buflen = 0; ++ dctx->rset = 0; ++ dctx->sset = false; ++ ++ return 0; ++} ++ ++static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ if (unlikely(!dctx->sset)) ++ return -ENOKEY; + ++ poly1305_final_generic(dctx, dst); + return 0; + } + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -697,7 +697,7 @@ config CRYPTO_POLY1305 + config CRYPTO_POLY1305_X86_64 + tristate "Poly1305 authenticator algorithm (x86_64/SSE2/AVX2)" + depends on X86 && 64BIT +- select CRYPTO_POLY1305 ++ select CRYPTO_LIB_POLY1305_GENERIC + help + Poly1305 authenticator algorithm, RFC7539. + +--- a/crypto/poly1305_generic.c ++++ b/crypto/poly1305_generic.c +@@ -19,7 +19,7 @@ + #include + #include + +-int crypto_poly1305_init(struct shash_desc *desc) ++static int crypto_poly1305_init(struct shash_desc *desc) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + +@@ -30,7 +30,6 @@ int crypto_poly1305_init(struct shash_de + + return 0; + } +-EXPORT_SYMBOL_GPL(crypto_poly1305_init); + + static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, + unsigned int srclen) +@@ -47,8 +46,8 @@ static void poly1305_blocks(struct poly1 + srclen / POLY1305_BLOCK_SIZE, 1); + } + +-int crypto_poly1305_update(struct shash_desc *desc, +- const u8 *src, unsigned int srclen) ++static int crypto_poly1305_update(struct shash_desc *desc, ++ const u8 *src, unsigned int srclen) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + unsigned int bytes; +@@ -80,9 +79,8 @@ int crypto_poly1305_update(struct shash_ + + return 0; + } +-EXPORT_SYMBOL_GPL(crypto_poly1305_update); + +-int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) ++static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + +@@ -92,7 +90,6 @@ int crypto_poly1305_final(struct shash_d + poly1305_final_generic(dctx, dst); + return 0; + } +-EXPORT_SYMBOL_GPL(crypto_poly1305_final); + + static struct shash_alg poly1305_alg = { + .digestsize = POLY1305_DIGEST_SIZE, +--- a/include/crypto/internal/poly1305.h ++++ b/include/crypto/internal/poly1305.h +@@ -10,8 +10,6 @@ + #include + #include + +-struct shash_desc; +- + /* + * Poly1305 core functions. These implement the ε-almost-∆-universal hash + * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce +@@ -28,13 +26,6 @@ void poly1305_core_blocks(struct poly130 + unsigned int nblocks, u32 hibit); + void poly1305_core_emit(const struct poly1305_state *state, void *dst); + +-/* Crypto API helper functions for the Poly1305 MAC */ +-int crypto_poly1305_init(struct shash_desc *desc); +- +-int crypto_poly1305_update(struct shash_desc *desc, +- const u8 *src, unsigned int srclen); +-int crypto_poly1305_final(struct shash_desc *desc, u8 *dst); +- + /* + * Poly1305 requires a unique key for each tag, which implies that we can't set + * it on the tfm that gets accessed by multiple users simultaneously. Instead we diff --git a/ipq806x/backport-5.4/080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch b/ipq806x/backport-5.4/080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch new file mode 100644 index 0000000..6514987 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0017-crypto-x86-poly1305-expose-existing-driver-as-poly13.patch @@ -0,0 +1,163 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:23 +0100 +Subject: [PATCH] crypto: x86/poly1305 - expose existing driver as poly1305 + library + +commit f0e89bcfbb894e5844cd1bbf6b3cf7c63cb0f5ac upstream. + +Implement the arch init/update/final Poly1305 library routines in the +accelerated SIMD driver for x86 so they are accessible to users of +the Poly1305 library interface as well. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305_glue.c | 57 ++++++++++++++++++++++++--------- + crypto/Kconfig | 1 + + lib/crypto/Kconfig | 1 + + 3 files changed, 43 insertions(+), 16 deletions(-) + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -21,7 +22,8 @@ asmlinkage void poly1305_2block_sse2(u32 + asmlinkage void poly1305_4block_avx2(u32 *h, const u8 *src, const u32 *r, + unsigned int blocks, const u32 *u); + +-static bool poly1305_use_avx2 __ro_after_init; ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_simd); ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx2); + + static void poly1305_simd_mult(u32 *a, const u32 *b) + { +@@ -64,7 +66,7 @@ static unsigned int poly1305_simd_blocks + } + + if (IS_ENABLED(CONFIG_AS_AVX2) && +- poly1305_use_avx2 && ++ static_branch_likely(&poly1305_use_avx2) && + srclen >= POLY1305_BLOCK_SIZE * 4) { + if (unlikely(dctx->rset < 4)) { + if (dctx->rset < 2) { +@@ -103,10 +105,15 @@ static unsigned int poly1305_simd_blocks + return srclen; + } + +-static int poly1305_simd_update(struct shash_desc *desc, +- const u8 *src, unsigned int srclen) ++void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key) ++{ ++ poly1305_init_generic(desc, key); ++} ++EXPORT_SYMBOL(poly1305_init_arch); ++ ++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src, ++ unsigned int srclen) + { +- struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + unsigned int bytes; + + if (unlikely(dctx->buflen)) { +@@ -117,7 +124,8 @@ static int poly1305_simd_update(struct s + dctx->buflen += bytes; + + if (dctx->buflen == POLY1305_BLOCK_SIZE) { +- if (likely(crypto_simd_usable())) { ++ if (static_branch_likely(&poly1305_use_simd) && ++ likely(crypto_simd_usable())) { + kernel_fpu_begin(); + poly1305_simd_blocks(dctx, dctx->buf, + POLY1305_BLOCK_SIZE); +@@ -131,7 +139,8 @@ static int poly1305_simd_update(struct s + } + + if (likely(srclen >= POLY1305_BLOCK_SIZE)) { +- if (likely(crypto_simd_usable())) { ++ if (static_branch_likely(&poly1305_use_simd) && ++ likely(crypto_simd_usable())) { + kernel_fpu_begin(); + bytes = poly1305_simd_blocks(dctx, src, srclen); + kernel_fpu_end(); +@@ -147,6 +156,13 @@ static int poly1305_simd_update(struct s + memcpy(dctx->buf, src, srclen); + } + } ++EXPORT_SYMBOL(poly1305_update_arch); ++ ++void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *digest) ++{ ++ poly1305_final_generic(desc, digest); ++} ++EXPORT_SYMBOL(poly1305_final_arch); + + static int crypto_poly1305_init(struct shash_desc *desc) + { +@@ -171,6 +187,15 @@ static int crypto_poly1305_final(struct + return 0; + } + ++static int poly1305_simd_update(struct shash_desc *desc, ++ const u8 *src, unsigned int srclen) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ poly1305_update_arch(dctx, src, srclen); ++ return 0; ++} ++ + static struct shash_alg alg = { + .digestsize = POLY1305_DIGEST_SIZE, + .init = crypto_poly1305_init, +@@ -189,15 +214,15 @@ static struct shash_alg alg = { + static int __init poly1305_simd_mod_init(void) + { + if (!boot_cpu_has(X86_FEATURE_XMM2)) +- return -ENODEV; ++ return 0; + +- poly1305_use_avx2 = IS_ENABLED(CONFIG_AS_AVX2) && +- boot_cpu_has(X86_FEATURE_AVX) && +- boot_cpu_has(X86_FEATURE_AVX2) && +- cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL); +- alg.descsize = sizeof(struct poly1305_desc_ctx) + 5 * sizeof(u32); +- if (poly1305_use_avx2) +- alg.descsize += 10 * sizeof(u32); ++ static_branch_enable(&poly1305_use_simd); ++ ++ if (IS_ENABLED(CONFIG_AS_AVX2) && ++ boot_cpu_has(X86_FEATURE_AVX) && ++ boot_cpu_has(X86_FEATURE_AVX2) && ++ cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) ++ static_branch_enable(&poly1305_use_avx2); + + return crypto_register_shash(&alg); + } +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -698,6 +698,7 @@ config CRYPTO_POLY1305_X86_64 + tristate "Poly1305 authenticator algorithm (x86_64/SSE2/AVX2)" + depends on X86 && 64BIT + select CRYPTO_LIB_POLY1305_GENERIC ++ select CRYPTO_ARCH_HAVE_LIB_POLY1305 + help + Poly1305 authenticator algorithm, RFC7539. + +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -39,6 +39,7 @@ config CRYPTO_LIB_DES + + config CRYPTO_LIB_POLY1305_RSIZE + int ++ default 4 if X86_64 + default 1 + + config CRYPTO_ARCH_HAVE_LIB_POLY1305 diff --git a/ipq806x/backport-5.4/080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch b/ipq806x/backport-5.4/080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch new file mode 100644 index 0000000..464c656 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0018-crypto-arm64-poly1305-incorporate-OpenSSL-CRYPTOGAMS.patch @@ -0,0 +1,2083 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:24 +0100 +Subject: [PATCH] crypto: arm64/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON + implementation + +commit f569ca16475155013525686d0f73bc379c67e635 upstream. + +This is a straight import of the OpenSSL/CRYPTOGAMS Poly1305 implementation +for NEON authored by Andy Polyakov, and contributed by him to the OpenSSL +project. The file 'poly1305-armv8.pl' is taken straight from this upstream +GitHub repository [0] at commit ec55a08dc0244ce570c4fc7cade330c60798952f, +and already contains all the changes required to build it as part of a +Linux kernel module. + +[0] https://github.com/dot-asm/cryptogams + +Co-developed-by: Andy Polyakov +Signed-off-by: Andy Polyakov +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm64/crypto/Kconfig | 6 + + arch/arm64/crypto/Makefile | 10 +- + arch/arm64/crypto/poly1305-armv8.pl | 913 ++++++++++++++++++++++ + arch/arm64/crypto/poly1305-core.S_shipped | 835 ++++++++++++++++++++ + arch/arm64/crypto/poly1305-glue.c | 237 ++++++ + lib/crypto/Kconfig | 1 + + 6 files changed, 2001 insertions(+), 1 deletion(-) + create mode 100644 arch/arm64/crypto/poly1305-armv8.pl + create mode 100644 arch/arm64/crypto/poly1305-core.S_shipped + create mode 100644 arch/arm64/crypto/poly1305-glue.c + +--- a/arch/arm64/crypto/Kconfig ++++ b/arch/arm64/crypto/Kconfig +@@ -106,6 +106,12 @@ config CRYPTO_CHACHA20_NEON + select CRYPTO_LIB_CHACHA_GENERIC + select CRYPTO_ARCH_HAVE_LIB_CHACHA + ++config CRYPTO_POLY1305_NEON ++ tristate "Poly1305 hash function using scalar or NEON instructions" ++ depends on KERNEL_MODE_NEON ++ select CRYPTO_HASH ++ select CRYPTO_ARCH_HAVE_LIB_POLY1305 ++ + config CRYPTO_NHPOLY1305_NEON + tristate "NHPoly1305 hash function using NEON instructions (for Adiantum)" + depends on KERNEL_MODE_NEON +--- a/arch/arm64/crypto/Makefile ++++ b/arch/arm64/crypto/Makefile +@@ -50,6 +50,10 @@ sha512-arm64-y := sha512-glue.o sha512-c + obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o + chacha-neon-y := chacha-neon-core.o chacha-neon-glue.o + ++obj-$(CONFIG_CRYPTO_POLY1305_NEON) += poly1305-neon.o ++poly1305-neon-y := poly1305-core.o poly1305-glue.o ++AFLAGS_poly1305-core.o += -Dpoly1305_init=poly1305_init_arm64 ++ + obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o + nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o + +@@ -68,11 +72,15 @@ ifdef REGENERATE_ARM64_CRYPTO + quiet_cmd_perlasm = PERLASM $@ + cmd_perlasm = $(PERL) $(<) void $(@) + ++$(src)/poly1305-core.S_shipped: $(src)/poly1305-armv8.pl ++ $(call cmd,perlasm) ++ + $(src)/sha256-core.S_shipped: $(src)/sha512-armv8.pl + $(call cmd,perlasm) + + $(src)/sha512-core.S_shipped: $(src)/sha512-armv8.pl + $(call cmd,perlasm) ++ + endif + +-clean-files += sha256-core.S sha512-core.S ++clean-files += poly1305-core.S sha256-core.S sha512-core.S +--- /dev/null ++++ b/arch/arm64/crypto/poly1305-armv8.pl +@@ -0,0 +1,913 @@ ++#!/usr/bin/env perl ++# SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause ++# ++# ==================================================================== ++# Written by Andy Polyakov, @dot-asm, initially for the OpenSSL ++# project. ++# ==================================================================== ++# ++# This module implements Poly1305 hash for ARMv8. ++# ++# June 2015 ++# ++# Numbers are cycles per processed byte with poly1305_blocks alone. ++# ++# IALU/gcc-4.9 NEON ++# ++# Apple A7 1.86/+5% 0.72 ++# Cortex-A53 2.69/+58% 1.47 ++# Cortex-A57 2.70/+7% 1.14 ++# Denver 1.64/+50% 1.18(*) ++# X-Gene 2.13/+68% 2.27 ++# Mongoose 1.77/+75% 1.12 ++# Kryo 2.70/+55% 1.13 ++# ThunderX2 1.17/+95% 1.36 ++# ++# (*) estimate based on resources availability is less than 1.0, ++# i.e. measured result is worse than expected, presumably binary ++# translator is not almighty; ++ ++$flavour=shift; ++$output=shift; ++ ++if ($flavour && $flavour ne "void") { ++ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; ++ ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or ++ ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or ++ die "can't locate arm-xlate.pl"; ++ ++ open STDOUT,"| \"$^X\" $xlate $flavour $output"; ++} else { ++ open STDOUT,">$output"; ++} ++ ++my ($ctx,$inp,$len,$padbit) = map("x$_",(0..3)); ++my ($mac,$nonce)=($inp,$len); ++ ++my ($h0,$h1,$h2,$r0,$r1,$s1,$t0,$t1,$d0,$d1,$d2) = map("x$_",(4..14)); ++ ++$code.=<<___; ++#ifndef __KERNEL__ ++# include "arm_arch.h" ++.extern OPENSSL_armcap_P ++#endif ++ ++.text ++ ++// forward "declarations" are required for Apple ++.globl poly1305_blocks ++.globl poly1305_emit ++ ++.globl poly1305_init ++.type poly1305_init,%function ++.align 5 ++poly1305_init: ++ cmp $inp,xzr ++ stp xzr,xzr,[$ctx] // zero hash value ++ stp xzr,xzr,[$ctx,#16] // [along with is_base2_26] ++ ++ csel x0,xzr,x0,eq ++ b.eq .Lno_key ++ ++#ifndef __KERNEL__ ++ adrp x17,OPENSSL_armcap_P ++ ldr w17,[x17,#:lo12:OPENSSL_armcap_P] ++#endif ++ ++ ldp $r0,$r1,[$inp] // load key ++ mov $s1,#0xfffffffc0fffffff ++ movk $s1,#0x0fff,lsl#48 ++#ifdef __AARCH64EB__ ++ rev $r0,$r0 // flip bytes ++ rev $r1,$r1 ++#endif ++ and $r0,$r0,$s1 // &=0ffffffc0fffffff ++ and $s1,$s1,#-4 ++ and $r1,$r1,$s1 // &=0ffffffc0ffffffc ++ mov w#$s1,#-1 ++ stp $r0,$r1,[$ctx,#32] // save key value ++ str w#$s1,[$ctx,#48] // impossible key power value ++ ++#ifndef __KERNEL__ ++ tst w17,#ARMV7_NEON ++ ++ adr $d0,.Lpoly1305_blocks ++ adr $r0,.Lpoly1305_blocks_neon ++ adr $d1,.Lpoly1305_emit ++ ++ csel $d0,$d0,$r0,eq ++ ++# ifdef __ILP32__ ++ stp w#$d0,w#$d1,[$len] ++# else ++ stp $d0,$d1,[$len] ++# endif ++#endif ++ mov x0,#1 ++.Lno_key: ++ ret ++.size poly1305_init,.-poly1305_init ++ ++.type poly1305_blocks,%function ++.align 5 ++poly1305_blocks: ++.Lpoly1305_blocks: ++ ands $len,$len,#-16 ++ b.eq .Lno_data ++ ++ ldp $h0,$h1,[$ctx] // load hash value ++ ldp $h2,x17,[$ctx,#16] // [along with is_base2_26] ++ ldp $r0,$r1,[$ctx,#32] // load key value ++ ++#ifdef __AARCH64EB__ ++ lsr $d0,$h0,#32 ++ mov w#$d1,w#$h0 ++ lsr $d2,$h1,#32 ++ mov w15,w#$h1 ++ lsr x16,$h2,#32 ++#else ++ mov w#$d0,w#$h0 ++ lsr $d1,$h0,#32 ++ mov w#$d2,w#$h1 ++ lsr x15,$h1,#32 ++ mov w16,w#$h2 ++#endif ++ ++ add $d0,$d0,$d1,lsl#26 // base 2^26 -> base 2^64 ++ lsr $d1,$d2,#12 ++ adds $d0,$d0,$d2,lsl#52 ++ add $d1,$d1,x15,lsl#14 ++ adc $d1,$d1,xzr ++ lsr $d2,x16,#24 ++ adds $d1,$d1,x16,lsl#40 ++ adc $d2,$d2,xzr ++ ++ cmp x17,#0 // is_base2_26? ++ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2) ++ csel $h0,$h0,$d0,eq // choose between radixes ++ csel $h1,$h1,$d1,eq ++ csel $h2,$h2,$d2,eq ++ ++.Loop: ++ ldp $t0,$t1,[$inp],#16 // load input ++ sub $len,$len,#16 ++#ifdef __AARCH64EB__ ++ rev $t0,$t0 ++ rev $t1,$t1 ++#endif ++ adds $h0,$h0,$t0 // accumulate input ++ adcs $h1,$h1,$t1 ++ ++ mul $d0,$h0,$r0 // h0*r0 ++ adc $h2,$h2,$padbit ++ umulh $d1,$h0,$r0 ++ ++ mul $t0,$h1,$s1 // h1*5*r1 ++ umulh $t1,$h1,$s1 ++ ++ adds $d0,$d0,$t0 ++ mul $t0,$h0,$r1 // h0*r1 ++ adc $d1,$d1,$t1 ++ umulh $d2,$h0,$r1 ++ ++ adds $d1,$d1,$t0 ++ mul $t0,$h1,$r0 // h1*r0 ++ adc $d2,$d2,xzr ++ umulh $t1,$h1,$r0 ++ ++ adds $d1,$d1,$t0 ++ mul $t0,$h2,$s1 // h2*5*r1 ++ adc $d2,$d2,$t1 ++ mul $t1,$h2,$r0 // h2*r0 ++ ++ adds $d1,$d1,$t0 ++ adc $d2,$d2,$t1 ++ ++ and $t0,$d2,#-4 // final reduction ++ and $h2,$d2,#3 ++ add $t0,$t0,$d2,lsr#2 ++ adds $h0,$d0,$t0 ++ adcs $h1,$d1,xzr ++ adc $h2,$h2,xzr ++ ++ cbnz $len,.Loop ++ ++ stp $h0,$h1,[$ctx] // store hash value ++ stp $h2,xzr,[$ctx,#16] // [and clear is_base2_26] ++ ++.Lno_data: ++ ret ++.size poly1305_blocks,.-poly1305_blocks ++ ++.type poly1305_emit,%function ++.align 5 ++poly1305_emit: ++.Lpoly1305_emit: ++ ldp $h0,$h1,[$ctx] // load hash base 2^64 ++ ldp $h2,$r0,[$ctx,#16] // [along with is_base2_26] ++ ldp $t0,$t1,[$nonce] // load nonce ++ ++#ifdef __AARCH64EB__ ++ lsr $d0,$h0,#32 ++ mov w#$d1,w#$h0 ++ lsr $d2,$h1,#32 ++ mov w15,w#$h1 ++ lsr x16,$h2,#32 ++#else ++ mov w#$d0,w#$h0 ++ lsr $d1,$h0,#32 ++ mov w#$d2,w#$h1 ++ lsr x15,$h1,#32 ++ mov w16,w#$h2 ++#endif ++ ++ add $d0,$d0,$d1,lsl#26 // base 2^26 -> base 2^64 ++ lsr $d1,$d2,#12 ++ adds $d0,$d0,$d2,lsl#52 ++ add $d1,$d1,x15,lsl#14 ++ adc $d1,$d1,xzr ++ lsr $d2,x16,#24 ++ adds $d1,$d1,x16,lsl#40 ++ adc $d2,$d2,xzr ++ ++ cmp $r0,#0 // is_base2_26? ++ csel $h0,$h0,$d0,eq // choose between radixes ++ csel $h1,$h1,$d1,eq ++ csel $h2,$h2,$d2,eq ++ ++ adds $d0,$h0,#5 // compare to modulus ++ adcs $d1,$h1,xzr ++ adc $d2,$h2,xzr ++ ++ tst $d2,#-4 // see if it's carried/borrowed ++ ++ csel $h0,$h0,$d0,eq ++ csel $h1,$h1,$d1,eq ++ ++#ifdef __AARCH64EB__ ++ ror $t0,$t0,#32 // flip nonce words ++ ror $t1,$t1,#32 ++#endif ++ adds $h0,$h0,$t0 // accumulate nonce ++ adc $h1,$h1,$t1 ++#ifdef __AARCH64EB__ ++ rev $h0,$h0 // flip output bytes ++ rev $h1,$h1 ++#endif ++ stp $h0,$h1,[$mac] // write result ++ ++ ret ++.size poly1305_emit,.-poly1305_emit ++___ ++my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("v$_.4s",(0..8)); ++my ($IN01_0,$IN01_1,$IN01_2,$IN01_3,$IN01_4) = map("v$_.2s",(9..13)); ++my ($IN23_0,$IN23_1,$IN23_2,$IN23_3,$IN23_4) = map("v$_.2s",(14..18)); ++my ($ACC0,$ACC1,$ACC2,$ACC3,$ACC4) = map("v$_.2d",(19..23)); ++my ($H0,$H1,$H2,$H3,$H4) = map("v$_.2s",(24..28)); ++my ($T0,$T1,$MASK) = map("v$_",(29..31)); ++ ++my ($in2,$zeros)=("x16","x17"); ++my $is_base2_26 = $zeros; # borrow ++ ++$code.=<<___; ++.type poly1305_mult,%function ++.align 5 ++poly1305_mult: ++ mul $d0,$h0,$r0 // h0*r0 ++ umulh $d1,$h0,$r0 ++ ++ mul $t0,$h1,$s1 // h1*5*r1 ++ umulh $t1,$h1,$s1 ++ ++ adds $d0,$d0,$t0 ++ mul $t0,$h0,$r1 // h0*r1 ++ adc $d1,$d1,$t1 ++ umulh $d2,$h0,$r1 ++ ++ adds $d1,$d1,$t0 ++ mul $t0,$h1,$r0 // h1*r0 ++ adc $d2,$d2,xzr ++ umulh $t1,$h1,$r0 ++ ++ adds $d1,$d1,$t0 ++ mul $t0,$h2,$s1 // h2*5*r1 ++ adc $d2,$d2,$t1 ++ mul $t1,$h2,$r0 // h2*r0 ++ ++ adds $d1,$d1,$t0 ++ adc $d2,$d2,$t1 ++ ++ and $t0,$d2,#-4 // final reduction ++ and $h2,$d2,#3 ++ add $t0,$t0,$d2,lsr#2 ++ adds $h0,$d0,$t0 ++ adcs $h1,$d1,xzr ++ adc $h2,$h2,xzr ++ ++ ret ++.size poly1305_mult,.-poly1305_mult ++ ++.type poly1305_splat,%function ++.align 4 ++poly1305_splat: ++ and x12,$h0,#0x03ffffff // base 2^64 -> base 2^26 ++ ubfx x13,$h0,#26,#26 ++ extr x14,$h1,$h0,#52 ++ and x14,x14,#0x03ffffff ++ ubfx x15,$h1,#14,#26 ++ extr x16,$h2,$h1,#40 ++ ++ str w12,[$ctx,#16*0] // r0 ++ add w12,w13,w13,lsl#2 // r1*5 ++ str w13,[$ctx,#16*1] // r1 ++ add w13,w14,w14,lsl#2 // r2*5 ++ str w12,[$ctx,#16*2] // s1 ++ str w14,[$ctx,#16*3] // r2 ++ add w14,w15,w15,lsl#2 // r3*5 ++ str w13,[$ctx,#16*4] // s2 ++ str w15,[$ctx,#16*5] // r3 ++ add w15,w16,w16,lsl#2 // r4*5 ++ str w14,[$ctx,#16*6] // s3 ++ str w16,[$ctx,#16*7] // r4 ++ str w15,[$ctx,#16*8] // s4 ++ ++ ret ++.size poly1305_splat,.-poly1305_splat ++ ++#ifdef __KERNEL__ ++.globl poly1305_blocks_neon ++#endif ++.type poly1305_blocks_neon,%function ++.align 5 ++poly1305_blocks_neon: ++.Lpoly1305_blocks_neon: ++ ldr $is_base2_26,[$ctx,#24] ++ cmp $len,#128 ++ b.lo .Lpoly1305_blocks ++ ++ .inst 0xd503233f // paciasp ++ stp x29,x30,[sp,#-80]! ++ add x29,sp,#0 ++ ++ stp d8,d9,[sp,#16] // meet ABI requirements ++ stp d10,d11,[sp,#32] ++ stp d12,d13,[sp,#48] ++ stp d14,d15,[sp,#64] ++ ++ cbz $is_base2_26,.Lbase2_64_neon ++ ++ ldp w10,w11,[$ctx] // load hash value base 2^26 ++ ldp w12,w13,[$ctx,#8] ++ ldr w14,[$ctx,#16] ++ ++ tst $len,#31 ++ b.eq .Leven_neon ++ ++ ldp $r0,$r1,[$ctx,#32] // load key value ++ ++ add $h0,x10,x11,lsl#26 // base 2^26 -> base 2^64 ++ lsr $h1,x12,#12 ++ adds $h0,$h0,x12,lsl#52 ++ add $h1,$h1,x13,lsl#14 ++ adc $h1,$h1,xzr ++ lsr $h2,x14,#24 ++ adds $h1,$h1,x14,lsl#40 ++ adc $d2,$h2,xzr // can be partially reduced... ++ ++ ldp $d0,$d1,[$inp],#16 // load input ++ sub $len,$len,#16 ++ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2) ++ ++#ifdef __AARCH64EB__ ++ rev $d0,$d0 ++ rev $d1,$d1 ++#endif ++ adds $h0,$h0,$d0 // accumulate input ++ adcs $h1,$h1,$d1 ++ adc $h2,$h2,$padbit ++ ++ bl poly1305_mult ++ ++ and x10,$h0,#0x03ffffff // base 2^64 -> base 2^26 ++ ubfx x11,$h0,#26,#26 ++ extr x12,$h1,$h0,#52 ++ and x12,x12,#0x03ffffff ++ ubfx x13,$h1,#14,#26 ++ extr x14,$h2,$h1,#40 ++ ++ b .Leven_neon ++ ++.align 4 ++.Lbase2_64_neon: ++ ldp $r0,$r1,[$ctx,#32] // load key value ++ ++ ldp $h0,$h1,[$ctx] // load hash value base 2^64 ++ ldr $h2,[$ctx,#16] ++ ++ tst $len,#31 ++ b.eq .Linit_neon ++ ++ ldp $d0,$d1,[$inp],#16 // load input ++ sub $len,$len,#16 ++ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2) ++#ifdef __AARCH64EB__ ++ rev $d0,$d0 ++ rev $d1,$d1 ++#endif ++ adds $h0,$h0,$d0 // accumulate input ++ adcs $h1,$h1,$d1 ++ adc $h2,$h2,$padbit ++ ++ bl poly1305_mult ++ ++.Linit_neon: ++ ldr w17,[$ctx,#48] // first table element ++ and x10,$h0,#0x03ffffff // base 2^64 -> base 2^26 ++ ubfx x11,$h0,#26,#26 ++ extr x12,$h1,$h0,#52 ++ and x12,x12,#0x03ffffff ++ ubfx x13,$h1,#14,#26 ++ extr x14,$h2,$h1,#40 ++ ++ cmp w17,#-1 // is value impossible? ++ b.ne .Leven_neon ++ ++ fmov ${H0},x10 ++ fmov ${H1},x11 ++ fmov ${H2},x12 ++ fmov ${H3},x13 ++ fmov ${H4},x14 ++ ++ ////////////////////////////////// initialize r^n table ++ mov $h0,$r0 // r^1 ++ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2) ++ mov $h1,$r1 ++ mov $h2,xzr ++ add $ctx,$ctx,#48+12 ++ bl poly1305_splat ++ ++ bl poly1305_mult // r^2 ++ sub $ctx,$ctx,#4 ++ bl poly1305_splat ++ ++ bl poly1305_mult // r^3 ++ sub $ctx,$ctx,#4 ++ bl poly1305_splat ++ ++ bl poly1305_mult // r^4 ++ sub $ctx,$ctx,#4 ++ bl poly1305_splat ++ sub $ctx,$ctx,#48 // restore original $ctx ++ b .Ldo_neon ++ ++.align 4 ++.Leven_neon: ++ fmov ${H0},x10 ++ fmov ${H1},x11 ++ fmov ${H2},x12 ++ fmov ${H3},x13 ++ fmov ${H4},x14 ++ ++.Ldo_neon: ++ ldp x8,x12,[$inp,#32] // inp[2:3] ++ subs $len,$len,#64 ++ ldp x9,x13,[$inp,#48] ++ add $in2,$inp,#96 ++ adr $zeros,.Lzeros ++ ++ lsl $padbit,$padbit,#24 ++ add x15,$ctx,#48 ++ ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ and x5,x9,#0x03ffffff ++ ubfx x6,x8,#26,#26 ++ ubfx x7,x9,#26,#26 ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ extr x8,x12,x8,#52 ++ extr x9,x13,x9,#52 ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ fmov $IN23_0,x4 ++ and x8,x8,#0x03ffffff ++ and x9,x9,#0x03ffffff ++ ubfx x10,x12,#14,#26 ++ ubfx x11,x13,#14,#26 ++ add x12,$padbit,x12,lsr#40 ++ add x13,$padbit,x13,lsr#40 ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ fmov $IN23_1,x6 ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ fmov $IN23_2,x8 ++ fmov $IN23_3,x10 ++ fmov $IN23_4,x12 ++ ++ ldp x8,x12,[$inp],#16 // inp[0:1] ++ ldp x9,x13,[$inp],#48 ++ ++ ld1 {$R0,$R1,$S1,$R2},[x15],#64 ++ ld1 {$S2,$R3,$S3,$R4},[x15],#64 ++ ld1 {$S4},[x15] ++ ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ and x5,x9,#0x03ffffff ++ ubfx x6,x8,#26,#26 ++ ubfx x7,x9,#26,#26 ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ extr x8,x12,x8,#52 ++ extr x9,x13,x9,#52 ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ fmov $IN01_0,x4 ++ and x8,x8,#0x03ffffff ++ and x9,x9,#0x03ffffff ++ ubfx x10,x12,#14,#26 ++ ubfx x11,x13,#14,#26 ++ add x12,$padbit,x12,lsr#40 ++ add x13,$padbit,x13,lsr#40 ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ fmov $IN01_1,x6 ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ movi $MASK.2d,#-1 ++ fmov $IN01_2,x8 ++ fmov $IN01_3,x10 ++ fmov $IN01_4,x12 ++ ushr $MASK.2d,$MASK.2d,#38 ++ ++ b.ls .Lskip_loop ++ ++.align 4 ++.Loop_neon: ++ //////////////////////////////////////////////////////////////// ++ // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2 ++ // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r ++ // \___________________/ ++ // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2 ++ // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r ++ // \___________________/ \____________________/ ++ // ++ // Note that we start with inp[2:3]*r^2. This is because it ++ // doesn't depend on reduction in previous iteration. ++ //////////////////////////////////////////////////////////////// ++ // d4 = h0*r4 + h1*r3 + h2*r2 + h3*r1 + h4*r0 ++ // d3 = h0*r3 + h1*r2 + h2*r1 + h3*r0 + h4*5*r4 ++ // d2 = h0*r2 + h1*r1 + h2*r0 + h3*5*r4 + h4*5*r3 ++ // d1 = h0*r1 + h1*r0 + h2*5*r4 + h3*5*r3 + h4*5*r2 ++ // d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1 ++ ++ subs $len,$len,#64 ++ umull $ACC4,$IN23_0,${R4}[2] ++ csel $in2,$zeros,$in2,lo ++ umull $ACC3,$IN23_0,${R3}[2] ++ umull $ACC2,$IN23_0,${R2}[2] ++ ldp x8,x12,[$in2],#16 // inp[2:3] (or zero) ++ umull $ACC1,$IN23_0,${R1}[2] ++ ldp x9,x13,[$in2],#48 ++ umull $ACC0,$IN23_0,${R0}[2] ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ ++ umlal $ACC4,$IN23_1,${R3}[2] ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ umlal $ACC3,$IN23_1,${R2}[2] ++ and x5,x9,#0x03ffffff ++ umlal $ACC2,$IN23_1,${R1}[2] ++ ubfx x6,x8,#26,#26 ++ umlal $ACC1,$IN23_1,${R0}[2] ++ ubfx x7,x9,#26,#26 ++ umlal $ACC0,$IN23_1,${S4}[2] ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ ++ umlal $ACC4,$IN23_2,${R2}[2] ++ extr x8,x12,x8,#52 ++ umlal $ACC3,$IN23_2,${R1}[2] ++ extr x9,x13,x9,#52 ++ umlal $ACC2,$IN23_2,${R0}[2] ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ umlal $ACC1,$IN23_2,${S4}[2] ++ fmov $IN23_0,x4 ++ umlal $ACC0,$IN23_2,${S3}[2] ++ and x8,x8,#0x03ffffff ++ ++ umlal $ACC4,$IN23_3,${R1}[2] ++ and x9,x9,#0x03ffffff ++ umlal $ACC3,$IN23_3,${R0}[2] ++ ubfx x10,x12,#14,#26 ++ umlal $ACC2,$IN23_3,${S4}[2] ++ ubfx x11,x13,#14,#26 ++ umlal $ACC1,$IN23_3,${S3}[2] ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ umlal $ACC0,$IN23_3,${S2}[2] ++ fmov $IN23_1,x6 ++ ++ add $IN01_2,$IN01_2,$H2 ++ add x12,$padbit,x12,lsr#40 ++ umlal $ACC4,$IN23_4,${R0}[2] ++ add x13,$padbit,x13,lsr#40 ++ umlal $ACC3,$IN23_4,${S4}[2] ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ umlal $ACC2,$IN23_4,${S3}[2] ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ umlal $ACC1,$IN23_4,${S2}[2] ++ fmov $IN23_2,x8 ++ umlal $ACC0,$IN23_4,${S1}[2] ++ fmov $IN23_3,x10 ++ ++ //////////////////////////////////////////////////////////////// ++ // (hash+inp[0:1])*r^4 and accumulate ++ ++ add $IN01_0,$IN01_0,$H0 ++ fmov $IN23_4,x12 ++ umlal $ACC3,$IN01_2,${R1}[0] ++ ldp x8,x12,[$inp],#16 // inp[0:1] ++ umlal $ACC0,$IN01_2,${S3}[0] ++ ldp x9,x13,[$inp],#48 ++ umlal $ACC4,$IN01_2,${R2}[0] ++ umlal $ACC1,$IN01_2,${S4}[0] ++ umlal $ACC2,$IN01_2,${R0}[0] ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ ++ add $IN01_1,$IN01_1,$H1 ++ umlal $ACC3,$IN01_0,${R3}[0] ++ umlal $ACC4,$IN01_0,${R4}[0] ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ umlal $ACC2,$IN01_0,${R2}[0] ++ and x5,x9,#0x03ffffff ++ umlal $ACC0,$IN01_0,${R0}[0] ++ ubfx x6,x8,#26,#26 ++ umlal $ACC1,$IN01_0,${R1}[0] ++ ubfx x7,x9,#26,#26 ++ ++ add $IN01_3,$IN01_3,$H3 ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ umlal $ACC3,$IN01_1,${R2}[0] ++ extr x8,x12,x8,#52 ++ umlal $ACC4,$IN01_1,${R3}[0] ++ extr x9,x13,x9,#52 ++ umlal $ACC0,$IN01_1,${S4}[0] ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ umlal $ACC2,$IN01_1,${R1}[0] ++ fmov $IN01_0,x4 ++ umlal $ACC1,$IN01_1,${R0}[0] ++ and x8,x8,#0x03ffffff ++ ++ add $IN01_4,$IN01_4,$H4 ++ and x9,x9,#0x03ffffff ++ umlal $ACC3,$IN01_3,${R0}[0] ++ ubfx x10,x12,#14,#26 ++ umlal $ACC0,$IN01_3,${S2}[0] ++ ubfx x11,x13,#14,#26 ++ umlal $ACC4,$IN01_3,${R1}[0] ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ umlal $ACC1,$IN01_3,${S3}[0] ++ fmov $IN01_1,x6 ++ umlal $ACC2,$IN01_3,${S4}[0] ++ add x12,$padbit,x12,lsr#40 ++ ++ umlal $ACC3,$IN01_4,${S4}[0] ++ add x13,$padbit,x13,lsr#40 ++ umlal $ACC0,$IN01_4,${S1}[0] ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ umlal $ACC4,$IN01_4,${R0}[0] ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ umlal $ACC1,$IN01_4,${S2}[0] ++ fmov $IN01_2,x8 ++ umlal $ACC2,$IN01_4,${S3}[0] ++ fmov $IN01_3,x10 ++ fmov $IN01_4,x12 ++ ++ ///////////////////////////////////////////////////////////////// ++ // lazy reduction as discussed in "NEON crypto" by D.J. Bernstein ++ // and P. Schwabe ++ // ++ // [see discussion in poly1305-armv4 module] ++ ++ ushr $T0.2d,$ACC3,#26 ++ xtn $H3,$ACC3 ++ ushr $T1.2d,$ACC0,#26 ++ and $ACC0,$ACC0,$MASK.2d ++ add $ACC4,$ACC4,$T0.2d // h3 -> h4 ++ bic $H3,#0xfc,lsl#24 // &=0x03ffffff ++ add $ACC1,$ACC1,$T1.2d // h0 -> h1 ++ ++ ushr $T0.2d,$ACC4,#26 ++ xtn $H4,$ACC4 ++ ushr $T1.2d,$ACC1,#26 ++ xtn $H1,$ACC1 ++ bic $H4,#0xfc,lsl#24 ++ add $ACC2,$ACC2,$T1.2d // h1 -> h2 ++ ++ add $ACC0,$ACC0,$T0.2d ++ shl $T0.2d,$T0.2d,#2 ++ shrn $T1.2s,$ACC2,#26 ++ xtn $H2,$ACC2 ++ add $ACC0,$ACC0,$T0.2d // h4 -> h0 ++ bic $H1,#0xfc,lsl#24 ++ add $H3,$H3,$T1.2s // h2 -> h3 ++ bic $H2,#0xfc,lsl#24 ++ ++ shrn $T0.2s,$ACC0,#26 ++ xtn $H0,$ACC0 ++ ushr $T1.2s,$H3,#26 ++ bic $H3,#0xfc,lsl#24 ++ bic $H0,#0xfc,lsl#24 ++ add $H1,$H1,$T0.2s // h0 -> h1 ++ add $H4,$H4,$T1.2s // h3 -> h4 ++ ++ b.hi .Loop_neon ++ ++.Lskip_loop: ++ dup $IN23_2,${IN23_2}[0] ++ add $IN01_2,$IN01_2,$H2 ++ ++ //////////////////////////////////////////////////////////////// ++ // multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1 ++ ++ adds $len,$len,#32 ++ b.ne .Long_tail ++ ++ dup $IN23_2,${IN01_2}[0] ++ add $IN23_0,$IN01_0,$H0 ++ add $IN23_3,$IN01_3,$H3 ++ add $IN23_1,$IN01_1,$H1 ++ add $IN23_4,$IN01_4,$H4 ++ ++.Long_tail: ++ dup $IN23_0,${IN23_0}[0] ++ umull2 $ACC0,$IN23_2,${S3} ++ umull2 $ACC3,$IN23_2,${R1} ++ umull2 $ACC4,$IN23_2,${R2} ++ umull2 $ACC2,$IN23_2,${R0} ++ umull2 $ACC1,$IN23_2,${S4} ++ ++ dup $IN23_1,${IN23_1}[0] ++ umlal2 $ACC0,$IN23_0,${R0} ++ umlal2 $ACC2,$IN23_0,${R2} ++ umlal2 $ACC3,$IN23_0,${R3} ++ umlal2 $ACC4,$IN23_0,${R4} ++ umlal2 $ACC1,$IN23_0,${R1} ++ ++ dup $IN23_3,${IN23_3}[0] ++ umlal2 $ACC0,$IN23_1,${S4} ++ umlal2 $ACC3,$IN23_1,${R2} ++ umlal2 $ACC2,$IN23_1,${R1} ++ umlal2 $ACC4,$IN23_1,${R3} ++ umlal2 $ACC1,$IN23_1,${R0} ++ ++ dup $IN23_4,${IN23_4}[0] ++ umlal2 $ACC3,$IN23_3,${R0} ++ umlal2 $ACC4,$IN23_3,${R1} ++ umlal2 $ACC0,$IN23_3,${S2} ++ umlal2 $ACC1,$IN23_3,${S3} ++ umlal2 $ACC2,$IN23_3,${S4} ++ ++ umlal2 $ACC3,$IN23_4,${S4} ++ umlal2 $ACC0,$IN23_4,${S1} ++ umlal2 $ACC4,$IN23_4,${R0} ++ umlal2 $ACC1,$IN23_4,${S2} ++ umlal2 $ACC2,$IN23_4,${S3} ++ ++ b.eq .Lshort_tail ++ ++ //////////////////////////////////////////////////////////////// ++ // (hash+inp[0:1])*r^4:r^3 and accumulate ++ ++ add $IN01_0,$IN01_0,$H0 ++ umlal $ACC3,$IN01_2,${R1} ++ umlal $ACC0,$IN01_2,${S3} ++ umlal $ACC4,$IN01_2,${R2} ++ umlal $ACC1,$IN01_2,${S4} ++ umlal $ACC2,$IN01_2,${R0} ++ ++ add $IN01_1,$IN01_1,$H1 ++ umlal $ACC3,$IN01_0,${R3} ++ umlal $ACC0,$IN01_0,${R0} ++ umlal $ACC4,$IN01_0,${R4} ++ umlal $ACC1,$IN01_0,${R1} ++ umlal $ACC2,$IN01_0,${R2} ++ ++ add $IN01_3,$IN01_3,$H3 ++ umlal $ACC3,$IN01_1,${R2} ++ umlal $ACC0,$IN01_1,${S4} ++ umlal $ACC4,$IN01_1,${R3} ++ umlal $ACC1,$IN01_1,${R0} ++ umlal $ACC2,$IN01_1,${R1} ++ ++ add $IN01_4,$IN01_4,$H4 ++ umlal $ACC3,$IN01_3,${R0} ++ umlal $ACC0,$IN01_3,${S2} ++ umlal $ACC4,$IN01_3,${R1} ++ umlal $ACC1,$IN01_3,${S3} ++ umlal $ACC2,$IN01_3,${S4} ++ ++ umlal $ACC3,$IN01_4,${S4} ++ umlal $ACC0,$IN01_4,${S1} ++ umlal $ACC4,$IN01_4,${R0} ++ umlal $ACC1,$IN01_4,${S2} ++ umlal $ACC2,$IN01_4,${S3} ++ ++.Lshort_tail: ++ //////////////////////////////////////////////////////////////// ++ // horizontal add ++ ++ addp $ACC3,$ACC3,$ACC3 ++ ldp d8,d9,[sp,#16] // meet ABI requirements ++ addp $ACC0,$ACC0,$ACC0 ++ ldp d10,d11,[sp,#32] ++ addp $ACC4,$ACC4,$ACC4 ++ ldp d12,d13,[sp,#48] ++ addp $ACC1,$ACC1,$ACC1 ++ ldp d14,d15,[sp,#64] ++ addp $ACC2,$ACC2,$ACC2 ++ ldr x30,[sp,#8] ++ .inst 0xd50323bf // autiasp ++ ++ //////////////////////////////////////////////////////////////// ++ // lazy reduction, but without narrowing ++ ++ ushr $T0.2d,$ACC3,#26 ++ and $ACC3,$ACC3,$MASK.2d ++ ushr $T1.2d,$ACC0,#26 ++ and $ACC0,$ACC0,$MASK.2d ++ ++ add $ACC4,$ACC4,$T0.2d // h3 -> h4 ++ add $ACC1,$ACC1,$T1.2d // h0 -> h1 ++ ++ ushr $T0.2d,$ACC4,#26 ++ and $ACC4,$ACC4,$MASK.2d ++ ushr $T1.2d,$ACC1,#26 ++ and $ACC1,$ACC1,$MASK.2d ++ add $ACC2,$ACC2,$T1.2d // h1 -> h2 ++ ++ add $ACC0,$ACC0,$T0.2d ++ shl $T0.2d,$T0.2d,#2 ++ ushr $T1.2d,$ACC2,#26 ++ and $ACC2,$ACC2,$MASK.2d ++ add $ACC0,$ACC0,$T0.2d // h4 -> h0 ++ add $ACC3,$ACC3,$T1.2d // h2 -> h3 ++ ++ ushr $T0.2d,$ACC0,#26 ++ and $ACC0,$ACC0,$MASK.2d ++ ushr $T1.2d,$ACC3,#26 ++ and $ACC3,$ACC3,$MASK.2d ++ add $ACC1,$ACC1,$T0.2d // h0 -> h1 ++ add $ACC4,$ACC4,$T1.2d // h3 -> h4 ++ ++ //////////////////////////////////////////////////////////////// ++ // write the result, can be partially reduced ++ ++ st4 {$ACC0,$ACC1,$ACC2,$ACC3}[0],[$ctx],#16 ++ mov x4,#1 ++ st1 {$ACC4}[0],[$ctx] ++ str x4,[$ctx,#8] // set is_base2_26 ++ ++ ldr x29,[sp],#80 ++ ret ++.size poly1305_blocks_neon,.-poly1305_blocks_neon ++ ++.align 5 ++.Lzeros: ++.long 0,0,0,0,0,0,0,0 ++.asciz "Poly1305 for ARMv8, CRYPTOGAMS by \@dot-asm" ++.align 2 ++#if !defined(__KERNEL__) && !defined(_WIN64) ++.comm OPENSSL_armcap_P,4,4 ++.hidden OPENSSL_armcap_P ++#endif ++___ ++ ++foreach (split("\n",$code)) { ++ s/\b(shrn\s+v[0-9]+)\.[24]d/$1.2s/ or ++ s/\b(fmov\s+)v([0-9]+)[^,]*,\s*x([0-9]+)/$1d$2,x$3/ or ++ (m/\bdup\b/ and (s/\.[24]s/.2d/g or 1)) or ++ (m/\b(eor|and)/ and (s/\.[248][sdh]/.16b/g or 1)) or ++ (m/\bum(ul|la)l\b/ and (s/\.4s/.2s/g or 1)) or ++ (m/\bum(ul|la)l2\b/ and (s/\.2s/.4s/g or 1)) or ++ (m/\bst[1-4]\s+{[^}]+}\[/ and (s/\.[24]d/.s/g or 1)); ++ ++ s/\.[124]([sd])\[/.$1\[/; ++ s/w#x([0-9]+)/w$1/g; ++ ++ print $_,"\n"; ++} ++close STDOUT; +--- /dev/null ++++ b/arch/arm64/crypto/poly1305-core.S_shipped +@@ -0,0 +1,835 @@ ++#ifndef __KERNEL__ ++# include "arm_arch.h" ++.extern OPENSSL_armcap_P ++#endif ++ ++.text ++ ++// forward "declarations" are required for Apple ++.globl poly1305_blocks ++.globl poly1305_emit ++ ++.globl poly1305_init ++.type poly1305_init,%function ++.align 5 ++poly1305_init: ++ cmp x1,xzr ++ stp xzr,xzr,[x0] // zero hash value ++ stp xzr,xzr,[x0,#16] // [along with is_base2_26] ++ ++ csel x0,xzr,x0,eq ++ b.eq .Lno_key ++ ++#ifndef __KERNEL__ ++ adrp x17,OPENSSL_armcap_P ++ ldr w17,[x17,#:lo12:OPENSSL_armcap_P] ++#endif ++ ++ ldp x7,x8,[x1] // load key ++ mov x9,#0xfffffffc0fffffff ++ movk x9,#0x0fff,lsl#48 ++#ifdef __AARCH64EB__ ++ rev x7,x7 // flip bytes ++ rev x8,x8 ++#endif ++ and x7,x7,x9 // &=0ffffffc0fffffff ++ and x9,x9,#-4 ++ and x8,x8,x9 // &=0ffffffc0ffffffc ++ mov w9,#-1 ++ stp x7,x8,[x0,#32] // save key value ++ str w9,[x0,#48] // impossible key power value ++ ++#ifndef __KERNEL__ ++ tst w17,#ARMV7_NEON ++ ++ adr x12,.Lpoly1305_blocks ++ adr x7,.Lpoly1305_blocks_neon ++ adr x13,.Lpoly1305_emit ++ ++ csel x12,x12,x7,eq ++ ++# ifdef __ILP32__ ++ stp w12,w13,[x2] ++# else ++ stp x12,x13,[x2] ++# endif ++#endif ++ mov x0,#1 ++.Lno_key: ++ ret ++.size poly1305_init,.-poly1305_init ++ ++.type poly1305_blocks,%function ++.align 5 ++poly1305_blocks: ++.Lpoly1305_blocks: ++ ands x2,x2,#-16 ++ b.eq .Lno_data ++ ++ ldp x4,x5,[x0] // load hash value ++ ldp x6,x17,[x0,#16] // [along with is_base2_26] ++ ldp x7,x8,[x0,#32] // load key value ++ ++#ifdef __AARCH64EB__ ++ lsr x12,x4,#32 ++ mov w13,w4 ++ lsr x14,x5,#32 ++ mov w15,w5 ++ lsr x16,x6,#32 ++#else ++ mov w12,w4 ++ lsr x13,x4,#32 ++ mov w14,w5 ++ lsr x15,x5,#32 ++ mov w16,w6 ++#endif ++ ++ add x12,x12,x13,lsl#26 // base 2^26 -> base 2^64 ++ lsr x13,x14,#12 ++ adds x12,x12,x14,lsl#52 ++ add x13,x13,x15,lsl#14 ++ adc x13,x13,xzr ++ lsr x14,x16,#24 ++ adds x13,x13,x16,lsl#40 ++ adc x14,x14,xzr ++ ++ cmp x17,#0 // is_base2_26? ++ add x9,x8,x8,lsr#2 // s1 = r1 + (r1 >> 2) ++ csel x4,x4,x12,eq // choose between radixes ++ csel x5,x5,x13,eq ++ csel x6,x6,x14,eq ++ ++.Loop: ++ ldp x10,x11,[x1],#16 // load input ++ sub x2,x2,#16 ++#ifdef __AARCH64EB__ ++ rev x10,x10 ++ rev x11,x11 ++#endif ++ adds x4,x4,x10 // accumulate input ++ adcs x5,x5,x11 ++ ++ mul x12,x4,x7 // h0*r0 ++ adc x6,x6,x3 ++ umulh x13,x4,x7 ++ ++ mul x10,x5,x9 // h1*5*r1 ++ umulh x11,x5,x9 ++ ++ adds x12,x12,x10 ++ mul x10,x4,x8 // h0*r1 ++ adc x13,x13,x11 ++ umulh x14,x4,x8 ++ ++ adds x13,x13,x10 ++ mul x10,x5,x7 // h1*r0 ++ adc x14,x14,xzr ++ umulh x11,x5,x7 ++ ++ adds x13,x13,x10 ++ mul x10,x6,x9 // h2*5*r1 ++ adc x14,x14,x11 ++ mul x11,x6,x7 // h2*r0 ++ ++ adds x13,x13,x10 ++ adc x14,x14,x11 ++ ++ and x10,x14,#-4 // final reduction ++ and x6,x14,#3 ++ add x10,x10,x14,lsr#2 ++ adds x4,x12,x10 ++ adcs x5,x13,xzr ++ adc x6,x6,xzr ++ ++ cbnz x2,.Loop ++ ++ stp x4,x5,[x0] // store hash value ++ stp x6,xzr,[x0,#16] // [and clear is_base2_26] ++ ++.Lno_data: ++ ret ++.size poly1305_blocks,.-poly1305_blocks ++ ++.type poly1305_emit,%function ++.align 5 ++poly1305_emit: ++.Lpoly1305_emit: ++ ldp x4,x5,[x0] // load hash base 2^64 ++ ldp x6,x7,[x0,#16] // [along with is_base2_26] ++ ldp x10,x11,[x2] // load nonce ++ ++#ifdef __AARCH64EB__ ++ lsr x12,x4,#32 ++ mov w13,w4 ++ lsr x14,x5,#32 ++ mov w15,w5 ++ lsr x16,x6,#32 ++#else ++ mov w12,w4 ++ lsr x13,x4,#32 ++ mov w14,w5 ++ lsr x15,x5,#32 ++ mov w16,w6 ++#endif ++ ++ add x12,x12,x13,lsl#26 // base 2^26 -> base 2^64 ++ lsr x13,x14,#12 ++ adds x12,x12,x14,lsl#52 ++ add x13,x13,x15,lsl#14 ++ adc x13,x13,xzr ++ lsr x14,x16,#24 ++ adds x13,x13,x16,lsl#40 ++ adc x14,x14,xzr ++ ++ cmp x7,#0 // is_base2_26? ++ csel x4,x4,x12,eq // choose between radixes ++ csel x5,x5,x13,eq ++ csel x6,x6,x14,eq ++ ++ adds x12,x4,#5 // compare to modulus ++ adcs x13,x5,xzr ++ adc x14,x6,xzr ++ ++ tst x14,#-4 // see if it's carried/borrowed ++ ++ csel x4,x4,x12,eq ++ csel x5,x5,x13,eq ++ ++#ifdef __AARCH64EB__ ++ ror x10,x10,#32 // flip nonce words ++ ror x11,x11,#32 ++#endif ++ adds x4,x4,x10 // accumulate nonce ++ adc x5,x5,x11 ++#ifdef __AARCH64EB__ ++ rev x4,x4 // flip output bytes ++ rev x5,x5 ++#endif ++ stp x4,x5,[x1] // write result ++ ++ ret ++.size poly1305_emit,.-poly1305_emit ++.type poly1305_mult,%function ++.align 5 ++poly1305_mult: ++ mul x12,x4,x7 // h0*r0 ++ umulh x13,x4,x7 ++ ++ mul x10,x5,x9 // h1*5*r1 ++ umulh x11,x5,x9 ++ ++ adds x12,x12,x10 ++ mul x10,x4,x8 // h0*r1 ++ adc x13,x13,x11 ++ umulh x14,x4,x8 ++ ++ adds x13,x13,x10 ++ mul x10,x5,x7 // h1*r0 ++ adc x14,x14,xzr ++ umulh x11,x5,x7 ++ ++ adds x13,x13,x10 ++ mul x10,x6,x9 // h2*5*r1 ++ adc x14,x14,x11 ++ mul x11,x6,x7 // h2*r0 ++ ++ adds x13,x13,x10 ++ adc x14,x14,x11 ++ ++ and x10,x14,#-4 // final reduction ++ and x6,x14,#3 ++ add x10,x10,x14,lsr#2 ++ adds x4,x12,x10 ++ adcs x5,x13,xzr ++ adc x6,x6,xzr ++ ++ ret ++.size poly1305_mult,.-poly1305_mult ++ ++.type poly1305_splat,%function ++.align 4 ++poly1305_splat: ++ and x12,x4,#0x03ffffff // base 2^64 -> base 2^26 ++ ubfx x13,x4,#26,#26 ++ extr x14,x5,x4,#52 ++ and x14,x14,#0x03ffffff ++ ubfx x15,x5,#14,#26 ++ extr x16,x6,x5,#40 ++ ++ str w12,[x0,#16*0] // r0 ++ add w12,w13,w13,lsl#2 // r1*5 ++ str w13,[x0,#16*1] // r1 ++ add w13,w14,w14,lsl#2 // r2*5 ++ str w12,[x0,#16*2] // s1 ++ str w14,[x0,#16*3] // r2 ++ add w14,w15,w15,lsl#2 // r3*5 ++ str w13,[x0,#16*4] // s2 ++ str w15,[x0,#16*5] // r3 ++ add w15,w16,w16,lsl#2 // r4*5 ++ str w14,[x0,#16*6] // s3 ++ str w16,[x0,#16*7] // r4 ++ str w15,[x0,#16*8] // s4 ++ ++ ret ++.size poly1305_splat,.-poly1305_splat ++ ++#ifdef __KERNEL__ ++.globl poly1305_blocks_neon ++#endif ++.type poly1305_blocks_neon,%function ++.align 5 ++poly1305_blocks_neon: ++.Lpoly1305_blocks_neon: ++ ldr x17,[x0,#24] ++ cmp x2,#128 ++ b.lo .Lpoly1305_blocks ++ ++ .inst 0xd503233f // paciasp ++ stp x29,x30,[sp,#-80]! ++ add x29,sp,#0 ++ ++ stp d8,d9,[sp,#16] // meet ABI requirements ++ stp d10,d11,[sp,#32] ++ stp d12,d13,[sp,#48] ++ stp d14,d15,[sp,#64] ++ ++ cbz x17,.Lbase2_64_neon ++ ++ ldp w10,w11,[x0] // load hash value base 2^26 ++ ldp w12,w13,[x0,#8] ++ ldr w14,[x0,#16] ++ ++ tst x2,#31 ++ b.eq .Leven_neon ++ ++ ldp x7,x8,[x0,#32] // load key value ++ ++ add x4,x10,x11,lsl#26 // base 2^26 -> base 2^64 ++ lsr x5,x12,#12 ++ adds x4,x4,x12,lsl#52 ++ add x5,x5,x13,lsl#14 ++ adc x5,x5,xzr ++ lsr x6,x14,#24 ++ adds x5,x5,x14,lsl#40 ++ adc x14,x6,xzr // can be partially reduced... ++ ++ ldp x12,x13,[x1],#16 // load input ++ sub x2,x2,#16 ++ add x9,x8,x8,lsr#2 // s1 = r1 + (r1 >> 2) ++ ++#ifdef __AARCH64EB__ ++ rev x12,x12 ++ rev x13,x13 ++#endif ++ adds x4,x4,x12 // accumulate input ++ adcs x5,x5,x13 ++ adc x6,x6,x3 ++ ++ bl poly1305_mult ++ ++ and x10,x4,#0x03ffffff // base 2^64 -> base 2^26 ++ ubfx x11,x4,#26,#26 ++ extr x12,x5,x4,#52 ++ and x12,x12,#0x03ffffff ++ ubfx x13,x5,#14,#26 ++ extr x14,x6,x5,#40 ++ ++ b .Leven_neon ++ ++.align 4 ++.Lbase2_64_neon: ++ ldp x7,x8,[x0,#32] // load key value ++ ++ ldp x4,x5,[x0] // load hash value base 2^64 ++ ldr x6,[x0,#16] ++ ++ tst x2,#31 ++ b.eq .Linit_neon ++ ++ ldp x12,x13,[x1],#16 // load input ++ sub x2,x2,#16 ++ add x9,x8,x8,lsr#2 // s1 = r1 + (r1 >> 2) ++#ifdef __AARCH64EB__ ++ rev x12,x12 ++ rev x13,x13 ++#endif ++ adds x4,x4,x12 // accumulate input ++ adcs x5,x5,x13 ++ adc x6,x6,x3 ++ ++ bl poly1305_mult ++ ++.Linit_neon: ++ ldr w17,[x0,#48] // first table element ++ and x10,x4,#0x03ffffff // base 2^64 -> base 2^26 ++ ubfx x11,x4,#26,#26 ++ extr x12,x5,x4,#52 ++ and x12,x12,#0x03ffffff ++ ubfx x13,x5,#14,#26 ++ extr x14,x6,x5,#40 ++ ++ cmp w17,#-1 // is value impossible? ++ b.ne .Leven_neon ++ ++ fmov d24,x10 ++ fmov d25,x11 ++ fmov d26,x12 ++ fmov d27,x13 ++ fmov d28,x14 ++ ++ ////////////////////////////////// initialize r^n table ++ mov x4,x7 // r^1 ++ add x9,x8,x8,lsr#2 // s1 = r1 + (r1 >> 2) ++ mov x5,x8 ++ mov x6,xzr ++ add x0,x0,#48+12 ++ bl poly1305_splat ++ ++ bl poly1305_mult // r^2 ++ sub x0,x0,#4 ++ bl poly1305_splat ++ ++ bl poly1305_mult // r^3 ++ sub x0,x0,#4 ++ bl poly1305_splat ++ ++ bl poly1305_mult // r^4 ++ sub x0,x0,#4 ++ bl poly1305_splat ++ sub x0,x0,#48 // restore original x0 ++ b .Ldo_neon ++ ++.align 4 ++.Leven_neon: ++ fmov d24,x10 ++ fmov d25,x11 ++ fmov d26,x12 ++ fmov d27,x13 ++ fmov d28,x14 ++ ++.Ldo_neon: ++ ldp x8,x12,[x1,#32] // inp[2:3] ++ subs x2,x2,#64 ++ ldp x9,x13,[x1,#48] ++ add x16,x1,#96 ++ adr x17,.Lzeros ++ ++ lsl x3,x3,#24 ++ add x15,x0,#48 ++ ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ and x5,x9,#0x03ffffff ++ ubfx x6,x8,#26,#26 ++ ubfx x7,x9,#26,#26 ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ extr x8,x12,x8,#52 ++ extr x9,x13,x9,#52 ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ fmov d14,x4 ++ and x8,x8,#0x03ffffff ++ and x9,x9,#0x03ffffff ++ ubfx x10,x12,#14,#26 ++ ubfx x11,x13,#14,#26 ++ add x12,x3,x12,lsr#40 ++ add x13,x3,x13,lsr#40 ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ fmov d15,x6 ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ fmov d16,x8 ++ fmov d17,x10 ++ fmov d18,x12 ++ ++ ldp x8,x12,[x1],#16 // inp[0:1] ++ ldp x9,x13,[x1],#48 ++ ++ ld1 {v0.4s,v1.4s,v2.4s,v3.4s},[x15],#64 ++ ld1 {v4.4s,v5.4s,v6.4s,v7.4s},[x15],#64 ++ ld1 {v8.4s},[x15] ++ ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ and x5,x9,#0x03ffffff ++ ubfx x6,x8,#26,#26 ++ ubfx x7,x9,#26,#26 ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ extr x8,x12,x8,#52 ++ extr x9,x13,x9,#52 ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ fmov d9,x4 ++ and x8,x8,#0x03ffffff ++ and x9,x9,#0x03ffffff ++ ubfx x10,x12,#14,#26 ++ ubfx x11,x13,#14,#26 ++ add x12,x3,x12,lsr#40 ++ add x13,x3,x13,lsr#40 ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ fmov d10,x6 ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ movi v31.2d,#-1 ++ fmov d11,x8 ++ fmov d12,x10 ++ fmov d13,x12 ++ ushr v31.2d,v31.2d,#38 ++ ++ b.ls .Lskip_loop ++ ++.align 4 ++.Loop_neon: ++ //////////////////////////////////////////////////////////////// ++ // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2 ++ // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r ++ // ___________________/ ++ // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2 ++ // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r ++ // ___________________/ ____________________/ ++ // ++ // Note that we start with inp[2:3]*r^2. This is because it ++ // doesn't depend on reduction in previous iteration. ++ //////////////////////////////////////////////////////////////// ++ // d4 = h0*r4 + h1*r3 + h2*r2 + h3*r1 + h4*r0 ++ // d3 = h0*r3 + h1*r2 + h2*r1 + h3*r0 + h4*5*r4 ++ // d2 = h0*r2 + h1*r1 + h2*r0 + h3*5*r4 + h4*5*r3 ++ // d1 = h0*r1 + h1*r0 + h2*5*r4 + h3*5*r3 + h4*5*r2 ++ // d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1 ++ ++ subs x2,x2,#64 ++ umull v23.2d,v14.2s,v7.s[2] ++ csel x16,x17,x16,lo ++ umull v22.2d,v14.2s,v5.s[2] ++ umull v21.2d,v14.2s,v3.s[2] ++ ldp x8,x12,[x16],#16 // inp[2:3] (or zero) ++ umull v20.2d,v14.2s,v1.s[2] ++ ldp x9,x13,[x16],#48 ++ umull v19.2d,v14.2s,v0.s[2] ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ ++ umlal v23.2d,v15.2s,v5.s[2] ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ umlal v22.2d,v15.2s,v3.s[2] ++ and x5,x9,#0x03ffffff ++ umlal v21.2d,v15.2s,v1.s[2] ++ ubfx x6,x8,#26,#26 ++ umlal v20.2d,v15.2s,v0.s[2] ++ ubfx x7,x9,#26,#26 ++ umlal v19.2d,v15.2s,v8.s[2] ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ ++ umlal v23.2d,v16.2s,v3.s[2] ++ extr x8,x12,x8,#52 ++ umlal v22.2d,v16.2s,v1.s[2] ++ extr x9,x13,x9,#52 ++ umlal v21.2d,v16.2s,v0.s[2] ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ umlal v20.2d,v16.2s,v8.s[2] ++ fmov d14,x4 ++ umlal v19.2d,v16.2s,v6.s[2] ++ and x8,x8,#0x03ffffff ++ ++ umlal v23.2d,v17.2s,v1.s[2] ++ and x9,x9,#0x03ffffff ++ umlal v22.2d,v17.2s,v0.s[2] ++ ubfx x10,x12,#14,#26 ++ umlal v21.2d,v17.2s,v8.s[2] ++ ubfx x11,x13,#14,#26 ++ umlal v20.2d,v17.2s,v6.s[2] ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ umlal v19.2d,v17.2s,v4.s[2] ++ fmov d15,x6 ++ ++ add v11.2s,v11.2s,v26.2s ++ add x12,x3,x12,lsr#40 ++ umlal v23.2d,v18.2s,v0.s[2] ++ add x13,x3,x13,lsr#40 ++ umlal v22.2d,v18.2s,v8.s[2] ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ umlal v21.2d,v18.2s,v6.s[2] ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ umlal v20.2d,v18.2s,v4.s[2] ++ fmov d16,x8 ++ umlal v19.2d,v18.2s,v2.s[2] ++ fmov d17,x10 ++ ++ //////////////////////////////////////////////////////////////// ++ // (hash+inp[0:1])*r^4 and accumulate ++ ++ add v9.2s,v9.2s,v24.2s ++ fmov d18,x12 ++ umlal v22.2d,v11.2s,v1.s[0] ++ ldp x8,x12,[x1],#16 // inp[0:1] ++ umlal v19.2d,v11.2s,v6.s[0] ++ ldp x9,x13,[x1],#48 ++ umlal v23.2d,v11.2s,v3.s[0] ++ umlal v20.2d,v11.2s,v8.s[0] ++ umlal v21.2d,v11.2s,v0.s[0] ++#ifdef __AARCH64EB__ ++ rev x8,x8 ++ rev x12,x12 ++ rev x9,x9 ++ rev x13,x13 ++#endif ++ ++ add v10.2s,v10.2s,v25.2s ++ umlal v22.2d,v9.2s,v5.s[0] ++ umlal v23.2d,v9.2s,v7.s[0] ++ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26 ++ umlal v21.2d,v9.2s,v3.s[0] ++ and x5,x9,#0x03ffffff ++ umlal v19.2d,v9.2s,v0.s[0] ++ ubfx x6,x8,#26,#26 ++ umlal v20.2d,v9.2s,v1.s[0] ++ ubfx x7,x9,#26,#26 ++ ++ add v12.2s,v12.2s,v27.2s ++ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32 ++ umlal v22.2d,v10.2s,v3.s[0] ++ extr x8,x12,x8,#52 ++ umlal v23.2d,v10.2s,v5.s[0] ++ extr x9,x13,x9,#52 ++ umlal v19.2d,v10.2s,v8.s[0] ++ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32 ++ umlal v21.2d,v10.2s,v1.s[0] ++ fmov d9,x4 ++ umlal v20.2d,v10.2s,v0.s[0] ++ and x8,x8,#0x03ffffff ++ ++ add v13.2s,v13.2s,v28.2s ++ and x9,x9,#0x03ffffff ++ umlal v22.2d,v12.2s,v0.s[0] ++ ubfx x10,x12,#14,#26 ++ umlal v19.2d,v12.2s,v4.s[0] ++ ubfx x11,x13,#14,#26 ++ umlal v23.2d,v12.2s,v1.s[0] ++ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32 ++ umlal v20.2d,v12.2s,v6.s[0] ++ fmov d10,x6 ++ umlal v21.2d,v12.2s,v8.s[0] ++ add x12,x3,x12,lsr#40 ++ ++ umlal v22.2d,v13.2s,v8.s[0] ++ add x13,x3,x13,lsr#40 ++ umlal v19.2d,v13.2s,v2.s[0] ++ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32 ++ umlal v23.2d,v13.2s,v0.s[0] ++ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32 ++ umlal v20.2d,v13.2s,v4.s[0] ++ fmov d11,x8 ++ umlal v21.2d,v13.2s,v6.s[0] ++ fmov d12,x10 ++ fmov d13,x12 ++ ++ ///////////////////////////////////////////////////////////////// ++ // lazy reduction as discussed in "NEON crypto" by D.J. Bernstein ++ // and P. Schwabe ++ // ++ // [see discussion in poly1305-armv4 module] ++ ++ ushr v29.2d,v22.2d,#26 ++ xtn v27.2s,v22.2d ++ ushr v30.2d,v19.2d,#26 ++ and v19.16b,v19.16b,v31.16b ++ add v23.2d,v23.2d,v29.2d // h3 -> h4 ++ bic v27.2s,#0xfc,lsl#24 // &=0x03ffffff ++ add v20.2d,v20.2d,v30.2d // h0 -> h1 ++ ++ ushr v29.2d,v23.2d,#26 ++ xtn v28.2s,v23.2d ++ ushr v30.2d,v20.2d,#26 ++ xtn v25.2s,v20.2d ++ bic v28.2s,#0xfc,lsl#24 ++ add v21.2d,v21.2d,v30.2d // h1 -> h2 ++ ++ add v19.2d,v19.2d,v29.2d ++ shl v29.2d,v29.2d,#2 ++ shrn v30.2s,v21.2d,#26 ++ xtn v26.2s,v21.2d ++ add v19.2d,v19.2d,v29.2d // h4 -> h0 ++ bic v25.2s,#0xfc,lsl#24 ++ add v27.2s,v27.2s,v30.2s // h2 -> h3 ++ bic v26.2s,#0xfc,lsl#24 ++ ++ shrn v29.2s,v19.2d,#26 ++ xtn v24.2s,v19.2d ++ ushr v30.2s,v27.2s,#26 ++ bic v27.2s,#0xfc,lsl#24 ++ bic v24.2s,#0xfc,lsl#24 ++ add v25.2s,v25.2s,v29.2s // h0 -> h1 ++ add v28.2s,v28.2s,v30.2s // h3 -> h4 ++ ++ b.hi .Loop_neon ++ ++.Lskip_loop: ++ dup v16.2d,v16.d[0] ++ add v11.2s,v11.2s,v26.2s ++ ++ //////////////////////////////////////////////////////////////// ++ // multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1 ++ ++ adds x2,x2,#32 ++ b.ne .Long_tail ++ ++ dup v16.2d,v11.d[0] ++ add v14.2s,v9.2s,v24.2s ++ add v17.2s,v12.2s,v27.2s ++ add v15.2s,v10.2s,v25.2s ++ add v18.2s,v13.2s,v28.2s ++ ++.Long_tail: ++ dup v14.2d,v14.d[0] ++ umull2 v19.2d,v16.4s,v6.4s ++ umull2 v22.2d,v16.4s,v1.4s ++ umull2 v23.2d,v16.4s,v3.4s ++ umull2 v21.2d,v16.4s,v0.4s ++ umull2 v20.2d,v16.4s,v8.4s ++ ++ dup v15.2d,v15.d[0] ++ umlal2 v19.2d,v14.4s,v0.4s ++ umlal2 v21.2d,v14.4s,v3.4s ++ umlal2 v22.2d,v14.4s,v5.4s ++ umlal2 v23.2d,v14.4s,v7.4s ++ umlal2 v20.2d,v14.4s,v1.4s ++ ++ dup v17.2d,v17.d[0] ++ umlal2 v19.2d,v15.4s,v8.4s ++ umlal2 v22.2d,v15.4s,v3.4s ++ umlal2 v21.2d,v15.4s,v1.4s ++ umlal2 v23.2d,v15.4s,v5.4s ++ umlal2 v20.2d,v15.4s,v0.4s ++ ++ dup v18.2d,v18.d[0] ++ umlal2 v22.2d,v17.4s,v0.4s ++ umlal2 v23.2d,v17.4s,v1.4s ++ umlal2 v19.2d,v17.4s,v4.4s ++ umlal2 v20.2d,v17.4s,v6.4s ++ umlal2 v21.2d,v17.4s,v8.4s ++ ++ umlal2 v22.2d,v18.4s,v8.4s ++ umlal2 v19.2d,v18.4s,v2.4s ++ umlal2 v23.2d,v18.4s,v0.4s ++ umlal2 v20.2d,v18.4s,v4.4s ++ umlal2 v21.2d,v18.4s,v6.4s ++ ++ b.eq .Lshort_tail ++ ++ //////////////////////////////////////////////////////////////// ++ // (hash+inp[0:1])*r^4:r^3 and accumulate ++ ++ add v9.2s,v9.2s,v24.2s ++ umlal v22.2d,v11.2s,v1.2s ++ umlal v19.2d,v11.2s,v6.2s ++ umlal v23.2d,v11.2s,v3.2s ++ umlal v20.2d,v11.2s,v8.2s ++ umlal v21.2d,v11.2s,v0.2s ++ ++ add v10.2s,v10.2s,v25.2s ++ umlal v22.2d,v9.2s,v5.2s ++ umlal v19.2d,v9.2s,v0.2s ++ umlal v23.2d,v9.2s,v7.2s ++ umlal v20.2d,v9.2s,v1.2s ++ umlal v21.2d,v9.2s,v3.2s ++ ++ add v12.2s,v12.2s,v27.2s ++ umlal v22.2d,v10.2s,v3.2s ++ umlal v19.2d,v10.2s,v8.2s ++ umlal v23.2d,v10.2s,v5.2s ++ umlal v20.2d,v10.2s,v0.2s ++ umlal v21.2d,v10.2s,v1.2s ++ ++ add v13.2s,v13.2s,v28.2s ++ umlal v22.2d,v12.2s,v0.2s ++ umlal v19.2d,v12.2s,v4.2s ++ umlal v23.2d,v12.2s,v1.2s ++ umlal v20.2d,v12.2s,v6.2s ++ umlal v21.2d,v12.2s,v8.2s ++ ++ umlal v22.2d,v13.2s,v8.2s ++ umlal v19.2d,v13.2s,v2.2s ++ umlal v23.2d,v13.2s,v0.2s ++ umlal v20.2d,v13.2s,v4.2s ++ umlal v21.2d,v13.2s,v6.2s ++ ++.Lshort_tail: ++ //////////////////////////////////////////////////////////////// ++ // horizontal add ++ ++ addp v22.2d,v22.2d,v22.2d ++ ldp d8,d9,[sp,#16] // meet ABI requirements ++ addp v19.2d,v19.2d,v19.2d ++ ldp d10,d11,[sp,#32] ++ addp v23.2d,v23.2d,v23.2d ++ ldp d12,d13,[sp,#48] ++ addp v20.2d,v20.2d,v20.2d ++ ldp d14,d15,[sp,#64] ++ addp v21.2d,v21.2d,v21.2d ++ ldr x30,[sp,#8] ++ .inst 0xd50323bf // autiasp ++ ++ //////////////////////////////////////////////////////////////// ++ // lazy reduction, but without narrowing ++ ++ ushr v29.2d,v22.2d,#26 ++ and v22.16b,v22.16b,v31.16b ++ ushr v30.2d,v19.2d,#26 ++ and v19.16b,v19.16b,v31.16b ++ ++ add v23.2d,v23.2d,v29.2d // h3 -> h4 ++ add v20.2d,v20.2d,v30.2d // h0 -> h1 ++ ++ ushr v29.2d,v23.2d,#26 ++ and v23.16b,v23.16b,v31.16b ++ ushr v30.2d,v20.2d,#26 ++ and v20.16b,v20.16b,v31.16b ++ add v21.2d,v21.2d,v30.2d // h1 -> h2 ++ ++ add v19.2d,v19.2d,v29.2d ++ shl v29.2d,v29.2d,#2 ++ ushr v30.2d,v21.2d,#26 ++ and v21.16b,v21.16b,v31.16b ++ add v19.2d,v19.2d,v29.2d // h4 -> h0 ++ add v22.2d,v22.2d,v30.2d // h2 -> h3 ++ ++ ushr v29.2d,v19.2d,#26 ++ and v19.16b,v19.16b,v31.16b ++ ushr v30.2d,v22.2d,#26 ++ and v22.16b,v22.16b,v31.16b ++ add v20.2d,v20.2d,v29.2d // h0 -> h1 ++ add v23.2d,v23.2d,v30.2d // h3 -> h4 ++ ++ //////////////////////////////////////////////////////////////// ++ // write the result, can be partially reduced ++ ++ st4 {v19.s,v20.s,v21.s,v22.s}[0],[x0],#16 ++ mov x4,#1 ++ st1 {v23.s}[0],[x0] ++ str x4,[x0,#8] // set is_base2_26 ++ ++ ldr x29,[sp],#80 ++ ret ++.size poly1305_blocks_neon,.-poly1305_blocks_neon ++ ++.align 5 ++.Lzeros: ++.long 0,0,0,0,0,0,0,0 ++.asciz "Poly1305 for ARMv8, CRYPTOGAMS by @dot-asm" ++.align 2 ++#if !defined(__KERNEL__) && !defined(_WIN64) ++.comm OPENSSL_armcap_P,4,4 ++.hidden OPENSSL_armcap_P ++#endif +--- /dev/null ++++ b/arch/arm64/crypto/poly1305-glue.c +@@ -0,0 +1,237 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * OpenSSL/Cryptogams accelerated Poly1305 transform for arm64 ++ * ++ * Copyright (C) 2019 Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++asmlinkage void poly1305_init_arm64(void *state, const u8 *key); ++asmlinkage void poly1305_blocks(void *state, const u8 *src, u32 len, u32 hibit); ++asmlinkage void poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit); ++asmlinkage void poly1305_emit(void *state, __le32 *digest, const u32 *nonce); ++ ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); ++ ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++{ ++ poly1305_init_arm64(&dctx->h, key); ++ dctx->s[0] = get_unaligned_le32(key + 16); ++ dctx->s[1] = get_unaligned_le32(key + 20); ++ dctx->s[2] = get_unaligned_le32(key + 24); ++ dctx->s[3] = get_unaligned_le32(key + 28); ++ dctx->buflen = 0; ++} ++EXPORT_SYMBOL(poly1305_init_arch); ++ ++static int neon_poly1305_init(struct shash_desc *desc) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ dctx->buflen = 0; ++ dctx->rset = 0; ++ dctx->sset = false; ++ ++ return 0; ++} ++ ++static void neon_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, ++ u32 len, u32 hibit, bool do_neon) ++{ ++ if (unlikely(!dctx->sset)) { ++ if (!dctx->rset) { ++ poly1305_init_arch(dctx, src); ++ src += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ dctx->rset = 1; ++ } ++ if (len >= POLY1305_BLOCK_SIZE) { ++ dctx->s[0] = get_unaligned_le32(src + 0); ++ dctx->s[1] = get_unaligned_le32(src + 4); ++ dctx->s[2] = get_unaligned_le32(src + 8); ++ dctx->s[3] = get_unaligned_le32(src + 12); ++ src += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ dctx->sset = true; ++ } ++ if (len < POLY1305_BLOCK_SIZE) ++ return; ++ } ++ ++ len &= ~(POLY1305_BLOCK_SIZE - 1); ++ ++ if (static_branch_likely(&have_neon) && likely(do_neon)) ++ poly1305_blocks_neon(&dctx->h, src, len, hibit); ++ else ++ poly1305_blocks(&dctx->h, src, len, hibit); ++} ++ ++static void neon_poly1305_do_update(struct poly1305_desc_ctx *dctx, ++ const u8 *src, u32 len, bool do_neon) ++{ ++ if (unlikely(dctx->buflen)) { ++ u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen); ++ ++ memcpy(dctx->buf + dctx->buflen, src, bytes); ++ src += bytes; ++ len -= bytes; ++ dctx->buflen += bytes; ++ ++ if (dctx->buflen == POLY1305_BLOCK_SIZE) { ++ neon_poly1305_blocks(dctx, dctx->buf, ++ POLY1305_BLOCK_SIZE, 1, false); ++ dctx->buflen = 0; ++ } ++ } ++ ++ if (likely(len >= POLY1305_BLOCK_SIZE)) { ++ neon_poly1305_blocks(dctx, src, len, 1, do_neon); ++ src += round_down(len, POLY1305_BLOCK_SIZE); ++ len %= POLY1305_BLOCK_SIZE; ++ } ++ ++ if (unlikely(len)) { ++ dctx->buflen = len; ++ memcpy(dctx->buf, src, len); ++ } ++} ++ ++static int neon_poly1305_update(struct shash_desc *desc, ++ const u8 *src, unsigned int srclen) ++{ ++ bool do_neon = crypto_simd_usable() && srclen > 128; ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ if (static_branch_likely(&have_neon) && do_neon) ++ kernel_neon_begin(); ++ neon_poly1305_do_update(dctx, src, srclen, do_neon); ++ if (static_branch_likely(&have_neon) && do_neon) ++ kernel_neon_end(); ++ return 0; ++} ++ ++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src, ++ unsigned int nbytes) ++{ ++ if (unlikely(dctx->buflen)) { ++ u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen); ++ ++ memcpy(dctx->buf + dctx->buflen, src, bytes); ++ src += bytes; ++ nbytes -= bytes; ++ dctx->buflen += bytes; ++ ++ if (dctx->buflen == POLY1305_BLOCK_SIZE) { ++ poly1305_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 1); ++ dctx->buflen = 0; ++ } ++ } ++ ++ if (likely(nbytes >= POLY1305_BLOCK_SIZE)) { ++ unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE); ++ ++ if (static_branch_likely(&have_neon) && crypto_simd_usable()) { ++ kernel_neon_begin(); ++ poly1305_blocks_neon(&dctx->h, src, len, 1); ++ kernel_neon_end(); ++ } else { ++ poly1305_blocks(&dctx->h, src, len, 1); ++ } ++ src += len; ++ nbytes %= POLY1305_BLOCK_SIZE; ++ } ++ ++ if (unlikely(nbytes)) { ++ dctx->buflen = nbytes; ++ memcpy(dctx->buf, src, nbytes); ++ } ++} ++EXPORT_SYMBOL(poly1305_update_arch); ++ ++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst) ++{ ++ __le32 digest[4]; ++ u64 f = 0; ++ ++ if (unlikely(dctx->buflen)) { ++ dctx->buf[dctx->buflen++] = 1; ++ memset(dctx->buf + dctx->buflen, 0, ++ POLY1305_BLOCK_SIZE - dctx->buflen); ++ poly1305_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0); ++ } ++ ++ poly1305_emit(&dctx->h, digest, dctx->s); ++ ++ /* mac = (h + s) % (2^128) */ ++ f = (f >> 32) + le32_to_cpu(digest[0]); ++ put_unaligned_le32(f, dst); ++ f = (f >> 32) + le32_to_cpu(digest[1]); ++ put_unaligned_le32(f, dst + 4); ++ f = (f >> 32) + le32_to_cpu(digest[2]); ++ put_unaligned_le32(f, dst + 8); ++ f = (f >> 32) + le32_to_cpu(digest[3]); ++ put_unaligned_le32(f, dst + 12); ++ ++ *dctx = (struct poly1305_desc_ctx){}; ++} ++EXPORT_SYMBOL(poly1305_final_arch); ++ ++static int neon_poly1305_final(struct shash_desc *desc, u8 *dst) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ if (unlikely(!dctx->sset)) ++ return -ENOKEY; ++ ++ poly1305_final_arch(dctx, dst); ++ return 0; ++} ++ ++static struct shash_alg neon_poly1305_alg = { ++ .init = neon_poly1305_init, ++ .update = neon_poly1305_update, ++ .final = neon_poly1305_final, ++ .digestsize = POLY1305_DIGEST_SIZE, ++ .descsize = sizeof(struct poly1305_desc_ctx), ++ ++ .base.cra_name = "poly1305", ++ .base.cra_driver_name = "poly1305-neon", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = POLY1305_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++}; ++ ++static int __init neon_poly1305_mod_init(void) ++{ ++ if (!cpu_have_named_feature(ASIMD)) ++ return 0; ++ ++ static_branch_enable(&have_neon); ++ ++ return crypto_register_shash(&neon_poly1305_alg); ++} ++ ++static void __exit neon_poly1305_mod_exit(void) ++{ ++ if (cpu_have_named_feature(ASIMD)) ++ crypto_unregister_shash(&neon_poly1305_alg); ++} ++ ++module_init(neon_poly1305_mod_init); ++module_exit(neon_poly1305_mod_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_CRYPTO("poly1305"); ++MODULE_ALIAS_CRYPTO("poly1305-neon"); +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -40,6 +40,7 @@ config CRYPTO_LIB_DES + config CRYPTO_LIB_POLY1305_RSIZE + int + default 4 if X86_64 ++ default 9 if ARM64 + default 1 + + config CRYPTO_ARCH_HAVE_LIB_POLY1305 diff --git a/ipq806x/backport-5.4/080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch b/ipq806x/backport-5.4/080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch new file mode 100644 index 0000000..367b20f --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0019-crypto-arm-poly1305-incorporate-OpenSSL-CRYPTOGAMS-N.patch @@ -0,0 +1,2776 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:25 +0100 +Subject: [PATCH] crypto: arm/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON + implementation + +commit a6b803b3ddc793d6db0c16f12fc12d30d20fa9cc upstream. + +This is a straight import of the OpenSSL/CRYPTOGAMS Poly1305 implementation +for NEON authored by Andy Polyakov, and contributed by him to the OpenSSL +project. The file 'poly1305-armv4.pl' is taken straight from this upstream +GitHub repository [0] at commit ec55a08dc0244ce570c4fc7cade330c60798952f, +and already contains all the changes required to build it as part of a +Linux kernel module. + +[0] https://github.com/dot-asm/cryptogams + +Co-developed-by: Andy Polyakov +Signed-off-by: Andy Polyakov +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/Kconfig | 5 + + arch/arm/crypto/Makefile | 12 +- + arch/arm/crypto/poly1305-armv4.pl | 1236 +++++++++++++++++++++++ + arch/arm/crypto/poly1305-core.S_shipped | 1158 +++++++++++++++++++++ + arch/arm/crypto/poly1305-glue.c | 276 +++++ + lib/crypto/Kconfig | 2 +- + 6 files changed, 2687 insertions(+), 2 deletions(-) + create mode 100644 arch/arm/crypto/poly1305-armv4.pl + create mode 100644 arch/arm/crypto/poly1305-core.S_shipped + create mode 100644 arch/arm/crypto/poly1305-glue.c + +--- a/arch/arm/crypto/Kconfig ++++ b/arch/arm/crypto/Kconfig +@@ -131,6 +131,11 @@ config CRYPTO_CHACHA20_NEON + select CRYPTO_BLKCIPHER + select CRYPTO_ARCH_HAVE_LIB_CHACHA + ++config CRYPTO_POLY1305_ARM ++ tristate "Accelerated scalar and SIMD Poly1305 hash implementations" ++ select CRYPTO_HASH ++ select CRYPTO_ARCH_HAVE_LIB_POLY1305 ++ + config CRYPTO_NHPOLY1305_NEON + tristate "NEON accelerated NHPoly1305 hash function (for Adiantum)" + depends on KERNEL_MODE_NEON +--- a/arch/arm/crypto/Makefile ++++ b/arch/arm/crypto/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sh + obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o + obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha512-arm.o + obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o ++obj-$(CONFIG_CRYPTO_POLY1305_ARM) += poly1305-arm.o + obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o + + ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o +@@ -55,12 +56,16 @@ crct10dif-arm-ce-y := crct10dif-ce-core. + crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o + chacha-neon-y := chacha-scalar-core.o chacha-glue.o + chacha-neon-$(CONFIG_KERNEL_MODE_NEON) += chacha-neon-core.o ++poly1305-arm-y := poly1305-core.o poly1305-glue.o + nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o + + ifdef REGENERATE_ARM_CRYPTO + quiet_cmd_perl = PERL $@ + cmd_perl = $(PERL) $(<) > $(@) + ++$(src)/poly1305-core.S_shipped: $(src)/poly1305-armv4.pl ++ $(call cmd,perl) ++ + $(src)/sha256-core.S_shipped: $(src)/sha256-armv4.pl + $(call cmd,perl) + +@@ -68,4 +73,9 @@ $(src)/sha512-core.S_shipped: $(src)/sha + $(call cmd,perl) + endif + +-clean-files += sha256-core.S sha512-core.S ++clean-files += poly1305-core.S sha256-core.S sha512-core.S ++ ++# massage the perlasm code a bit so we only get the NEON routine if we need it ++poly1305-aflags-$(CONFIG_CPU_V7) := -U__LINUX_ARM_ARCH__ -D__LINUX_ARM_ARCH__=5 ++poly1305-aflags-$(CONFIG_KERNEL_MODE_NEON) := -U__LINUX_ARM_ARCH__ -D__LINUX_ARM_ARCH__=7 ++AFLAGS_poly1305-core.o += $(poly1305-aflags-y) +--- /dev/null ++++ b/arch/arm/crypto/poly1305-armv4.pl +@@ -0,0 +1,1236 @@ ++#!/usr/bin/env perl ++# SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause ++# ++# ==================================================================== ++# Written by Andy Polyakov, @dot-asm, initially for the OpenSSL ++# project. ++# ==================================================================== ++# ++# IALU(*)/gcc-4.4 NEON ++# ++# ARM11xx(ARMv6) 7.78/+100% - ++# Cortex-A5 6.35/+130% 3.00 ++# Cortex-A8 6.25/+115% 2.36 ++# Cortex-A9 5.10/+95% 2.55 ++# Cortex-A15 3.85/+85% 1.25(**) ++# Snapdragon S4 5.70/+100% 1.48(**) ++# ++# (*) this is for -march=armv6, i.e. with bunch of ldrb loading data; ++# (**) these are trade-off results, they can be improved by ~8% but at ++# the cost of 15/12% regression on Cortex-A5/A7, it's even possible ++# to improve Cortex-A9 result, but then A5/A7 loose more than 20%; ++ ++$flavour = shift; ++if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } ++else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} } ++ ++if ($flavour && $flavour ne "void") { ++ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; ++ ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or ++ ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or ++ die "can't locate arm-xlate.pl"; ++ ++ open STDOUT,"| \"$^X\" $xlate $flavour $output"; ++} else { ++ open STDOUT,">$output"; ++} ++ ++($ctx,$inp,$len,$padbit)=map("r$_",(0..3)); ++ ++$code.=<<___; ++#ifndef __KERNEL__ ++# include "arm_arch.h" ++#else ++# define __ARM_ARCH__ __LINUX_ARM_ARCH__ ++# define __ARM_MAX_ARCH__ __LINUX_ARM_ARCH__ ++# define poly1305_init poly1305_init_arm ++# define poly1305_blocks poly1305_blocks_arm ++# define poly1305_emit poly1305_emit_arm ++.globl poly1305_blocks_neon ++#endif ++ ++#if defined(__thumb2__) ++.syntax unified ++.thumb ++#else ++.code 32 ++#endif ++ ++.text ++ ++.globl poly1305_emit ++.globl poly1305_blocks ++.globl poly1305_init ++.type poly1305_init,%function ++.align 5 ++poly1305_init: ++.Lpoly1305_init: ++ stmdb sp!,{r4-r11} ++ ++ eor r3,r3,r3 ++ cmp $inp,#0 ++ str r3,[$ctx,#0] @ zero hash value ++ str r3,[$ctx,#4] ++ str r3,[$ctx,#8] ++ str r3,[$ctx,#12] ++ str r3,[$ctx,#16] ++ str r3,[$ctx,#36] @ clear is_base2_26 ++ add $ctx,$ctx,#20 ++ ++#ifdef __thumb2__ ++ it eq ++#endif ++ moveq r0,#0 ++ beq .Lno_key ++ ++#if __ARM_MAX_ARCH__>=7 ++ mov r3,#-1 ++ str r3,[$ctx,#28] @ impossible key power value ++# ifndef __KERNEL__ ++ adr r11,.Lpoly1305_init ++ ldr r12,.LOPENSSL_armcap ++# endif ++#endif ++ ldrb r4,[$inp,#0] ++ mov r10,#0x0fffffff ++ ldrb r5,[$inp,#1] ++ and r3,r10,#-4 @ 0x0ffffffc ++ ldrb r6,[$inp,#2] ++ ldrb r7,[$inp,#3] ++ orr r4,r4,r5,lsl#8 ++ ldrb r5,[$inp,#4] ++ orr r4,r4,r6,lsl#16 ++ ldrb r6,[$inp,#5] ++ orr r4,r4,r7,lsl#24 ++ ldrb r7,[$inp,#6] ++ and r4,r4,r10 ++ ++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ++# if !defined(_WIN32) ++ ldr r12,[r11,r12] @ OPENSSL_armcap_P ++# endif ++# if defined(__APPLE__) || defined(_WIN32) ++ ldr r12,[r12] ++# endif ++#endif ++ ldrb r8,[$inp,#7] ++ orr r5,r5,r6,lsl#8 ++ ldrb r6,[$inp,#8] ++ orr r5,r5,r7,lsl#16 ++ ldrb r7,[$inp,#9] ++ orr r5,r5,r8,lsl#24 ++ ldrb r8,[$inp,#10] ++ and r5,r5,r3 ++ ++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ++ tst r12,#ARMV7_NEON @ check for NEON ++# ifdef __thumb2__ ++ adr r9,.Lpoly1305_blocks_neon ++ adr r11,.Lpoly1305_blocks ++ it ne ++ movne r11,r9 ++ adr r12,.Lpoly1305_emit ++ orr r11,r11,#1 @ thumb-ify addresses ++ orr r12,r12,#1 ++# else ++ add r12,r11,#(.Lpoly1305_emit-.Lpoly1305_init) ++ ite eq ++ addeq r11,r11,#(.Lpoly1305_blocks-.Lpoly1305_init) ++ addne r11,r11,#(.Lpoly1305_blocks_neon-.Lpoly1305_init) ++# endif ++#endif ++ ldrb r9,[$inp,#11] ++ orr r6,r6,r7,lsl#8 ++ ldrb r7,[$inp,#12] ++ orr r6,r6,r8,lsl#16 ++ ldrb r8,[$inp,#13] ++ orr r6,r6,r9,lsl#24 ++ ldrb r9,[$inp,#14] ++ and r6,r6,r3 ++ ++ ldrb r10,[$inp,#15] ++ orr r7,r7,r8,lsl#8 ++ str r4,[$ctx,#0] ++ orr r7,r7,r9,lsl#16 ++ str r5,[$ctx,#4] ++ orr r7,r7,r10,lsl#24 ++ str r6,[$ctx,#8] ++ and r7,r7,r3 ++ str r7,[$ctx,#12] ++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ++ stmia r2,{r11,r12} @ fill functions table ++ mov r0,#1 ++#else ++ mov r0,#0 ++#endif ++.Lno_key: ++ ldmia sp!,{r4-r11} ++#if __ARM_ARCH__>=5 ++ ret @ bx lr ++#else ++ tst lr,#1 ++ moveq pc,lr @ be binary compatible with V4, yet ++ bx lr @ interoperable with Thumb ISA:-) ++#endif ++.size poly1305_init,.-poly1305_init ++___ ++{ ++my ($h0,$h1,$h2,$h3,$h4,$r0,$r1,$r2,$r3)=map("r$_",(4..12)); ++my ($s1,$s2,$s3)=($r1,$r2,$r3); ++ ++$code.=<<___; ++.type poly1305_blocks,%function ++.align 5 ++poly1305_blocks: ++.Lpoly1305_blocks: ++ stmdb sp!,{r3-r11,lr} ++ ++ ands $len,$len,#-16 ++ beq .Lno_data ++ ++ add $len,$len,$inp @ end pointer ++ sub sp,sp,#32 ++ ++#if __ARM_ARCH__<7 ++ ldmia $ctx,{$h0-$r3} @ load context ++ add $ctx,$ctx,#20 ++ str $len,[sp,#16] @ offload stuff ++ str $ctx,[sp,#12] ++#else ++ ldr lr,[$ctx,#36] @ is_base2_26 ++ ldmia $ctx!,{$h0-$h4} @ load hash value ++ str $len,[sp,#16] @ offload stuff ++ str $ctx,[sp,#12] ++ ++ adds $r0,$h0,$h1,lsl#26 @ base 2^26 -> base 2^32 ++ mov $r1,$h1,lsr#6 ++ adcs $r1,$r1,$h2,lsl#20 ++ mov $r2,$h2,lsr#12 ++ adcs $r2,$r2,$h3,lsl#14 ++ mov $r3,$h3,lsr#18 ++ adcs $r3,$r3,$h4,lsl#8 ++ mov $len,#0 ++ teq lr,#0 ++ str $len,[$ctx,#16] @ clear is_base2_26 ++ adc $len,$len,$h4,lsr#24 ++ ++ itttt ne ++ movne $h0,$r0 @ choose between radixes ++ movne $h1,$r1 ++ movne $h2,$r2 ++ movne $h3,$r3 ++ ldmia $ctx,{$r0-$r3} @ load key ++ it ne ++ movne $h4,$len ++#endif ++ ++ mov lr,$inp ++ cmp $padbit,#0 ++ str $r1,[sp,#20] ++ str $r2,[sp,#24] ++ str $r3,[sp,#28] ++ b .Loop ++ ++.align 4 ++.Loop: ++#if __ARM_ARCH__<7 ++ ldrb r0,[lr],#16 @ load input ++# ifdef __thumb2__ ++ it hi ++# endif ++ addhi $h4,$h4,#1 @ 1<<128 ++ ldrb r1,[lr,#-15] ++ ldrb r2,[lr,#-14] ++ ldrb r3,[lr,#-13] ++ orr r1,r0,r1,lsl#8 ++ ldrb r0,[lr,#-12] ++ orr r2,r1,r2,lsl#16 ++ ldrb r1,[lr,#-11] ++ orr r3,r2,r3,lsl#24 ++ ldrb r2,[lr,#-10] ++ adds $h0,$h0,r3 @ accumulate input ++ ++ ldrb r3,[lr,#-9] ++ orr r1,r0,r1,lsl#8 ++ ldrb r0,[lr,#-8] ++ orr r2,r1,r2,lsl#16 ++ ldrb r1,[lr,#-7] ++ orr r3,r2,r3,lsl#24 ++ ldrb r2,[lr,#-6] ++ adcs $h1,$h1,r3 ++ ++ ldrb r3,[lr,#-5] ++ orr r1,r0,r1,lsl#8 ++ ldrb r0,[lr,#-4] ++ orr r2,r1,r2,lsl#16 ++ ldrb r1,[lr,#-3] ++ orr r3,r2,r3,lsl#24 ++ ldrb r2,[lr,#-2] ++ adcs $h2,$h2,r3 ++ ++ ldrb r3,[lr,#-1] ++ orr r1,r0,r1,lsl#8 ++ str lr,[sp,#8] @ offload input pointer ++ orr r2,r1,r2,lsl#16 ++ add $s1,$r1,$r1,lsr#2 ++ orr r3,r2,r3,lsl#24 ++#else ++ ldr r0,[lr],#16 @ load input ++ it hi ++ addhi $h4,$h4,#1 @ padbit ++ ldr r1,[lr,#-12] ++ ldr r2,[lr,#-8] ++ ldr r3,[lr,#-4] ++# ifdef __ARMEB__ ++ rev r0,r0 ++ rev r1,r1 ++ rev r2,r2 ++ rev r3,r3 ++# endif ++ adds $h0,$h0,r0 @ accumulate input ++ str lr,[sp,#8] @ offload input pointer ++ adcs $h1,$h1,r1 ++ add $s1,$r1,$r1,lsr#2 ++ adcs $h2,$h2,r2 ++#endif ++ add $s2,$r2,$r2,lsr#2 ++ adcs $h3,$h3,r3 ++ add $s3,$r3,$r3,lsr#2 ++ ++ umull r2,r3,$h1,$r0 ++ adc $h4,$h4,#0 ++ umull r0,r1,$h0,$r0 ++ umlal r2,r3,$h4,$s1 ++ umlal r0,r1,$h3,$s1 ++ ldr $r1,[sp,#20] @ reload $r1 ++ umlal r2,r3,$h2,$s3 ++ umlal r0,r1,$h1,$s3 ++ umlal r2,r3,$h3,$s2 ++ umlal r0,r1,$h2,$s2 ++ umlal r2,r3,$h0,$r1 ++ str r0,[sp,#0] @ future $h0 ++ mul r0,$s2,$h4 ++ ldr $r2,[sp,#24] @ reload $r2 ++ adds r2,r2,r1 @ d1+=d0>>32 ++ eor r1,r1,r1 ++ adc lr,r3,#0 @ future $h2 ++ str r2,[sp,#4] @ future $h1 ++ ++ mul r2,$s3,$h4 ++ eor r3,r3,r3 ++ umlal r0,r1,$h3,$s3 ++ ldr $r3,[sp,#28] @ reload $r3 ++ umlal r2,r3,$h3,$r0 ++ umlal r0,r1,$h2,$r0 ++ umlal r2,r3,$h2,$r1 ++ umlal r0,r1,$h1,$r1 ++ umlal r2,r3,$h1,$r2 ++ umlal r0,r1,$h0,$r2 ++ umlal r2,r3,$h0,$r3 ++ ldr $h0,[sp,#0] ++ mul $h4,$r0,$h4 ++ ldr $h1,[sp,#4] ++ ++ adds $h2,lr,r0 @ d2+=d1>>32 ++ ldr lr,[sp,#8] @ reload input pointer ++ adc r1,r1,#0 ++ adds $h3,r2,r1 @ d3+=d2>>32 ++ ldr r0,[sp,#16] @ reload end pointer ++ adc r3,r3,#0 ++ add $h4,$h4,r3 @ h4+=d3>>32 ++ ++ and r1,$h4,#-4 ++ and $h4,$h4,#3 ++ add r1,r1,r1,lsr#2 @ *=5 ++ adds $h0,$h0,r1 ++ adcs $h1,$h1,#0 ++ adcs $h2,$h2,#0 ++ adcs $h3,$h3,#0 ++ adc $h4,$h4,#0 ++ ++ cmp r0,lr @ done yet? ++ bhi .Loop ++ ++ ldr $ctx,[sp,#12] ++ add sp,sp,#32 ++ stmdb $ctx,{$h0-$h4} @ store the result ++ ++.Lno_data: ++#if __ARM_ARCH__>=5 ++ ldmia sp!,{r3-r11,pc} ++#else ++ ldmia sp!,{r3-r11,lr} ++ tst lr,#1 ++ moveq pc,lr @ be binary compatible with V4, yet ++ bx lr @ interoperable with Thumb ISA:-) ++#endif ++.size poly1305_blocks,.-poly1305_blocks ++___ ++} ++{ ++my ($ctx,$mac,$nonce)=map("r$_",(0..2)); ++my ($h0,$h1,$h2,$h3,$h4,$g0,$g1,$g2,$g3)=map("r$_",(3..11)); ++my $g4=$ctx; ++ ++$code.=<<___; ++.type poly1305_emit,%function ++.align 5 ++poly1305_emit: ++.Lpoly1305_emit: ++ stmdb sp!,{r4-r11} ++ ++ ldmia $ctx,{$h0-$h4} ++ ++#if __ARM_ARCH__>=7 ++ ldr ip,[$ctx,#36] @ is_base2_26 ++ ++ adds $g0,$h0,$h1,lsl#26 @ base 2^26 -> base 2^32 ++ mov $g1,$h1,lsr#6 ++ adcs $g1,$g1,$h2,lsl#20 ++ mov $g2,$h2,lsr#12 ++ adcs $g2,$g2,$h3,lsl#14 ++ mov $g3,$h3,lsr#18 ++ adcs $g3,$g3,$h4,lsl#8 ++ mov $g4,#0 ++ adc $g4,$g4,$h4,lsr#24 ++ ++ tst ip,ip ++ itttt ne ++ movne $h0,$g0 ++ movne $h1,$g1 ++ movne $h2,$g2 ++ movne $h3,$g3 ++ it ne ++ movne $h4,$g4 ++#endif ++ ++ adds $g0,$h0,#5 @ compare to modulus ++ adcs $g1,$h1,#0 ++ adcs $g2,$h2,#0 ++ adcs $g3,$h3,#0 ++ adc $g4,$h4,#0 ++ tst $g4,#4 @ did it carry/borrow? ++ ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne $h0,$g0 ++ ldr $g0,[$nonce,#0] ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne $h1,$g1 ++ ldr $g1,[$nonce,#4] ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne $h2,$g2 ++ ldr $g2,[$nonce,#8] ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne $h3,$g3 ++ ldr $g3,[$nonce,#12] ++ ++ adds $h0,$h0,$g0 ++ adcs $h1,$h1,$g1 ++ adcs $h2,$h2,$g2 ++ adc $h3,$h3,$g3 ++ ++#if __ARM_ARCH__>=7 ++# ifdef __ARMEB__ ++ rev $h0,$h0 ++ rev $h1,$h1 ++ rev $h2,$h2 ++ rev $h3,$h3 ++# endif ++ str $h0,[$mac,#0] ++ str $h1,[$mac,#4] ++ str $h2,[$mac,#8] ++ str $h3,[$mac,#12] ++#else ++ strb $h0,[$mac,#0] ++ mov $h0,$h0,lsr#8 ++ strb $h1,[$mac,#4] ++ mov $h1,$h1,lsr#8 ++ strb $h2,[$mac,#8] ++ mov $h2,$h2,lsr#8 ++ strb $h3,[$mac,#12] ++ mov $h3,$h3,lsr#8 ++ ++ strb $h0,[$mac,#1] ++ mov $h0,$h0,lsr#8 ++ strb $h1,[$mac,#5] ++ mov $h1,$h1,lsr#8 ++ strb $h2,[$mac,#9] ++ mov $h2,$h2,lsr#8 ++ strb $h3,[$mac,#13] ++ mov $h3,$h3,lsr#8 ++ ++ strb $h0,[$mac,#2] ++ mov $h0,$h0,lsr#8 ++ strb $h1,[$mac,#6] ++ mov $h1,$h1,lsr#8 ++ strb $h2,[$mac,#10] ++ mov $h2,$h2,lsr#8 ++ strb $h3,[$mac,#14] ++ mov $h3,$h3,lsr#8 ++ ++ strb $h0,[$mac,#3] ++ strb $h1,[$mac,#7] ++ strb $h2,[$mac,#11] ++ strb $h3,[$mac,#15] ++#endif ++ ldmia sp!,{r4-r11} ++#if __ARM_ARCH__>=5 ++ ret @ bx lr ++#else ++ tst lr,#1 ++ moveq pc,lr @ be binary compatible with V4, yet ++ bx lr @ interoperable with Thumb ISA:-) ++#endif ++.size poly1305_emit,.-poly1305_emit ++___ ++{ ++my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("d$_",(0..9)); ++my ($D0,$D1,$D2,$D3,$D4, $H0,$H1,$H2,$H3,$H4) = map("q$_",(5..14)); ++my ($T0,$T1,$MASK) = map("q$_",(15,4,0)); ++ ++my ($in2,$zeros,$tbl0,$tbl1) = map("r$_",(4..7)); ++ ++$code.=<<___; ++#if __ARM_MAX_ARCH__>=7 ++.fpu neon ++ ++.type poly1305_init_neon,%function ++.align 5 ++poly1305_init_neon: ++.Lpoly1305_init_neon: ++ ldr r3,[$ctx,#48] @ first table element ++ cmp r3,#-1 @ is value impossible? ++ bne .Lno_init_neon ++ ++ ldr r4,[$ctx,#20] @ load key base 2^32 ++ ldr r5,[$ctx,#24] ++ ldr r6,[$ctx,#28] ++ ldr r7,[$ctx,#32] ++ ++ and r2,r4,#0x03ffffff @ base 2^32 -> base 2^26 ++ mov r3,r4,lsr#26 ++ mov r4,r5,lsr#20 ++ orr r3,r3,r5,lsl#6 ++ mov r5,r6,lsr#14 ++ orr r4,r4,r6,lsl#12 ++ mov r6,r7,lsr#8 ++ orr r5,r5,r7,lsl#18 ++ and r3,r3,#0x03ffffff ++ and r4,r4,#0x03ffffff ++ and r5,r5,#0x03ffffff ++ ++ vdup.32 $R0,r2 @ r^1 in both lanes ++ add r2,r3,r3,lsl#2 @ *5 ++ vdup.32 $R1,r3 ++ add r3,r4,r4,lsl#2 ++ vdup.32 $S1,r2 ++ vdup.32 $R2,r4 ++ add r4,r5,r5,lsl#2 ++ vdup.32 $S2,r3 ++ vdup.32 $R3,r5 ++ add r5,r6,r6,lsl#2 ++ vdup.32 $S3,r4 ++ vdup.32 $R4,r6 ++ vdup.32 $S4,r5 ++ ++ mov $zeros,#2 @ counter ++ ++.Lsquare_neon: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ @ d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ @ d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ @ d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ @ d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ ++ vmull.u32 $D0,$R0,${R0}[1] ++ vmull.u32 $D1,$R1,${R0}[1] ++ vmull.u32 $D2,$R2,${R0}[1] ++ vmull.u32 $D3,$R3,${R0}[1] ++ vmull.u32 $D4,$R4,${R0}[1] ++ ++ vmlal.u32 $D0,$R4,${S1}[1] ++ vmlal.u32 $D1,$R0,${R1}[1] ++ vmlal.u32 $D2,$R1,${R1}[1] ++ vmlal.u32 $D3,$R2,${R1}[1] ++ vmlal.u32 $D4,$R3,${R1}[1] ++ ++ vmlal.u32 $D0,$R3,${S2}[1] ++ vmlal.u32 $D1,$R4,${S2}[1] ++ vmlal.u32 $D3,$R1,${R2}[1] ++ vmlal.u32 $D2,$R0,${R2}[1] ++ vmlal.u32 $D4,$R2,${R2}[1] ++ ++ vmlal.u32 $D0,$R2,${S3}[1] ++ vmlal.u32 $D3,$R0,${R3}[1] ++ vmlal.u32 $D1,$R3,${S3}[1] ++ vmlal.u32 $D2,$R4,${S3}[1] ++ vmlal.u32 $D4,$R1,${R3}[1] ++ ++ vmlal.u32 $D3,$R4,${S4}[1] ++ vmlal.u32 $D0,$R1,${S4}[1] ++ vmlal.u32 $D1,$R2,${S4}[1] ++ vmlal.u32 $D2,$R3,${S4}[1] ++ vmlal.u32 $D4,$R0,${R4}[1] ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein ++ @ and P. Schwabe ++ @ ++ @ H0>>+H1>>+H2>>+H3>>+H4 ++ @ H3>>+H4>>*5+H0>>+H1 ++ @ ++ @ Trivia. ++ @ ++ @ Result of multiplication of n-bit number by m-bit number is ++ @ n+m bits wide. However! Even though 2^n is a n+1-bit number, ++ @ m-bit number multiplied by 2^n is still n+m bits wide. ++ @ ++ @ Sum of two n-bit numbers is n+1 bits wide, sum of three - n+2, ++ @ and so is sum of four. Sum of 2^m n-m-bit numbers and n-bit ++ @ one is n+1 bits wide. ++ @ ++ @ >>+ denotes Hnext += Hn>>26, Hn &= 0x3ffffff. This means that ++ @ H0, H2, H3 are guaranteed to be 26 bits wide, while H1 and H4 ++ @ can be 27. However! In cases when their width exceeds 26 bits ++ @ they are limited by 2^26+2^6. This in turn means that *sum* ++ @ of the products with these values can still be viewed as sum ++ @ of 52-bit numbers as long as the amount of addends is not a ++ @ power of 2. For example, ++ @ ++ @ H4 = H4*R0 + H3*R1 + H2*R2 + H1*R3 + H0 * R4, ++ @ ++ @ which can't be larger than 5 * (2^26 + 2^6) * (2^26 + 2^6), or ++ @ 5 * (2^52 + 2*2^32 + 2^12), which in turn is smaller than ++ @ 8 * (2^52) or 2^55. However, the value is then multiplied by ++ @ by 5, so we should be looking at 5 * 5 * (2^52 + 2^33 + 2^12), ++ @ which is less than 32 * (2^52) or 2^57. And when processing ++ @ data we are looking at triple as many addends... ++ @ ++ @ In key setup procedure pre-reduced H0 is limited by 5*4+1 and ++ @ 5*H4 - by 5*5 52-bit addends, or 57 bits. But when hashing the ++ @ input H0 is limited by (5*4+1)*3 addends, or 58 bits, while ++ @ 5*H4 by 5*5*3, or 59[!] bits. How is this relevant? vmlal.u32 ++ @ instruction accepts 2x32-bit input and writes 2x64-bit result. ++ @ This means that result of reduction have to be compressed upon ++ @ loop wrap-around. This can be done in the process of reduction ++ @ to minimize amount of instructions [as well as amount of ++ @ 128-bit instructions, which benefits low-end processors], but ++ @ one has to watch for H2 (which is narrower than H0) and 5*H4 ++ @ not being wider than 58 bits, so that result of right shift ++ @ by 26 bits fits in 32 bits. This is also useful on x86, ++ @ because it allows to use paddd in place for paddq, which ++ @ benefits Atom, where paddq is ridiculously slow. ++ ++ vshr.u64 $T0,$D3,#26 ++ vmovn.i64 $D3#lo,$D3 ++ vshr.u64 $T1,$D0,#26 ++ vmovn.i64 $D0#lo,$D0 ++ vadd.i64 $D4,$D4,$T0 @ h3 -> h4 ++ vbic.i32 $D3#lo,#0xfc000000 @ &=0x03ffffff ++ vadd.i64 $D1,$D1,$T1 @ h0 -> h1 ++ vbic.i32 $D0#lo,#0xfc000000 ++ ++ vshrn.u64 $T0#lo,$D4,#26 ++ vmovn.i64 $D4#lo,$D4 ++ vshr.u64 $T1,$D1,#26 ++ vmovn.i64 $D1#lo,$D1 ++ vadd.i64 $D2,$D2,$T1 @ h1 -> h2 ++ vbic.i32 $D4#lo,#0xfc000000 ++ vbic.i32 $D1#lo,#0xfc000000 ++ ++ vadd.i32 $D0#lo,$D0#lo,$T0#lo ++ vshl.u32 $T0#lo,$T0#lo,#2 ++ vshrn.u64 $T1#lo,$D2,#26 ++ vmovn.i64 $D2#lo,$D2 ++ vadd.i32 $D0#lo,$D0#lo,$T0#lo @ h4 -> h0 ++ vadd.i32 $D3#lo,$D3#lo,$T1#lo @ h2 -> h3 ++ vbic.i32 $D2#lo,#0xfc000000 ++ ++ vshr.u32 $T0#lo,$D0#lo,#26 ++ vbic.i32 $D0#lo,#0xfc000000 ++ vshr.u32 $T1#lo,$D3#lo,#26 ++ vbic.i32 $D3#lo,#0xfc000000 ++ vadd.i32 $D1#lo,$D1#lo,$T0#lo @ h0 -> h1 ++ vadd.i32 $D4#lo,$D4#lo,$T1#lo @ h3 -> h4 ++ ++ subs $zeros,$zeros,#1 ++ beq .Lsquare_break_neon ++ ++ add $tbl0,$ctx,#(48+0*9*4) ++ add $tbl1,$ctx,#(48+1*9*4) ++ ++ vtrn.32 $R0,$D0#lo @ r^2:r^1 ++ vtrn.32 $R2,$D2#lo ++ vtrn.32 $R3,$D3#lo ++ vtrn.32 $R1,$D1#lo ++ vtrn.32 $R4,$D4#lo ++ ++ vshl.u32 $S2,$R2,#2 @ *5 ++ vshl.u32 $S3,$R3,#2 ++ vshl.u32 $S1,$R1,#2 ++ vshl.u32 $S4,$R4,#2 ++ vadd.i32 $S2,$S2,$R2 ++ vadd.i32 $S1,$S1,$R1 ++ vadd.i32 $S3,$S3,$R3 ++ vadd.i32 $S4,$S4,$R4 ++ ++ vst4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! ++ vst4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! ++ vst4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]! ++ vst4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]! ++ vst1.32 {${S4}[0]},[$tbl0,:32] ++ vst1.32 {${S4}[1]},[$tbl1,:32] ++ ++ b .Lsquare_neon ++ ++.align 4 ++.Lsquare_break_neon: ++ add $tbl0,$ctx,#(48+2*4*9) ++ add $tbl1,$ctx,#(48+3*4*9) ++ ++ vmov $R0,$D0#lo @ r^4:r^3 ++ vshl.u32 $S1,$D1#lo,#2 @ *5 ++ vmov $R1,$D1#lo ++ vshl.u32 $S2,$D2#lo,#2 ++ vmov $R2,$D2#lo ++ vshl.u32 $S3,$D3#lo,#2 ++ vmov $R3,$D3#lo ++ vshl.u32 $S4,$D4#lo,#2 ++ vmov $R4,$D4#lo ++ vadd.i32 $S1,$S1,$D1#lo ++ vadd.i32 $S2,$S2,$D2#lo ++ vadd.i32 $S3,$S3,$D3#lo ++ vadd.i32 $S4,$S4,$D4#lo ++ ++ vst4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! ++ vst4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! ++ vst4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]! ++ vst4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]! ++ vst1.32 {${S4}[0]},[$tbl0] ++ vst1.32 {${S4}[1]},[$tbl1] ++ ++.Lno_init_neon: ++ ret @ bx lr ++.size poly1305_init_neon,.-poly1305_init_neon ++ ++.type poly1305_blocks_neon,%function ++.align 5 ++poly1305_blocks_neon: ++.Lpoly1305_blocks_neon: ++ ldr ip,[$ctx,#36] @ is_base2_26 ++ ++ cmp $len,#64 ++ blo .Lpoly1305_blocks ++ ++ stmdb sp!,{r4-r7} ++ vstmdb sp!,{d8-d15} @ ABI specification says so ++ ++ tst ip,ip @ is_base2_26? ++ bne .Lbase2_26_neon ++ ++ stmdb sp!,{r1-r3,lr} ++ bl .Lpoly1305_init_neon ++ ++ ldr r4,[$ctx,#0] @ load hash value base 2^32 ++ ldr r5,[$ctx,#4] ++ ldr r6,[$ctx,#8] ++ ldr r7,[$ctx,#12] ++ ldr ip,[$ctx,#16] ++ ++ and r2,r4,#0x03ffffff @ base 2^32 -> base 2^26 ++ mov r3,r4,lsr#26 ++ veor $D0#lo,$D0#lo,$D0#lo ++ mov r4,r5,lsr#20 ++ orr r3,r3,r5,lsl#6 ++ veor $D1#lo,$D1#lo,$D1#lo ++ mov r5,r6,lsr#14 ++ orr r4,r4,r6,lsl#12 ++ veor $D2#lo,$D2#lo,$D2#lo ++ mov r6,r7,lsr#8 ++ orr r5,r5,r7,lsl#18 ++ veor $D3#lo,$D3#lo,$D3#lo ++ and r3,r3,#0x03ffffff ++ orr r6,r6,ip,lsl#24 ++ veor $D4#lo,$D4#lo,$D4#lo ++ and r4,r4,#0x03ffffff ++ mov r1,#1 ++ and r5,r5,#0x03ffffff ++ str r1,[$ctx,#36] @ set is_base2_26 ++ ++ vmov.32 $D0#lo[0],r2 ++ vmov.32 $D1#lo[0],r3 ++ vmov.32 $D2#lo[0],r4 ++ vmov.32 $D3#lo[0],r5 ++ vmov.32 $D4#lo[0],r6 ++ adr $zeros,.Lzeros ++ ++ ldmia sp!,{r1-r3,lr} ++ b .Lhash_loaded ++ ++.align 4 ++.Lbase2_26_neon: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ load hash value ++ ++ veor $D0#lo,$D0#lo,$D0#lo ++ veor $D1#lo,$D1#lo,$D1#lo ++ veor $D2#lo,$D2#lo,$D2#lo ++ veor $D3#lo,$D3#lo,$D3#lo ++ veor $D4#lo,$D4#lo,$D4#lo ++ vld4.32 {$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]! ++ adr $zeros,.Lzeros ++ vld1.32 {$D4#lo[0]},[$ctx] ++ sub $ctx,$ctx,#16 @ rewind ++ ++.Lhash_loaded: ++ add $in2,$inp,#32 ++ mov $padbit,$padbit,lsl#24 ++ tst $len,#31 ++ beq .Leven ++ ++ vld4.32 {$H0#lo[0],$H1#lo[0],$H2#lo[0],$H3#lo[0]},[$inp]! ++ vmov.32 $H4#lo[0],$padbit ++ sub $len,$len,#16 ++ add $in2,$inp,#32 ++ ++# ifdef __ARMEB__ ++ vrev32.8 $H0,$H0 ++ vrev32.8 $H3,$H3 ++ vrev32.8 $H1,$H1 ++ vrev32.8 $H2,$H2 ++# endif ++ vsri.u32 $H4#lo,$H3#lo,#8 @ base 2^32 -> base 2^26 ++ vshl.u32 $H3#lo,$H3#lo,#18 ++ ++ vsri.u32 $H3#lo,$H2#lo,#14 ++ vshl.u32 $H2#lo,$H2#lo,#12 ++ vadd.i32 $H4#hi,$H4#lo,$D4#lo @ add hash value and move to #hi ++ ++ vbic.i32 $H3#lo,#0xfc000000 ++ vsri.u32 $H2#lo,$H1#lo,#20 ++ vshl.u32 $H1#lo,$H1#lo,#6 ++ ++ vbic.i32 $H2#lo,#0xfc000000 ++ vsri.u32 $H1#lo,$H0#lo,#26 ++ vadd.i32 $H3#hi,$H3#lo,$D3#lo ++ ++ vbic.i32 $H0#lo,#0xfc000000 ++ vbic.i32 $H1#lo,#0xfc000000 ++ vadd.i32 $H2#hi,$H2#lo,$D2#lo ++ ++ vadd.i32 $H0#hi,$H0#lo,$D0#lo ++ vadd.i32 $H1#hi,$H1#lo,$D1#lo ++ ++ mov $tbl1,$zeros ++ add $tbl0,$ctx,#48 ++ ++ cmp $len,$len ++ b .Long_tail ++ ++.align 4 ++.Leven: ++ subs $len,$len,#64 ++ it lo ++ movlo $in2,$zeros ++ ++ vmov.i32 $H4,#1<<24 @ padbit, yes, always ++ vld4.32 {$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp] @ inp[0:1] ++ add $inp,$inp,#64 ++ vld4.32 {$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2] @ inp[2:3] (or 0) ++ add $in2,$in2,#64 ++ itt hi ++ addhi $tbl1,$ctx,#(48+1*9*4) ++ addhi $tbl0,$ctx,#(48+3*9*4) ++ ++# ifdef __ARMEB__ ++ vrev32.8 $H0,$H0 ++ vrev32.8 $H3,$H3 ++ vrev32.8 $H1,$H1 ++ vrev32.8 $H2,$H2 ++# endif ++ vsri.u32 $H4,$H3,#8 @ base 2^32 -> base 2^26 ++ vshl.u32 $H3,$H3,#18 ++ ++ vsri.u32 $H3,$H2,#14 ++ vshl.u32 $H2,$H2,#12 ++ ++ vbic.i32 $H3,#0xfc000000 ++ vsri.u32 $H2,$H1,#20 ++ vshl.u32 $H1,$H1,#6 ++ ++ vbic.i32 $H2,#0xfc000000 ++ vsri.u32 $H1,$H0,#26 ++ ++ vbic.i32 $H0,#0xfc000000 ++ vbic.i32 $H1,#0xfc000000 ++ ++ bls .Lskip_loop ++ ++ vld4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! @ load r^2 ++ vld4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! @ load r^4 ++ vld4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]! ++ vld4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]! ++ b .Loop_neon ++ ++.align 5 ++.Loop_neon: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2 ++ @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r ++ @ \___________________/ ++ @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2 ++ @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r ++ @ \___________________/ \____________________/ ++ @ ++ @ Note that we start with inp[2:3]*r^2. This is because it ++ @ doesn't depend on reduction in previous iteration. ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ @ d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ @ d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ @ d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ inp[2:3]*r^2 ++ ++ vadd.i32 $H2#lo,$H2#lo,$D2#lo @ accumulate inp[0:1] ++ vmull.u32 $D2,$H2#hi,${R0}[1] ++ vadd.i32 $H0#lo,$H0#lo,$D0#lo ++ vmull.u32 $D0,$H0#hi,${R0}[1] ++ vadd.i32 $H3#lo,$H3#lo,$D3#lo ++ vmull.u32 $D3,$H3#hi,${R0}[1] ++ vmlal.u32 $D2,$H1#hi,${R1}[1] ++ vadd.i32 $H1#lo,$H1#lo,$D1#lo ++ vmull.u32 $D1,$H1#hi,${R0}[1] ++ ++ vadd.i32 $H4#lo,$H4#lo,$D4#lo ++ vmull.u32 $D4,$H4#hi,${R0}[1] ++ subs $len,$len,#64 ++ vmlal.u32 $D0,$H4#hi,${S1}[1] ++ it lo ++ movlo $in2,$zeros ++ vmlal.u32 $D3,$H2#hi,${R1}[1] ++ vld1.32 ${S4}[1],[$tbl1,:32] ++ vmlal.u32 $D1,$H0#hi,${R1}[1] ++ vmlal.u32 $D4,$H3#hi,${R1}[1] ++ ++ vmlal.u32 $D0,$H3#hi,${S2}[1] ++ vmlal.u32 $D3,$H1#hi,${R2}[1] ++ vmlal.u32 $D4,$H2#hi,${R2}[1] ++ vmlal.u32 $D1,$H4#hi,${S2}[1] ++ vmlal.u32 $D2,$H0#hi,${R2}[1] ++ ++ vmlal.u32 $D3,$H0#hi,${R3}[1] ++ vmlal.u32 $D0,$H2#hi,${S3}[1] ++ vmlal.u32 $D4,$H1#hi,${R3}[1] ++ vmlal.u32 $D1,$H3#hi,${S3}[1] ++ vmlal.u32 $D2,$H4#hi,${S3}[1] ++ ++ vmlal.u32 $D3,$H4#hi,${S4}[1] ++ vmlal.u32 $D0,$H1#hi,${S4}[1] ++ vmlal.u32 $D4,$H0#hi,${R4}[1] ++ vmlal.u32 $D1,$H2#hi,${S4}[1] ++ vmlal.u32 $D2,$H3#hi,${S4}[1] ++ ++ vld4.32 {$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2] @ inp[2:3] (or 0) ++ add $in2,$in2,#64 ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ (hash+inp[0:1])*r^4 and accumulate ++ ++ vmlal.u32 $D3,$H3#lo,${R0}[0] ++ vmlal.u32 $D0,$H0#lo,${R0}[0] ++ vmlal.u32 $D4,$H4#lo,${R0}[0] ++ vmlal.u32 $D1,$H1#lo,${R0}[0] ++ vmlal.u32 $D2,$H2#lo,${R0}[0] ++ vld1.32 ${S4}[0],[$tbl0,:32] ++ ++ vmlal.u32 $D3,$H2#lo,${R1}[0] ++ vmlal.u32 $D0,$H4#lo,${S1}[0] ++ vmlal.u32 $D4,$H3#lo,${R1}[0] ++ vmlal.u32 $D1,$H0#lo,${R1}[0] ++ vmlal.u32 $D2,$H1#lo,${R1}[0] ++ ++ vmlal.u32 $D3,$H1#lo,${R2}[0] ++ vmlal.u32 $D0,$H3#lo,${S2}[0] ++ vmlal.u32 $D4,$H2#lo,${R2}[0] ++ vmlal.u32 $D1,$H4#lo,${S2}[0] ++ vmlal.u32 $D2,$H0#lo,${R2}[0] ++ ++ vmlal.u32 $D3,$H0#lo,${R3}[0] ++ vmlal.u32 $D0,$H2#lo,${S3}[0] ++ vmlal.u32 $D4,$H1#lo,${R3}[0] ++ vmlal.u32 $D1,$H3#lo,${S3}[0] ++ vmlal.u32 $D3,$H4#lo,${S4}[0] ++ ++ vmlal.u32 $D2,$H4#lo,${S3}[0] ++ vmlal.u32 $D0,$H1#lo,${S4}[0] ++ vmlal.u32 $D4,$H0#lo,${R4}[0] ++ vmov.i32 $H4,#1<<24 @ padbit, yes, always ++ vmlal.u32 $D1,$H2#lo,${S4}[0] ++ vmlal.u32 $D2,$H3#lo,${S4}[0] ++ ++ vld4.32 {$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp] @ inp[0:1] ++ add $inp,$inp,#64 ++# ifdef __ARMEB__ ++ vrev32.8 $H0,$H0 ++ vrev32.8 $H1,$H1 ++ vrev32.8 $H2,$H2 ++ vrev32.8 $H3,$H3 ++# endif ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ lazy reduction interleaved with base 2^32 -> base 2^26 of ++ @ inp[0:3] previously loaded to $H0-$H3 and smashed to $H0-$H4. ++ ++ vshr.u64 $T0,$D3,#26 ++ vmovn.i64 $D3#lo,$D3 ++ vshr.u64 $T1,$D0,#26 ++ vmovn.i64 $D0#lo,$D0 ++ vadd.i64 $D4,$D4,$T0 @ h3 -> h4 ++ vbic.i32 $D3#lo,#0xfc000000 ++ vsri.u32 $H4,$H3,#8 @ base 2^32 -> base 2^26 ++ vadd.i64 $D1,$D1,$T1 @ h0 -> h1 ++ vshl.u32 $H3,$H3,#18 ++ vbic.i32 $D0#lo,#0xfc000000 ++ ++ vshrn.u64 $T0#lo,$D4,#26 ++ vmovn.i64 $D4#lo,$D4 ++ vshr.u64 $T1,$D1,#26 ++ vmovn.i64 $D1#lo,$D1 ++ vadd.i64 $D2,$D2,$T1 @ h1 -> h2 ++ vsri.u32 $H3,$H2,#14 ++ vbic.i32 $D4#lo,#0xfc000000 ++ vshl.u32 $H2,$H2,#12 ++ vbic.i32 $D1#lo,#0xfc000000 ++ ++ vadd.i32 $D0#lo,$D0#lo,$T0#lo ++ vshl.u32 $T0#lo,$T0#lo,#2 ++ vbic.i32 $H3,#0xfc000000 ++ vshrn.u64 $T1#lo,$D2,#26 ++ vmovn.i64 $D2#lo,$D2 ++ vaddl.u32 $D0,$D0#lo,$T0#lo @ h4 -> h0 [widen for a sec] ++ vsri.u32 $H2,$H1,#20 ++ vadd.i32 $D3#lo,$D3#lo,$T1#lo @ h2 -> h3 ++ vshl.u32 $H1,$H1,#6 ++ vbic.i32 $D2#lo,#0xfc000000 ++ vbic.i32 $H2,#0xfc000000 ++ ++ vshrn.u64 $T0#lo,$D0,#26 @ re-narrow ++ vmovn.i64 $D0#lo,$D0 ++ vsri.u32 $H1,$H0,#26 ++ vbic.i32 $H0,#0xfc000000 ++ vshr.u32 $T1#lo,$D3#lo,#26 ++ vbic.i32 $D3#lo,#0xfc000000 ++ vbic.i32 $D0#lo,#0xfc000000 ++ vadd.i32 $D1#lo,$D1#lo,$T0#lo @ h0 -> h1 ++ vadd.i32 $D4#lo,$D4#lo,$T1#lo @ h3 -> h4 ++ vbic.i32 $H1,#0xfc000000 ++ ++ bhi .Loop_neon ++ ++.Lskip_loop: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1 ++ ++ add $tbl1,$ctx,#(48+0*9*4) ++ add $tbl0,$ctx,#(48+1*9*4) ++ adds $len,$len,#32 ++ it ne ++ movne $len,#0 ++ bne .Long_tail ++ ++ vadd.i32 $H2#hi,$H2#lo,$D2#lo @ add hash value and move to #hi ++ vadd.i32 $H0#hi,$H0#lo,$D0#lo ++ vadd.i32 $H3#hi,$H3#lo,$D3#lo ++ vadd.i32 $H1#hi,$H1#lo,$D1#lo ++ vadd.i32 $H4#hi,$H4#lo,$D4#lo ++ ++.Long_tail: ++ vld4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! @ load r^1 ++ vld4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! @ load r^2 ++ ++ vadd.i32 $H2#lo,$H2#lo,$D2#lo @ can be redundant ++ vmull.u32 $D2,$H2#hi,$R0 ++ vadd.i32 $H0#lo,$H0#lo,$D0#lo ++ vmull.u32 $D0,$H0#hi,$R0 ++ vadd.i32 $H3#lo,$H3#lo,$D3#lo ++ vmull.u32 $D3,$H3#hi,$R0 ++ vadd.i32 $H1#lo,$H1#lo,$D1#lo ++ vmull.u32 $D1,$H1#hi,$R0 ++ vadd.i32 $H4#lo,$H4#lo,$D4#lo ++ vmull.u32 $D4,$H4#hi,$R0 ++ ++ vmlal.u32 $D0,$H4#hi,$S1 ++ vld4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]! ++ vmlal.u32 $D3,$H2#hi,$R1 ++ vld4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]! ++ vmlal.u32 $D1,$H0#hi,$R1 ++ vmlal.u32 $D4,$H3#hi,$R1 ++ vmlal.u32 $D2,$H1#hi,$R1 ++ ++ vmlal.u32 $D3,$H1#hi,$R2 ++ vld1.32 ${S4}[1],[$tbl1,:32] ++ vmlal.u32 $D0,$H3#hi,$S2 ++ vld1.32 ${S4}[0],[$tbl0,:32] ++ vmlal.u32 $D4,$H2#hi,$R2 ++ vmlal.u32 $D1,$H4#hi,$S2 ++ vmlal.u32 $D2,$H0#hi,$R2 ++ ++ vmlal.u32 $D3,$H0#hi,$R3 ++ it ne ++ addne $tbl1,$ctx,#(48+2*9*4) ++ vmlal.u32 $D0,$H2#hi,$S3 ++ it ne ++ addne $tbl0,$ctx,#(48+3*9*4) ++ vmlal.u32 $D4,$H1#hi,$R3 ++ vmlal.u32 $D1,$H3#hi,$S3 ++ vmlal.u32 $D2,$H4#hi,$S3 ++ ++ vmlal.u32 $D3,$H4#hi,$S4 ++ vorn $MASK,$MASK,$MASK @ all-ones, can be redundant ++ vmlal.u32 $D0,$H1#hi,$S4 ++ vshr.u64 $MASK,$MASK,#38 ++ vmlal.u32 $D4,$H0#hi,$R4 ++ vmlal.u32 $D1,$H2#hi,$S4 ++ vmlal.u32 $D2,$H3#hi,$S4 ++ ++ beq .Lshort_tail ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ (hash+inp[0:1])*r^4:r^3 and accumulate ++ ++ vld4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! @ load r^3 ++ vld4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! @ load r^4 ++ ++ vmlal.u32 $D2,$H2#lo,$R0 ++ vmlal.u32 $D0,$H0#lo,$R0 ++ vmlal.u32 $D3,$H3#lo,$R0 ++ vmlal.u32 $D1,$H1#lo,$R0 ++ vmlal.u32 $D4,$H4#lo,$R0 ++ ++ vmlal.u32 $D0,$H4#lo,$S1 ++ vld4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]! ++ vmlal.u32 $D3,$H2#lo,$R1 ++ vld4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]! ++ vmlal.u32 $D1,$H0#lo,$R1 ++ vmlal.u32 $D4,$H3#lo,$R1 ++ vmlal.u32 $D2,$H1#lo,$R1 ++ ++ vmlal.u32 $D3,$H1#lo,$R2 ++ vld1.32 ${S4}[1],[$tbl1,:32] ++ vmlal.u32 $D0,$H3#lo,$S2 ++ vld1.32 ${S4}[0],[$tbl0,:32] ++ vmlal.u32 $D4,$H2#lo,$R2 ++ vmlal.u32 $D1,$H4#lo,$S2 ++ vmlal.u32 $D2,$H0#lo,$R2 ++ ++ vmlal.u32 $D3,$H0#lo,$R3 ++ vmlal.u32 $D0,$H2#lo,$S3 ++ vmlal.u32 $D4,$H1#lo,$R3 ++ vmlal.u32 $D1,$H3#lo,$S3 ++ vmlal.u32 $D2,$H4#lo,$S3 ++ ++ vmlal.u32 $D3,$H4#lo,$S4 ++ vorn $MASK,$MASK,$MASK @ all-ones ++ vmlal.u32 $D0,$H1#lo,$S4 ++ vshr.u64 $MASK,$MASK,#38 ++ vmlal.u32 $D4,$H0#lo,$R4 ++ vmlal.u32 $D1,$H2#lo,$S4 ++ vmlal.u32 $D2,$H3#lo,$S4 ++ ++.Lshort_tail: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ horizontal addition ++ ++ vadd.i64 $D3#lo,$D3#lo,$D3#hi ++ vadd.i64 $D0#lo,$D0#lo,$D0#hi ++ vadd.i64 $D4#lo,$D4#lo,$D4#hi ++ vadd.i64 $D1#lo,$D1#lo,$D1#hi ++ vadd.i64 $D2#lo,$D2#lo,$D2#hi ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ lazy reduction, but without narrowing ++ ++ vshr.u64 $T0,$D3,#26 ++ vand.i64 $D3,$D3,$MASK ++ vshr.u64 $T1,$D0,#26 ++ vand.i64 $D0,$D0,$MASK ++ vadd.i64 $D4,$D4,$T0 @ h3 -> h4 ++ vadd.i64 $D1,$D1,$T1 @ h0 -> h1 ++ ++ vshr.u64 $T0,$D4,#26 ++ vand.i64 $D4,$D4,$MASK ++ vshr.u64 $T1,$D1,#26 ++ vand.i64 $D1,$D1,$MASK ++ vadd.i64 $D2,$D2,$T1 @ h1 -> h2 ++ ++ vadd.i64 $D0,$D0,$T0 ++ vshl.u64 $T0,$T0,#2 ++ vshr.u64 $T1,$D2,#26 ++ vand.i64 $D2,$D2,$MASK ++ vadd.i64 $D0,$D0,$T0 @ h4 -> h0 ++ vadd.i64 $D3,$D3,$T1 @ h2 -> h3 ++ ++ vshr.u64 $T0,$D0,#26 ++ vand.i64 $D0,$D0,$MASK ++ vshr.u64 $T1,$D3,#26 ++ vand.i64 $D3,$D3,$MASK ++ vadd.i64 $D1,$D1,$T0 @ h0 -> h1 ++ vadd.i64 $D4,$D4,$T1 @ h3 -> h4 ++ ++ cmp $len,#0 ++ bne .Leven ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ store hash value ++ ++ vst4.32 {$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]! ++ vst1.32 {$D4#lo[0]},[$ctx] ++ ++ vldmia sp!,{d8-d15} @ epilogue ++ ldmia sp!,{r4-r7} ++ ret @ bx lr ++.size poly1305_blocks_neon,.-poly1305_blocks_neon ++ ++.align 5 ++.Lzeros: ++.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ++#ifndef __KERNEL__ ++.LOPENSSL_armcap: ++# ifdef _WIN32 ++.word OPENSSL_armcap_P ++# else ++.word OPENSSL_armcap_P-.Lpoly1305_init ++# endif ++.comm OPENSSL_armcap_P,4,4 ++.hidden OPENSSL_armcap_P ++#endif ++#endif ++___ ++} } ++$code.=<<___; ++.asciz "Poly1305 for ARMv4/NEON, CRYPTOGAMS by \@dot-asm" ++.align 2 ++___ ++ ++foreach (split("\n",$code)) { ++ s/\`([^\`]*)\`/eval $1/geo; ++ ++ s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo or ++ s/\bret\b/bx lr/go or ++ s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4 ++ ++ print $_,"\n"; ++} ++close STDOUT; # enforce flush +--- /dev/null ++++ b/arch/arm/crypto/poly1305-core.S_shipped +@@ -0,0 +1,1158 @@ ++#ifndef __KERNEL__ ++# include "arm_arch.h" ++#else ++# define __ARM_ARCH__ __LINUX_ARM_ARCH__ ++# define __ARM_MAX_ARCH__ __LINUX_ARM_ARCH__ ++# define poly1305_init poly1305_init_arm ++# define poly1305_blocks poly1305_blocks_arm ++# define poly1305_emit poly1305_emit_arm ++.globl poly1305_blocks_neon ++#endif ++ ++#if defined(__thumb2__) ++.syntax unified ++.thumb ++#else ++.code 32 ++#endif ++ ++.text ++ ++.globl poly1305_emit ++.globl poly1305_blocks ++.globl poly1305_init ++.type poly1305_init,%function ++.align 5 ++poly1305_init: ++.Lpoly1305_init: ++ stmdb sp!,{r4-r11} ++ ++ eor r3,r3,r3 ++ cmp r1,#0 ++ str r3,[r0,#0] @ zero hash value ++ str r3,[r0,#4] ++ str r3,[r0,#8] ++ str r3,[r0,#12] ++ str r3,[r0,#16] ++ str r3,[r0,#36] @ clear is_base2_26 ++ add r0,r0,#20 ++ ++#ifdef __thumb2__ ++ it eq ++#endif ++ moveq r0,#0 ++ beq .Lno_key ++ ++#if __ARM_MAX_ARCH__>=7 ++ mov r3,#-1 ++ str r3,[r0,#28] @ impossible key power value ++# ifndef __KERNEL__ ++ adr r11,.Lpoly1305_init ++ ldr r12,.LOPENSSL_armcap ++# endif ++#endif ++ ldrb r4,[r1,#0] ++ mov r10,#0x0fffffff ++ ldrb r5,[r1,#1] ++ and r3,r10,#-4 @ 0x0ffffffc ++ ldrb r6,[r1,#2] ++ ldrb r7,[r1,#3] ++ orr r4,r4,r5,lsl#8 ++ ldrb r5,[r1,#4] ++ orr r4,r4,r6,lsl#16 ++ ldrb r6,[r1,#5] ++ orr r4,r4,r7,lsl#24 ++ ldrb r7,[r1,#6] ++ and r4,r4,r10 ++ ++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ++# if !defined(_WIN32) ++ ldr r12,[r11,r12] @ OPENSSL_armcap_P ++# endif ++# if defined(__APPLE__) || defined(_WIN32) ++ ldr r12,[r12] ++# endif ++#endif ++ ldrb r8,[r1,#7] ++ orr r5,r5,r6,lsl#8 ++ ldrb r6,[r1,#8] ++ orr r5,r5,r7,lsl#16 ++ ldrb r7,[r1,#9] ++ orr r5,r5,r8,lsl#24 ++ ldrb r8,[r1,#10] ++ and r5,r5,r3 ++ ++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ++ tst r12,#ARMV7_NEON @ check for NEON ++# ifdef __thumb2__ ++ adr r9,.Lpoly1305_blocks_neon ++ adr r11,.Lpoly1305_blocks ++ it ne ++ movne r11,r9 ++ adr r12,.Lpoly1305_emit ++ orr r11,r11,#1 @ thumb-ify addresses ++ orr r12,r12,#1 ++# else ++ add r12,r11,#(.Lpoly1305_emit-.Lpoly1305_init) ++ ite eq ++ addeq r11,r11,#(.Lpoly1305_blocks-.Lpoly1305_init) ++ addne r11,r11,#(.Lpoly1305_blocks_neon-.Lpoly1305_init) ++# endif ++#endif ++ ldrb r9,[r1,#11] ++ orr r6,r6,r7,lsl#8 ++ ldrb r7,[r1,#12] ++ orr r6,r6,r8,lsl#16 ++ ldrb r8,[r1,#13] ++ orr r6,r6,r9,lsl#24 ++ ldrb r9,[r1,#14] ++ and r6,r6,r3 ++ ++ ldrb r10,[r1,#15] ++ orr r7,r7,r8,lsl#8 ++ str r4,[r0,#0] ++ orr r7,r7,r9,lsl#16 ++ str r5,[r0,#4] ++ orr r7,r7,r10,lsl#24 ++ str r6,[r0,#8] ++ and r7,r7,r3 ++ str r7,[r0,#12] ++#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ++ stmia r2,{r11,r12} @ fill functions table ++ mov r0,#1 ++#else ++ mov r0,#0 ++#endif ++.Lno_key: ++ ldmia sp!,{r4-r11} ++#if __ARM_ARCH__>=5 ++ bx lr @ bx lr ++#else ++ tst lr,#1 ++ moveq pc,lr @ be binary compatible with V4, yet ++ .word 0xe12fff1e @ interoperable with Thumb ISA:-) ++#endif ++.size poly1305_init,.-poly1305_init ++.type poly1305_blocks,%function ++.align 5 ++poly1305_blocks: ++.Lpoly1305_blocks: ++ stmdb sp!,{r3-r11,lr} ++ ++ ands r2,r2,#-16 ++ beq .Lno_data ++ ++ add r2,r2,r1 @ end pointer ++ sub sp,sp,#32 ++ ++#if __ARM_ARCH__<7 ++ ldmia r0,{r4-r12} @ load context ++ add r0,r0,#20 ++ str r2,[sp,#16] @ offload stuff ++ str r0,[sp,#12] ++#else ++ ldr lr,[r0,#36] @ is_base2_26 ++ ldmia r0!,{r4-r8} @ load hash value ++ str r2,[sp,#16] @ offload stuff ++ str r0,[sp,#12] ++ ++ adds r9,r4,r5,lsl#26 @ base 2^26 -> base 2^32 ++ mov r10,r5,lsr#6 ++ adcs r10,r10,r6,lsl#20 ++ mov r11,r6,lsr#12 ++ adcs r11,r11,r7,lsl#14 ++ mov r12,r7,lsr#18 ++ adcs r12,r12,r8,lsl#8 ++ mov r2,#0 ++ teq lr,#0 ++ str r2,[r0,#16] @ clear is_base2_26 ++ adc r2,r2,r8,lsr#24 ++ ++ itttt ne ++ movne r4,r9 @ choose between radixes ++ movne r5,r10 ++ movne r6,r11 ++ movne r7,r12 ++ ldmia r0,{r9-r12} @ load key ++ it ne ++ movne r8,r2 ++#endif ++ ++ mov lr,r1 ++ cmp r3,#0 ++ str r10,[sp,#20] ++ str r11,[sp,#24] ++ str r12,[sp,#28] ++ b .Loop ++ ++.align 4 ++.Loop: ++#if __ARM_ARCH__<7 ++ ldrb r0,[lr],#16 @ load input ++# ifdef __thumb2__ ++ it hi ++# endif ++ addhi r8,r8,#1 @ 1<<128 ++ ldrb r1,[lr,#-15] ++ ldrb r2,[lr,#-14] ++ ldrb r3,[lr,#-13] ++ orr r1,r0,r1,lsl#8 ++ ldrb r0,[lr,#-12] ++ orr r2,r1,r2,lsl#16 ++ ldrb r1,[lr,#-11] ++ orr r3,r2,r3,lsl#24 ++ ldrb r2,[lr,#-10] ++ adds r4,r4,r3 @ accumulate input ++ ++ ldrb r3,[lr,#-9] ++ orr r1,r0,r1,lsl#8 ++ ldrb r0,[lr,#-8] ++ orr r2,r1,r2,lsl#16 ++ ldrb r1,[lr,#-7] ++ orr r3,r2,r3,lsl#24 ++ ldrb r2,[lr,#-6] ++ adcs r5,r5,r3 ++ ++ ldrb r3,[lr,#-5] ++ orr r1,r0,r1,lsl#8 ++ ldrb r0,[lr,#-4] ++ orr r2,r1,r2,lsl#16 ++ ldrb r1,[lr,#-3] ++ orr r3,r2,r3,lsl#24 ++ ldrb r2,[lr,#-2] ++ adcs r6,r6,r3 ++ ++ ldrb r3,[lr,#-1] ++ orr r1,r0,r1,lsl#8 ++ str lr,[sp,#8] @ offload input pointer ++ orr r2,r1,r2,lsl#16 ++ add r10,r10,r10,lsr#2 ++ orr r3,r2,r3,lsl#24 ++#else ++ ldr r0,[lr],#16 @ load input ++ it hi ++ addhi r8,r8,#1 @ padbit ++ ldr r1,[lr,#-12] ++ ldr r2,[lr,#-8] ++ ldr r3,[lr,#-4] ++# ifdef __ARMEB__ ++ rev r0,r0 ++ rev r1,r1 ++ rev r2,r2 ++ rev r3,r3 ++# endif ++ adds r4,r4,r0 @ accumulate input ++ str lr,[sp,#8] @ offload input pointer ++ adcs r5,r5,r1 ++ add r10,r10,r10,lsr#2 ++ adcs r6,r6,r2 ++#endif ++ add r11,r11,r11,lsr#2 ++ adcs r7,r7,r3 ++ add r12,r12,r12,lsr#2 ++ ++ umull r2,r3,r5,r9 ++ adc r8,r8,#0 ++ umull r0,r1,r4,r9 ++ umlal r2,r3,r8,r10 ++ umlal r0,r1,r7,r10 ++ ldr r10,[sp,#20] @ reload r10 ++ umlal r2,r3,r6,r12 ++ umlal r0,r1,r5,r12 ++ umlal r2,r3,r7,r11 ++ umlal r0,r1,r6,r11 ++ umlal r2,r3,r4,r10 ++ str r0,[sp,#0] @ future r4 ++ mul r0,r11,r8 ++ ldr r11,[sp,#24] @ reload r11 ++ adds r2,r2,r1 @ d1+=d0>>32 ++ eor r1,r1,r1 ++ adc lr,r3,#0 @ future r6 ++ str r2,[sp,#4] @ future r5 ++ ++ mul r2,r12,r8 ++ eor r3,r3,r3 ++ umlal r0,r1,r7,r12 ++ ldr r12,[sp,#28] @ reload r12 ++ umlal r2,r3,r7,r9 ++ umlal r0,r1,r6,r9 ++ umlal r2,r3,r6,r10 ++ umlal r0,r1,r5,r10 ++ umlal r2,r3,r5,r11 ++ umlal r0,r1,r4,r11 ++ umlal r2,r3,r4,r12 ++ ldr r4,[sp,#0] ++ mul r8,r9,r8 ++ ldr r5,[sp,#4] ++ ++ adds r6,lr,r0 @ d2+=d1>>32 ++ ldr lr,[sp,#8] @ reload input pointer ++ adc r1,r1,#0 ++ adds r7,r2,r1 @ d3+=d2>>32 ++ ldr r0,[sp,#16] @ reload end pointer ++ adc r3,r3,#0 ++ add r8,r8,r3 @ h4+=d3>>32 ++ ++ and r1,r8,#-4 ++ and r8,r8,#3 ++ add r1,r1,r1,lsr#2 @ *=5 ++ adds r4,r4,r1 ++ adcs r5,r5,#0 ++ adcs r6,r6,#0 ++ adcs r7,r7,#0 ++ adc r8,r8,#0 ++ ++ cmp r0,lr @ done yet? ++ bhi .Loop ++ ++ ldr r0,[sp,#12] ++ add sp,sp,#32 ++ stmdb r0,{r4-r8} @ store the result ++ ++.Lno_data: ++#if __ARM_ARCH__>=5 ++ ldmia sp!,{r3-r11,pc} ++#else ++ ldmia sp!,{r3-r11,lr} ++ tst lr,#1 ++ moveq pc,lr @ be binary compatible with V4, yet ++ .word 0xe12fff1e @ interoperable with Thumb ISA:-) ++#endif ++.size poly1305_blocks,.-poly1305_blocks ++.type poly1305_emit,%function ++.align 5 ++poly1305_emit: ++.Lpoly1305_emit: ++ stmdb sp!,{r4-r11} ++ ++ ldmia r0,{r3-r7} ++ ++#if __ARM_ARCH__>=7 ++ ldr ip,[r0,#36] @ is_base2_26 ++ ++ adds r8,r3,r4,lsl#26 @ base 2^26 -> base 2^32 ++ mov r9,r4,lsr#6 ++ adcs r9,r9,r5,lsl#20 ++ mov r10,r5,lsr#12 ++ adcs r10,r10,r6,lsl#14 ++ mov r11,r6,lsr#18 ++ adcs r11,r11,r7,lsl#8 ++ mov r0,#0 ++ adc r0,r0,r7,lsr#24 ++ ++ tst ip,ip ++ itttt ne ++ movne r3,r8 ++ movne r4,r9 ++ movne r5,r10 ++ movne r6,r11 ++ it ne ++ movne r7,r0 ++#endif ++ ++ adds r8,r3,#5 @ compare to modulus ++ adcs r9,r4,#0 ++ adcs r10,r5,#0 ++ adcs r11,r6,#0 ++ adc r0,r7,#0 ++ tst r0,#4 @ did it carry/borrow? ++ ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne r3,r8 ++ ldr r8,[r2,#0] ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne r4,r9 ++ ldr r9,[r2,#4] ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne r5,r10 ++ ldr r10,[r2,#8] ++#ifdef __thumb2__ ++ it ne ++#endif ++ movne r6,r11 ++ ldr r11,[r2,#12] ++ ++ adds r3,r3,r8 ++ adcs r4,r4,r9 ++ adcs r5,r5,r10 ++ adc r6,r6,r11 ++ ++#if __ARM_ARCH__>=7 ++# ifdef __ARMEB__ ++ rev r3,r3 ++ rev r4,r4 ++ rev r5,r5 ++ rev r6,r6 ++# endif ++ str r3,[r1,#0] ++ str r4,[r1,#4] ++ str r5,[r1,#8] ++ str r6,[r1,#12] ++#else ++ strb r3,[r1,#0] ++ mov r3,r3,lsr#8 ++ strb r4,[r1,#4] ++ mov r4,r4,lsr#8 ++ strb r5,[r1,#8] ++ mov r5,r5,lsr#8 ++ strb r6,[r1,#12] ++ mov r6,r6,lsr#8 ++ ++ strb r3,[r1,#1] ++ mov r3,r3,lsr#8 ++ strb r4,[r1,#5] ++ mov r4,r4,lsr#8 ++ strb r5,[r1,#9] ++ mov r5,r5,lsr#8 ++ strb r6,[r1,#13] ++ mov r6,r6,lsr#8 ++ ++ strb r3,[r1,#2] ++ mov r3,r3,lsr#8 ++ strb r4,[r1,#6] ++ mov r4,r4,lsr#8 ++ strb r5,[r1,#10] ++ mov r5,r5,lsr#8 ++ strb r6,[r1,#14] ++ mov r6,r6,lsr#8 ++ ++ strb r3,[r1,#3] ++ strb r4,[r1,#7] ++ strb r5,[r1,#11] ++ strb r6,[r1,#15] ++#endif ++ ldmia sp!,{r4-r11} ++#if __ARM_ARCH__>=5 ++ bx lr @ bx lr ++#else ++ tst lr,#1 ++ moveq pc,lr @ be binary compatible with V4, yet ++ .word 0xe12fff1e @ interoperable with Thumb ISA:-) ++#endif ++.size poly1305_emit,.-poly1305_emit ++#if __ARM_MAX_ARCH__>=7 ++.fpu neon ++ ++.type poly1305_init_neon,%function ++.align 5 ++poly1305_init_neon: ++.Lpoly1305_init_neon: ++ ldr r3,[r0,#48] @ first table element ++ cmp r3,#-1 @ is value impossible? ++ bne .Lno_init_neon ++ ++ ldr r4,[r0,#20] @ load key base 2^32 ++ ldr r5,[r0,#24] ++ ldr r6,[r0,#28] ++ ldr r7,[r0,#32] ++ ++ and r2,r4,#0x03ffffff @ base 2^32 -> base 2^26 ++ mov r3,r4,lsr#26 ++ mov r4,r5,lsr#20 ++ orr r3,r3,r5,lsl#6 ++ mov r5,r6,lsr#14 ++ orr r4,r4,r6,lsl#12 ++ mov r6,r7,lsr#8 ++ orr r5,r5,r7,lsl#18 ++ and r3,r3,#0x03ffffff ++ and r4,r4,#0x03ffffff ++ and r5,r5,#0x03ffffff ++ ++ vdup.32 d0,r2 @ r^1 in both lanes ++ add r2,r3,r3,lsl#2 @ *5 ++ vdup.32 d1,r3 ++ add r3,r4,r4,lsl#2 ++ vdup.32 d2,r2 ++ vdup.32 d3,r4 ++ add r4,r5,r5,lsl#2 ++ vdup.32 d4,r3 ++ vdup.32 d5,r5 ++ add r5,r6,r6,lsl#2 ++ vdup.32 d6,r4 ++ vdup.32 d7,r6 ++ vdup.32 d8,r5 ++ ++ mov r5,#2 @ counter ++ ++.Lsquare_neon: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ @ d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ @ d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ @ d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ @ d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ ++ vmull.u32 q5,d0,d0[1] ++ vmull.u32 q6,d1,d0[1] ++ vmull.u32 q7,d3,d0[1] ++ vmull.u32 q8,d5,d0[1] ++ vmull.u32 q9,d7,d0[1] ++ ++ vmlal.u32 q5,d7,d2[1] ++ vmlal.u32 q6,d0,d1[1] ++ vmlal.u32 q7,d1,d1[1] ++ vmlal.u32 q8,d3,d1[1] ++ vmlal.u32 q9,d5,d1[1] ++ ++ vmlal.u32 q5,d5,d4[1] ++ vmlal.u32 q6,d7,d4[1] ++ vmlal.u32 q8,d1,d3[1] ++ vmlal.u32 q7,d0,d3[1] ++ vmlal.u32 q9,d3,d3[1] ++ ++ vmlal.u32 q5,d3,d6[1] ++ vmlal.u32 q8,d0,d5[1] ++ vmlal.u32 q6,d5,d6[1] ++ vmlal.u32 q7,d7,d6[1] ++ vmlal.u32 q9,d1,d5[1] ++ ++ vmlal.u32 q8,d7,d8[1] ++ vmlal.u32 q5,d1,d8[1] ++ vmlal.u32 q6,d3,d8[1] ++ vmlal.u32 q7,d5,d8[1] ++ vmlal.u32 q9,d0,d7[1] ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein ++ @ and P. Schwabe ++ @ ++ @ H0>>+H1>>+H2>>+H3>>+H4 ++ @ H3>>+H4>>*5+H0>>+H1 ++ @ ++ @ Trivia. ++ @ ++ @ Result of multiplication of n-bit number by m-bit number is ++ @ n+m bits wide. However! Even though 2^n is a n+1-bit number, ++ @ m-bit number multiplied by 2^n is still n+m bits wide. ++ @ ++ @ Sum of two n-bit numbers is n+1 bits wide, sum of three - n+2, ++ @ and so is sum of four. Sum of 2^m n-m-bit numbers and n-bit ++ @ one is n+1 bits wide. ++ @ ++ @ >>+ denotes Hnext += Hn>>26, Hn &= 0x3ffffff. This means that ++ @ H0, H2, H3 are guaranteed to be 26 bits wide, while H1 and H4 ++ @ can be 27. However! In cases when their width exceeds 26 bits ++ @ they are limited by 2^26+2^6. This in turn means that *sum* ++ @ of the products with these values can still be viewed as sum ++ @ of 52-bit numbers as long as the amount of addends is not a ++ @ power of 2. For example, ++ @ ++ @ H4 = H4*R0 + H3*R1 + H2*R2 + H1*R3 + H0 * R4, ++ @ ++ @ which can't be larger than 5 * (2^26 + 2^6) * (2^26 + 2^6), or ++ @ 5 * (2^52 + 2*2^32 + 2^12), which in turn is smaller than ++ @ 8 * (2^52) or 2^55. However, the value is then multiplied by ++ @ by 5, so we should be looking at 5 * 5 * (2^52 + 2^33 + 2^12), ++ @ which is less than 32 * (2^52) or 2^57. And when processing ++ @ data we are looking at triple as many addends... ++ @ ++ @ In key setup procedure pre-reduced H0 is limited by 5*4+1 and ++ @ 5*H4 - by 5*5 52-bit addends, or 57 bits. But when hashing the ++ @ input H0 is limited by (5*4+1)*3 addends, or 58 bits, while ++ @ 5*H4 by 5*5*3, or 59[!] bits. How is this relevant? vmlal.u32 ++ @ instruction accepts 2x32-bit input and writes 2x64-bit result. ++ @ This means that result of reduction have to be compressed upon ++ @ loop wrap-around. This can be done in the process of reduction ++ @ to minimize amount of instructions [as well as amount of ++ @ 128-bit instructions, which benefits low-end processors], but ++ @ one has to watch for H2 (which is narrower than H0) and 5*H4 ++ @ not being wider than 58 bits, so that result of right shift ++ @ by 26 bits fits in 32 bits. This is also useful on x86, ++ @ because it allows to use paddd in place for paddq, which ++ @ benefits Atom, where paddq is ridiculously slow. ++ ++ vshr.u64 q15,q8,#26 ++ vmovn.i64 d16,q8 ++ vshr.u64 q4,q5,#26 ++ vmovn.i64 d10,q5 ++ vadd.i64 q9,q9,q15 @ h3 -> h4 ++ vbic.i32 d16,#0xfc000000 @ &=0x03ffffff ++ vadd.i64 q6,q6,q4 @ h0 -> h1 ++ vbic.i32 d10,#0xfc000000 ++ ++ vshrn.u64 d30,q9,#26 ++ vmovn.i64 d18,q9 ++ vshr.u64 q4,q6,#26 ++ vmovn.i64 d12,q6 ++ vadd.i64 q7,q7,q4 @ h1 -> h2 ++ vbic.i32 d18,#0xfc000000 ++ vbic.i32 d12,#0xfc000000 ++ ++ vadd.i32 d10,d10,d30 ++ vshl.u32 d30,d30,#2 ++ vshrn.u64 d8,q7,#26 ++ vmovn.i64 d14,q7 ++ vadd.i32 d10,d10,d30 @ h4 -> h0 ++ vadd.i32 d16,d16,d8 @ h2 -> h3 ++ vbic.i32 d14,#0xfc000000 ++ ++ vshr.u32 d30,d10,#26 ++ vbic.i32 d10,#0xfc000000 ++ vshr.u32 d8,d16,#26 ++ vbic.i32 d16,#0xfc000000 ++ vadd.i32 d12,d12,d30 @ h0 -> h1 ++ vadd.i32 d18,d18,d8 @ h3 -> h4 ++ ++ subs r5,r5,#1 ++ beq .Lsquare_break_neon ++ ++ add r6,r0,#(48+0*9*4) ++ add r7,r0,#(48+1*9*4) ++ ++ vtrn.32 d0,d10 @ r^2:r^1 ++ vtrn.32 d3,d14 ++ vtrn.32 d5,d16 ++ vtrn.32 d1,d12 ++ vtrn.32 d7,d18 ++ ++ vshl.u32 d4,d3,#2 @ *5 ++ vshl.u32 d6,d5,#2 ++ vshl.u32 d2,d1,#2 ++ vshl.u32 d8,d7,#2 ++ vadd.i32 d4,d4,d3 ++ vadd.i32 d2,d2,d1 ++ vadd.i32 d6,d6,d5 ++ vadd.i32 d8,d8,d7 ++ ++ vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r6]! ++ vst4.32 {d0[1],d1[1],d2[1],d3[1]},[r7]! ++ vst4.32 {d4[0],d5[0],d6[0],d7[0]},[r6]! ++ vst4.32 {d4[1],d5[1],d6[1],d7[1]},[r7]! ++ vst1.32 {d8[0]},[r6,:32] ++ vst1.32 {d8[1]},[r7,:32] ++ ++ b .Lsquare_neon ++ ++.align 4 ++.Lsquare_break_neon: ++ add r6,r0,#(48+2*4*9) ++ add r7,r0,#(48+3*4*9) ++ ++ vmov d0,d10 @ r^4:r^3 ++ vshl.u32 d2,d12,#2 @ *5 ++ vmov d1,d12 ++ vshl.u32 d4,d14,#2 ++ vmov d3,d14 ++ vshl.u32 d6,d16,#2 ++ vmov d5,d16 ++ vshl.u32 d8,d18,#2 ++ vmov d7,d18 ++ vadd.i32 d2,d2,d12 ++ vadd.i32 d4,d4,d14 ++ vadd.i32 d6,d6,d16 ++ vadd.i32 d8,d8,d18 ++ ++ vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r6]! ++ vst4.32 {d0[1],d1[1],d2[1],d3[1]},[r7]! ++ vst4.32 {d4[0],d5[0],d6[0],d7[0]},[r6]! ++ vst4.32 {d4[1],d5[1],d6[1],d7[1]},[r7]! ++ vst1.32 {d8[0]},[r6] ++ vst1.32 {d8[1]},[r7] ++ ++.Lno_init_neon: ++ bx lr @ bx lr ++.size poly1305_init_neon,.-poly1305_init_neon ++ ++.type poly1305_blocks_neon,%function ++.align 5 ++poly1305_blocks_neon: ++.Lpoly1305_blocks_neon: ++ ldr ip,[r0,#36] @ is_base2_26 ++ ++ cmp r2,#64 ++ blo .Lpoly1305_blocks ++ ++ stmdb sp!,{r4-r7} ++ vstmdb sp!,{d8-d15} @ ABI specification says so ++ ++ tst ip,ip @ is_base2_26? ++ bne .Lbase2_26_neon ++ ++ stmdb sp!,{r1-r3,lr} ++ bl .Lpoly1305_init_neon ++ ++ ldr r4,[r0,#0] @ load hash value base 2^32 ++ ldr r5,[r0,#4] ++ ldr r6,[r0,#8] ++ ldr r7,[r0,#12] ++ ldr ip,[r0,#16] ++ ++ and r2,r4,#0x03ffffff @ base 2^32 -> base 2^26 ++ mov r3,r4,lsr#26 ++ veor d10,d10,d10 ++ mov r4,r5,lsr#20 ++ orr r3,r3,r5,lsl#6 ++ veor d12,d12,d12 ++ mov r5,r6,lsr#14 ++ orr r4,r4,r6,lsl#12 ++ veor d14,d14,d14 ++ mov r6,r7,lsr#8 ++ orr r5,r5,r7,lsl#18 ++ veor d16,d16,d16 ++ and r3,r3,#0x03ffffff ++ orr r6,r6,ip,lsl#24 ++ veor d18,d18,d18 ++ and r4,r4,#0x03ffffff ++ mov r1,#1 ++ and r5,r5,#0x03ffffff ++ str r1,[r0,#36] @ set is_base2_26 ++ ++ vmov.32 d10[0],r2 ++ vmov.32 d12[0],r3 ++ vmov.32 d14[0],r4 ++ vmov.32 d16[0],r5 ++ vmov.32 d18[0],r6 ++ adr r5,.Lzeros ++ ++ ldmia sp!,{r1-r3,lr} ++ b .Lhash_loaded ++ ++.align 4 ++.Lbase2_26_neon: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ load hash value ++ ++ veor d10,d10,d10 ++ veor d12,d12,d12 ++ veor d14,d14,d14 ++ veor d16,d16,d16 ++ veor d18,d18,d18 ++ vld4.32 {d10[0],d12[0],d14[0],d16[0]},[r0]! ++ adr r5,.Lzeros ++ vld1.32 {d18[0]},[r0] ++ sub r0,r0,#16 @ rewind ++ ++.Lhash_loaded: ++ add r4,r1,#32 ++ mov r3,r3,lsl#24 ++ tst r2,#31 ++ beq .Leven ++ ++ vld4.32 {d20[0],d22[0],d24[0],d26[0]},[r1]! ++ vmov.32 d28[0],r3 ++ sub r2,r2,#16 ++ add r4,r1,#32 ++ ++# ifdef __ARMEB__ ++ vrev32.8 q10,q10 ++ vrev32.8 q13,q13 ++ vrev32.8 q11,q11 ++ vrev32.8 q12,q12 ++# endif ++ vsri.u32 d28,d26,#8 @ base 2^32 -> base 2^26 ++ vshl.u32 d26,d26,#18 ++ ++ vsri.u32 d26,d24,#14 ++ vshl.u32 d24,d24,#12 ++ vadd.i32 d29,d28,d18 @ add hash value and move to #hi ++ ++ vbic.i32 d26,#0xfc000000 ++ vsri.u32 d24,d22,#20 ++ vshl.u32 d22,d22,#6 ++ ++ vbic.i32 d24,#0xfc000000 ++ vsri.u32 d22,d20,#26 ++ vadd.i32 d27,d26,d16 ++ ++ vbic.i32 d20,#0xfc000000 ++ vbic.i32 d22,#0xfc000000 ++ vadd.i32 d25,d24,d14 ++ ++ vadd.i32 d21,d20,d10 ++ vadd.i32 d23,d22,d12 ++ ++ mov r7,r5 ++ add r6,r0,#48 ++ ++ cmp r2,r2 ++ b .Long_tail ++ ++.align 4 ++.Leven: ++ subs r2,r2,#64 ++ it lo ++ movlo r4,r5 ++ ++ vmov.i32 q14,#1<<24 @ padbit, yes, always ++ vld4.32 {d20,d22,d24,d26},[r1] @ inp[0:1] ++ add r1,r1,#64 ++ vld4.32 {d21,d23,d25,d27},[r4] @ inp[2:3] (or 0) ++ add r4,r4,#64 ++ itt hi ++ addhi r7,r0,#(48+1*9*4) ++ addhi r6,r0,#(48+3*9*4) ++ ++# ifdef __ARMEB__ ++ vrev32.8 q10,q10 ++ vrev32.8 q13,q13 ++ vrev32.8 q11,q11 ++ vrev32.8 q12,q12 ++# endif ++ vsri.u32 q14,q13,#8 @ base 2^32 -> base 2^26 ++ vshl.u32 q13,q13,#18 ++ ++ vsri.u32 q13,q12,#14 ++ vshl.u32 q12,q12,#12 ++ ++ vbic.i32 q13,#0xfc000000 ++ vsri.u32 q12,q11,#20 ++ vshl.u32 q11,q11,#6 ++ ++ vbic.i32 q12,#0xfc000000 ++ vsri.u32 q11,q10,#26 ++ ++ vbic.i32 q10,#0xfc000000 ++ vbic.i32 q11,#0xfc000000 ++ ++ bls .Lskip_loop ++ ++ vld4.32 {d0[1],d1[1],d2[1],d3[1]},[r7]! @ load r^2 ++ vld4.32 {d0[0],d1[0],d2[0],d3[0]},[r6]! @ load r^4 ++ vld4.32 {d4[1],d5[1],d6[1],d7[1]},[r7]! ++ vld4.32 {d4[0],d5[0],d6[0],d7[0]},[r6]! ++ b .Loop_neon ++ ++.align 5 ++.Loop_neon: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2 ++ @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r ++ @ ___________________/ ++ @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2 ++ @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r ++ @ ___________________/ ____________________/ ++ @ ++ @ Note that we start with inp[2:3]*r^2. This is because it ++ @ doesn't depend on reduction in previous iteration. ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ @ d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ @ d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ @ d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ inp[2:3]*r^2 ++ ++ vadd.i32 d24,d24,d14 @ accumulate inp[0:1] ++ vmull.u32 q7,d25,d0[1] ++ vadd.i32 d20,d20,d10 ++ vmull.u32 q5,d21,d0[1] ++ vadd.i32 d26,d26,d16 ++ vmull.u32 q8,d27,d0[1] ++ vmlal.u32 q7,d23,d1[1] ++ vadd.i32 d22,d22,d12 ++ vmull.u32 q6,d23,d0[1] ++ ++ vadd.i32 d28,d28,d18 ++ vmull.u32 q9,d29,d0[1] ++ subs r2,r2,#64 ++ vmlal.u32 q5,d29,d2[1] ++ it lo ++ movlo r4,r5 ++ vmlal.u32 q8,d25,d1[1] ++ vld1.32 d8[1],[r7,:32] ++ vmlal.u32 q6,d21,d1[1] ++ vmlal.u32 q9,d27,d1[1] ++ ++ vmlal.u32 q5,d27,d4[1] ++ vmlal.u32 q8,d23,d3[1] ++ vmlal.u32 q9,d25,d3[1] ++ vmlal.u32 q6,d29,d4[1] ++ vmlal.u32 q7,d21,d3[1] ++ ++ vmlal.u32 q8,d21,d5[1] ++ vmlal.u32 q5,d25,d6[1] ++ vmlal.u32 q9,d23,d5[1] ++ vmlal.u32 q6,d27,d6[1] ++ vmlal.u32 q7,d29,d6[1] ++ ++ vmlal.u32 q8,d29,d8[1] ++ vmlal.u32 q5,d23,d8[1] ++ vmlal.u32 q9,d21,d7[1] ++ vmlal.u32 q6,d25,d8[1] ++ vmlal.u32 q7,d27,d8[1] ++ ++ vld4.32 {d21,d23,d25,d27},[r4] @ inp[2:3] (or 0) ++ add r4,r4,#64 ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ (hash+inp[0:1])*r^4 and accumulate ++ ++ vmlal.u32 q8,d26,d0[0] ++ vmlal.u32 q5,d20,d0[0] ++ vmlal.u32 q9,d28,d0[0] ++ vmlal.u32 q6,d22,d0[0] ++ vmlal.u32 q7,d24,d0[0] ++ vld1.32 d8[0],[r6,:32] ++ ++ vmlal.u32 q8,d24,d1[0] ++ vmlal.u32 q5,d28,d2[0] ++ vmlal.u32 q9,d26,d1[0] ++ vmlal.u32 q6,d20,d1[0] ++ vmlal.u32 q7,d22,d1[0] ++ ++ vmlal.u32 q8,d22,d3[0] ++ vmlal.u32 q5,d26,d4[0] ++ vmlal.u32 q9,d24,d3[0] ++ vmlal.u32 q6,d28,d4[0] ++ vmlal.u32 q7,d20,d3[0] ++ ++ vmlal.u32 q8,d20,d5[0] ++ vmlal.u32 q5,d24,d6[0] ++ vmlal.u32 q9,d22,d5[0] ++ vmlal.u32 q6,d26,d6[0] ++ vmlal.u32 q8,d28,d8[0] ++ ++ vmlal.u32 q7,d28,d6[0] ++ vmlal.u32 q5,d22,d8[0] ++ vmlal.u32 q9,d20,d7[0] ++ vmov.i32 q14,#1<<24 @ padbit, yes, always ++ vmlal.u32 q6,d24,d8[0] ++ vmlal.u32 q7,d26,d8[0] ++ ++ vld4.32 {d20,d22,d24,d26},[r1] @ inp[0:1] ++ add r1,r1,#64 ++# ifdef __ARMEB__ ++ vrev32.8 q10,q10 ++ vrev32.8 q11,q11 ++ vrev32.8 q12,q12 ++ vrev32.8 q13,q13 ++# endif ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ lazy reduction interleaved with base 2^32 -> base 2^26 of ++ @ inp[0:3] previously loaded to q10-q13 and smashed to q10-q14. ++ ++ vshr.u64 q15,q8,#26 ++ vmovn.i64 d16,q8 ++ vshr.u64 q4,q5,#26 ++ vmovn.i64 d10,q5 ++ vadd.i64 q9,q9,q15 @ h3 -> h4 ++ vbic.i32 d16,#0xfc000000 ++ vsri.u32 q14,q13,#8 @ base 2^32 -> base 2^26 ++ vadd.i64 q6,q6,q4 @ h0 -> h1 ++ vshl.u32 q13,q13,#18 ++ vbic.i32 d10,#0xfc000000 ++ ++ vshrn.u64 d30,q9,#26 ++ vmovn.i64 d18,q9 ++ vshr.u64 q4,q6,#26 ++ vmovn.i64 d12,q6 ++ vadd.i64 q7,q7,q4 @ h1 -> h2 ++ vsri.u32 q13,q12,#14 ++ vbic.i32 d18,#0xfc000000 ++ vshl.u32 q12,q12,#12 ++ vbic.i32 d12,#0xfc000000 ++ ++ vadd.i32 d10,d10,d30 ++ vshl.u32 d30,d30,#2 ++ vbic.i32 q13,#0xfc000000 ++ vshrn.u64 d8,q7,#26 ++ vmovn.i64 d14,q7 ++ vaddl.u32 q5,d10,d30 @ h4 -> h0 [widen for a sec] ++ vsri.u32 q12,q11,#20 ++ vadd.i32 d16,d16,d8 @ h2 -> h3 ++ vshl.u32 q11,q11,#6 ++ vbic.i32 d14,#0xfc000000 ++ vbic.i32 q12,#0xfc000000 ++ ++ vshrn.u64 d30,q5,#26 @ re-narrow ++ vmovn.i64 d10,q5 ++ vsri.u32 q11,q10,#26 ++ vbic.i32 q10,#0xfc000000 ++ vshr.u32 d8,d16,#26 ++ vbic.i32 d16,#0xfc000000 ++ vbic.i32 d10,#0xfc000000 ++ vadd.i32 d12,d12,d30 @ h0 -> h1 ++ vadd.i32 d18,d18,d8 @ h3 -> h4 ++ vbic.i32 q11,#0xfc000000 ++ ++ bhi .Loop_neon ++ ++.Lskip_loop: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1 ++ ++ add r7,r0,#(48+0*9*4) ++ add r6,r0,#(48+1*9*4) ++ adds r2,r2,#32 ++ it ne ++ movne r2,#0 ++ bne .Long_tail ++ ++ vadd.i32 d25,d24,d14 @ add hash value and move to #hi ++ vadd.i32 d21,d20,d10 ++ vadd.i32 d27,d26,d16 ++ vadd.i32 d23,d22,d12 ++ vadd.i32 d29,d28,d18 ++ ++.Long_tail: ++ vld4.32 {d0[1],d1[1],d2[1],d3[1]},[r7]! @ load r^1 ++ vld4.32 {d0[0],d1[0],d2[0],d3[0]},[r6]! @ load r^2 ++ ++ vadd.i32 d24,d24,d14 @ can be redundant ++ vmull.u32 q7,d25,d0 ++ vadd.i32 d20,d20,d10 ++ vmull.u32 q5,d21,d0 ++ vadd.i32 d26,d26,d16 ++ vmull.u32 q8,d27,d0 ++ vadd.i32 d22,d22,d12 ++ vmull.u32 q6,d23,d0 ++ vadd.i32 d28,d28,d18 ++ vmull.u32 q9,d29,d0 ++ ++ vmlal.u32 q5,d29,d2 ++ vld4.32 {d4[1],d5[1],d6[1],d7[1]},[r7]! ++ vmlal.u32 q8,d25,d1 ++ vld4.32 {d4[0],d5[0],d6[0],d7[0]},[r6]! ++ vmlal.u32 q6,d21,d1 ++ vmlal.u32 q9,d27,d1 ++ vmlal.u32 q7,d23,d1 ++ ++ vmlal.u32 q8,d23,d3 ++ vld1.32 d8[1],[r7,:32] ++ vmlal.u32 q5,d27,d4 ++ vld1.32 d8[0],[r6,:32] ++ vmlal.u32 q9,d25,d3 ++ vmlal.u32 q6,d29,d4 ++ vmlal.u32 q7,d21,d3 ++ ++ vmlal.u32 q8,d21,d5 ++ it ne ++ addne r7,r0,#(48+2*9*4) ++ vmlal.u32 q5,d25,d6 ++ it ne ++ addne r6,r0,#(48+3*9*4) ++ vmlal.u32 q9,d23,d5 ++ vmlal.u32 q6,d27,d6 ++ vmlal.u32 q7,d29,d6 ++ ++ vmlal.u32 q8,d29,d8 ++ vorn q0,q0,q0 @ all-ones, can be redundant ++ vmlal.u32 q5,d23,d8 ++ vshr.u64 q0,q0,#38 ++ vmlal.u32 q9,d21,d7 ++ vmlal.u32 q6,d25,d8 ++ vmlal.u32 q7,d27,d8 ++ ++ beq .Lshort_tail ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ (hash+inp[0:1])*r^4:r^3 and accumulate ++ ++ vld4.32 {d0[1],d1[1],d2[1],d3[1]},[r7]! @ load r^3 ++ vld4.32 {d0[0],d1[0],d2[0],d3[0]},[r6]! @ load r^4 ++ ++ vmlal.u32 q7,d24,d0 ++ vmlal.u32 q5,d20,d0 ++ vmlal.u32 q8,d26,d0 ++ vmlal.u32 q6,d22,d0 ++ vmlal.u32 q9,d28,d0 ++ ++ vmlal.u32 q5,d28,d2 ++ vld4.32 {d4[1],d5[1],d6[1],d7[1]},[r7]! ++ vmlal.u32 q8,d24,d1 ++ vld4.32 {d4[0],d5[0],d6[0],d7[0]},[r6]! ++ vmlal.u32 q6,d20,d1 ++ vmlal.u32 q9,d26,d1 ++ vmlal.u32 q7,d22,d1 ++ ++ vmlal.u32 q8,d22,d3 ++ vld1.32 d8[1],[r7,:32] ++ vmlal.u32 q5,d26,d4 ++ vld1.32 d8[0],[r6,:32] ++ vmlal.u32 q9,d24,d3 ++ vmlal.u32 q6,d28,d4 ++ vmlal.u32 q7,d20,d3 ++ ++ vmlal.u32 q8,d20,d5 ++ vmlal.u32 q5,d24,d6 ++ vmlal.u32 q9,d22,d5 ++ vmlal.u32 q6,d26,d6 ++ vmlal.u32 q7,d28,d6 ++ ++ vmlal.u32 q8,d28,d8 ++ vorn q0,q0,q0 @ all-ones ++ vmlal.u32 q5,d22,d8 ++ vshr.u64 q0,q0,#38 ++ vmlal.u32 q9,d20,d7 ++ vmlal.u32 q6,d24,d8 ++ vmlal.u32 q7,d26,d8 ++ ++.Lshort_tail: ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ horizontal addition ++ ++ vadd.i64 d16,d16,d17 ++ vadd.i64 d10,d10,d11 ++ vadd.i64 d18,d18,d19 ++ vadd.i64 d12,d12,d13 ++ vadd.i64 d14,d14,d15 ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ lazy reduction, but without narrowing ++ ++ vshr.u64 q15,q8,#26 ++ vand.i64 q8,q8,q0 ++ vshr.u64 q4,q5,#26 ++ vand.i64 q5,q5,q0 ++ vadd.i64 q9,q9,q15 @ h3 -> h4 ++ vadd.i64 q6,q6,q4 @ h0 -> h1 ++ ++ vshr.u64 q15,q9,#26 ++ vand.i64 q9,q9,q0 ++ vshr.u64 q4,q6,#26 ++ vand.i64 q6,q6,q0 ++ vadd.i64 q7,q7,q4 @ h1 -> h2 ++ ++ vadd.i64 q5,q5,q15 ++ vshl.u64 q15,q15,#2 ++ vshr.u64 q4,q7,#26 ++ vand.i64 q7,q7,q0 ++ vadd.i64 q5,q5,q15 @ h4 -> h0 ++ vadd.i64 q8,q8,q4 @ h2 -> h3 ++ ++ vshr.u64 q15,q5,#26 ++ vand.i64 q5,q5,q0 ++ vshr.u64 q4,q8,#26 ++ vand.i64 q8,q8,q0 ++ vadd.i64 q6,q6,q15 @ h0 -> h1 ++ vadd.i64 q9,q9,q4 @ h3 -> h4 ++ ++ cmp r2,#0 ++ bne .Leven ++ ++ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ++ @ store hash value ++ ++ vst4.32 {d10[0],d12[0],d14[0],d16[0]},[r0]! ++ vst1.32 {d18[0]},[r0] ++ ++ vldmia sp!,{d8-d15} @ epilogue ++ ldmia sp!,{r4-r7} ++ bx lr @ bx lr ++.size poly1305_blocks_neon,.-poly1305_blocks_neon ++ ++.align 5 ++.Lzeros: ++.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ++#ifndef __KERNEL__ ++.LOPENSSL_armcap: ++# ifdef _WIN32 ++.word OPENSSL_armcap_P ++# else ++.word OPENSSL_armcap_P-.Lpoly1305_init ++# endif ++.comm OPENSSL_armcap_P,4,4 ++.hidden OPENSSL_armcap_P ++#endif ++#endif ++.asciz "Poly1305 for ARMv4/NEON, CRYPTOGAMS by @dot-asm" ++.align 2 +--- /dev/null ++++ b/arch/arm/crypto/poly1305-glue.c +@@ -0,0 +1,276 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * OpenSSL/Cryptogams accelerated Poly1305 transform for ARM ++ * ++ * Copyright (C) 2019 Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void poly1305_init_arm(void *state, const u8 *key); ++void poly1305_blocks_arm(void *state, const u8 *src, u32 len, u32 hibit); ++void poly1305_emit_arm(void *state, __le32 *digest, const u32 *nonce); ++ ++void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit) ++{ ++} ++ ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); ++ ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++{ ++ poly1305_init_arm(&dctx->h, key); ++ dctx->s[0] = get_unaligned_le32(key + 16); ++ dctx->s[1] = get_unaligned_le32(key + 20); ++ dctx->s[2] = get_unaligned_le32(key + 24); ++ dctx->s[3] = get_unaligned_le32(key + 28); ++ dctx->buflen = 0; ++} ++EXPORT_SYMBOL(poly1305_init_arch); ++ ++static int arm_poly1305_init(struct shash_desc *desc) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ dctx->buflen = 0; ++ dctx->rset = 0; ++ dctx->sset = false; ++ ++ return 0; ++} ++ ++static void arm_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, ++ u32 len, u32 hibit, bool do_neon) ++{ ++ if (unlikely(!dctx->sset)) { ++ if (!dctx->rset) { ++ poly1305_init_arm(&dctx->h, src); ++ src += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ dctx->rset = 1; ++ } ++ if (len >= POLY1305_BLOCK_SIZE) { ++ dctx->s[0] = get_unaligned_le32(src + 0); ++ dctx->s[1] = get_unaligned_le32(src + 4); ++ dctx->s[2] = get_unaligned_le32(src + 8); ++ dctx->s[3] = get_unaligned_le32(src + 12); ++ src += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ dctx->sset = true; ++ } ++ if (len < POLY1305_BLOCK_SIZE) ++ return; ++ } ++ ++ len &= ~(POLY1305_BLOCK_SIZE - 1); ++ ++ if (static_branch_likely(&have_neon) && likely(do_neon)) ++ poly1305_blocks_neon(&dctx->h, src, len, hibit); ++ else ++ poly1305_blocks_arm(&dctx->h, src, len, hibit); ++} ++ ++static void arm_poly1305_do_update(struct poly1305_desc_ctx *dctx, ++ const u8 *src, u32 len, bool do_neon) ++{ ++ if (unlikely(dctx->buflen)) { ++ u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen); ++ ++ memcpy(dctx->buf + dctx->buflen, src, bytes); ++ src += bytes; ++ len -= bytes; ++ dctx->buflen += bytes; ++ ++ if (dctx->buflen == POLY1305_BLOCK_SIZE) { ++ arm_poly1305_blocks(dctx, dctx->buf, ++ POLY1305_BLOCK_SIZE, 1, false); ++ dctx->buflen = 0; ++ } ++ } ++ ++ if (likely(len >= POLY1305_BLOCK_SIZE)) { ++ arm_poly1305_blocks(dctx, src, len, 1, do_neon); ++ src += round_down(len, POLY1305_BLOCK_SIZE); ++ len %= POLY1305_BLOCK_SIZE; ++ } ++ ++ if (unlikely(len)) { ++ dctx->buflen = len; ++ memcpy(dctx->buf, src, len); ++ } ++} ++ ++static int arm_poly1305_update(struct shash_desc *desc, ++ const u8 *src, unsigned int srclen) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ arm_poly1305_do_update(dctx, src, srclen, false); ++ return 0; ++} ++ ++static int __maybe_unused arm_poly1305_update_neon(struct shash_desc *desc, ++ const u8 *src, ++ unsigned int srclen) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ bool do_neon = crypto_simd_usable() && srclen > 128; ++ ++ if (static_branch_likely(&have_neon) && do_neon) ++ kernel_neon_begin(); ++ arm_poly1305_do_update(dctx, src, srclen, do_neon); ++ if (static_branch_likely(&have_neon) && do_neon) ++ kernel_neon_end(); ++ return 0; ++} ++ ++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src, ++ unsigned int nbytes) ++{ ++ bool do_neon = IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && ++ crypto_simd_usable(); ++ ++ if (unlikely(dctx->buflen)) { ++ u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen); ++ ++ memcpy(dctx->buf + dctx->buflen, src, bytes); ++ src += bytes; ++ nbytes -= bytes; ++ dctx->buflen += bytes; ++ ++ if (dctx->buflen == POLY1305_BLOCK_SIZE) { ++ poly1305_blocks_arm(&dctx->h, dctx->buf, ++ POLY1305_BLOCK_SIZE, 1); ++ dctx->buflen = 0; ++ } ++ } ++ ++ if (likely(nbytes >= POLY1305_BLOCK_SIZE)) { ++ unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE); ++ ++ if (static_branch_likely(&have_neon) && do_neon) { ++ kernel_neon_begin(); ++ poly1305_blocks_neon(&dctx->h, src, len, 1); ++ kernel_neon_end(); ++ } else { ++ poly1305_blocks_arm(&dctx->h, src, len, 1); ++ } ++ src += len; ++ nbytes %= POLY1305_BLOCK_SIZE; ++ } ++ ++ if (unlikely(nbytes)) { ++ dctx->buflen = nbytes; ++ memcpy(dctx->buf, src, nbytes); ++ } ++} ++EXPORT_SYMBOL(poly1305_update_arch); ++ ++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst) ++{ ++ __le32 digest[4]; ++ u64 f = 0; ++ ++ if (unlikely(dctx->buflen)) { ++ dctx->buf[dctx->buflen++] = 1; ++ memset(dctx->buf + dctx->buflen, 0, ++ POLY1305_BLOCK_SIZE - dctx->buflen); ++ poly1305_blocks_arm(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0); ++ } ++ ++ poly1305_emit_arm(&dctx->h, digest, dctx->s); ++ ++ /* mac = (h + s) % (2^128) */ ++ f = (f >> 32) + le32_to_cpu(digest[0]); ++ put_unaligned_le32(f, dst); ++ f = (f >> 32) + le32_to_cpu(digest[1]); ++ put_unaligned_le32(f, dst + 4); ++ f = (f >> 32) + le32_to_cpu(digest[2]); ++ put_unaligned_le32(f, dst + 8); ++ f = (f >> 32) + le32_to_cpu(digest[3]); ++ put_unaligned_le32(f, dst + 12); ++ ++ *dctx = (struct poly1305_desc_ctx){}; ++} ++EXPORT_SYMBOL(poly1305_final_arch); ++ ++static int arm_poly1305_final(struct shash_desc *desc, u8 *dst) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ if (unlikely(!dctx->sset)) ++ return -ENOKEY; ++ ++ poly1305_final_arch(dctx, dst); ++ return 0; ++} ++ ++static struct shash_alg arm_poly1305_algs[] = {{ ++ .init = arm_poly1305_init, ++ .update = arm_poly1305_update, ++ .final = arm_poly1305_final, ++ .digestsize = POLY1305_DIGEST_SIZE, ++ .descsize = sizeof(struct poly1305_desc_ctx), ++ ++ .base.cra_name = "poly1305", ++ .base.cra_driver_name = "poly1305-arm", ++ .base.cra_priority = 150, ++ .base.cra_blocksize = POLY1305_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++#ifdef CONFIG_KERNEL_MODE_NEON ++}, { ++ .init = arm_poly1305_init, ++ .update = arm_poly1305_update_neon, ++ .final = arm_poly1305_final, ++ .digestsize = POLY1305_DIGEST_SIZE, ++ .descsize = sizeof(struct poly1305_desc_ctx), ++ ++ .base.cra_name = "poly1305", ++ .base.cra_driver_name = "poly1305-neon", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = POLY1305_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++#endif ++}}; ++ ++static int __init arm_poly1305_mod_init(void) ++{ ++ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && ++ (elf_hwcap & HWCAP_NEON)) ++ static_branch_enable(&have_neon); ++ else ++ /* register only the first entry */ ++ return crypto_register_shash(&arm_poly1305_algs[0]); ++ ++ return crypto_register_shashes(arm_poly1305_algs, ++ ARRAY_SIZE(arm_poly1305_algs)); ++} ++ ++static void __exit arm_poly1305_mod_exit(void) ++{ ++ if (!static_branch_likely(&have_neon)) { ++ crypto_unregister_shash(&arm_poly1305_algs[0]); ++ return; ++ } ++ crypto_unregister_shashes(arm_poly1305_algs, ++ ARRAY_SIZE(arm_poly1305_algs)); ++} ++ ++module_init(arm_poly1305_mod_init); ++module_exit(arm_poly1305_mod_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_CRYPTO("poly1305"); ++MODULE_ALIAS_CRYPTO("poly1305-arm"); ++MODULE_ALIAS_CRYPTO("poly1305-neon"); +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -40,7 +40,7 @@ config CRYPTO_LIB_DES + config CRYPTO_LIB_POLY1305_RSIZE + int + default 4 if X86_64 +- default 9 if ARM64 ++ default 9 if ARM || ARM64 + default 1 + + config CRYPTO_ARCH_HAVE_LIB_POLY1305 diff --git a/ipq806x/backport-5.4/080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch b/ipq806x/backport-5.4/080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch new file mode 100644 index 0000000..272e179 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0020-crypto-mips-poly1305-incorporate-OpenSSL-CRYPTOGAMS-.patch @@ -0,0 +1,1563 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:26 +0100 +Subject: [PATCH] crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS + optimized implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit a11d055e7a64ac34a5e99b6fe731299449cbcd58 upstream. + +This is a straight import of the OpenSSL/CRYPTOGAMS Poly1305 implementation for +MIPS authored by Andy Polyakov, a prior 64-bit only version of which has been +contributed by him to the OpenSSL project. The file 'poly1305-mips.pl' is taken +straight from this upstream GitHub repository [0] at commit +d22ade312a7af958ec955620b0d241cf42c37feb, and already contains all the changes +required to build it as part of a Linux kernel module. + +[0] https://github.com/dot-asm/cryptogams + +Co-developed-by: Andy Polyakov +Signed-off-by: Andy Polyakov +Co-developed-by: René van Dorst +Signed-off-by: René van Dorst +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/mips/crypto/Makefile | 14 + + arch/mips/crypto/poly1305-glue.c | 203 +++++ + arch/mips/crypto/poly1305-mips.pl | 1273 +++++++++++++++++++++++++++++ + crypto/Kconfig | 5 + + lib/crypto/Kconfig | 1 + + 5 files changed, 1496 insertions(+) + create mode 100644 arch/mips/crypto/poly1305-glue.c + create mode 100644 arch/mips/crypto/poly1305-mips.pl + +--- a/arch/mips/crypto/Makefile ++++ b/arch/mips/crypto/Makefile +@@ -8,3 +8,17 @@ obj-$(CONFIG_CRYPTO_CRC32_MIPS) += crc32 + obj-$(CONFIG_CRYPTO_CHACHA_MIPS) += chacha-mips.o + chacha-mips-y := chacha-core.o chacha-glue.o + AFLAGS_chacha-core.o += -O2 # needed to fill branch delay slots ++ ++obj-$(CONFIG_CRYPTO_POLY1305_MIPS) += poly1305-mips.o ++poly1305-mips-y := poly1305-core.o poly1305-glue.o ++ ++perlasm-flavour-$(CONFIG_CPU_MIPS32) := o32 ++perlasm-flavour-$(CONFIG_CPU_MIPS64) := 64 ++ ++quiet_cmd_perlasm = PERLASM $@ ++ cmd_perlasm = $(PERL) $(<) $(perlasm-flavour-y) $(@) ++ ++$(obj)/poly1305-core.S: $(src)/poly1305-mips.pl FORCE ++ $(call if_changed,perlasm) ++ ++targets += poly1305-core.S +--- /dev/null ++++ b/arch/mips/crypto/poly1305-glue.c +@@ -0,0 +1,203 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * OpenSSL/Cryptogams accelerated Poly1305 transform for MIPS ++ * ++ * Copyright (C) 2019 Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++asmlinkage void poly1305_init_mips(void *state, const u8 *key); ++asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit); ++asmlinkage void poly1305_emit_mips(void *state, __le32 *digest, const u32 *nonce); ++ ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++{ ++ poly1305_init_mips(&dctx->h, key); ++ dctx->s[0] = get_unaligned_le32(key + 16); ++ dctx->s[1] = get_unaligned_le32(key + 20); ++ dctx->s[2] = get_unaligned_le32(key + 24); ++ dctx->s[3] = get_unaligned_le32(key + 28); ++ dctx->buflen = 0; ++} ++EXPORT_SYMBOL(poly1305_init_arch); ++ ++static int mips_poly1305_init(struct shash_desc *desc) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ dctx->buflen = 0; ++ dctx->rset = 0; ++ dctx->sset = false; ++ ++ return 0; ++} ++ ++static void mips_poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, ++ u32 len, u32 hibit) ++{ ++ if (unlikely(!dctx->sset)) { ++ if (!dctx->rset) { ++ poly1305_init_mips(&dctx->h, src); ++ src += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ dctx->rset = 1; ++ } ++ if (len >= POLY1305_BLOCK_SIZE) { ++ dctx->s[0] = get_unaligned_le32(src + 0); ++ dctx->s[1] = get_unaligned_le32(src + 4); ++ dctx->s[2] = get_unaligned_le32(src + 8); ++ dctx->s[3] = get_unaligned_le32(src + 12); ++ src += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ dctx->sset = true; ++ } ++ if (len < POLY1305_BLOCK_SIZE) ++ return; ++ } ++ ++ len &= ~(POLY1305_BLOCK_SIZE - 1); ++ ++ poly1305_blocks_mips(&dctx->h, src, len, hibit); ++} ++ ++static int mips_poly1305_update(struct shash_desc *desc, const u8 *src, ++ unsigned int len) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ if (unlikely(dctx->buflen)) { ++ u32 bytes = min(len, POLY1305_BLOCK_SIZE - dctx->buflen); ++ ++ memcpy(dctx->buf + dctx->buflen, src, bytes); ++ src += bytes; ++ len -= bytes; ++ dctx->buflen += bytes; ++ ++ if (dctx->buflen == POLY1305_BLOCK_SIZE) { ++ mips_poly1305_blocks(dctx, dctx->buf, POLY1305_BLOCK_SIZE, 1); ++ dctx->buflen = 0; ++ } ++ } ++ ++ if (likely(len >= POLY1305_BLOCK_SIZE)) { ++ mips_poly1305_blocks(dctx, src, len, 1); ++ src += round_down(len, POLY1305_BLOCK_SIZE); ++ len %= POLY1305_BLOCK_SIZE; ++ } ++ ++ if (unlikely(len)) { ++ dctx->buflen = len; ++ memcpy(dctx->buf, src, len); ++ } ++ return 0; ++} ++ ++void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src, ++ unsigned int nbytes) ++{ ++ if (unlikely(dctx->buflen)) { ++ u32 bytes = min(nbytes, POLY1305_BLOCK_SIZE - dctx->buflen); ++ ++ memcpy(dctx->buf + dctx->buflen, src, bytes); ++ src += bytes; ++ nbytes -= bytes; ++ dctx->buflen += bytes; ++ ++ if (dctx->buflen == POLY1305_BLOCK_SIZE) { ++ poly1305_blocks_mips(&dctx->h, dctx->buf, ++ POLY1305_BLOCK_SIZE, 1); ++ dctx->buflen = 0; ++ } ++ } ++ ++ if (likely(nbytes >= POLY1305_BLOCK_SIZE)) { ++ unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE); ++ ++ poly1305_blocks_mips(&dctx->h, src, len, 1); ++ src += len; ++ nbytes %= POLY1305_BLOCK_SIZE; ++ } ++ ++ if (unlikely(nbytes)) { ++ dctx->buflen = nbytes; ++ memcpy(dctx->buf, src, nbytes); ++ } ++} ++EXPORT_SYMBOL(poly1305_update_arch); ++ ++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst) ++{ ++ __le32 digest[4]; ++ u64 f = 0; ++ ++ if (unlikely(dctx->buflen)) { ++ dctx->buf[dctx->buflen++] = 1; ++ memset(dctx->buf + dctx->buflen, 0, ++ POLY1305_BLOCK_SIZE - dctx->buflen); ++ poly1305_blocks_mips(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0); ++ } ++ ++ poly1305_emit_mips(&dctx->h, digest, dctx->s); ++ ++ /* mac = (h + s) % (2^128) */ ++ f = (f >> 32) + le32_to_cpu(digest[0]); ++ put_unaligned_le32(f, dst); ++ f = (f >> 32) + le32_to_cpu(digest[1]); ++ put_unaligned_le32(f, dst + 4); ++ f = (f >> 32) + le32_to_cpu(digest[2]); ++ put_unaligned_le32(f, dst + 8); ++ f = (f >> 32) + le32_to_cpu(digest[3]); ++ put_unaligned_le32(f, dst + 12); ++ ++ *dctx = (struct poly1305_desc_ctx){}; ++} ++EXPORT_SYMBOL(poly1305_final_arch); ++ ++static int mips_poly1305_final(struct shash_desc *desc, u8 *dst) ++{ ++ struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); ++ ++ if (unlikely(!dctx->sset)) ++ return -ENOKEY; ++ ++ poly1305_final_arch(dctx, dst); ++ return 0; ++} ++ ++static struct shash_alg mips_poly1305_alg = { ++ .init = mips_poly1305_init, ++ .update = mips_poly1305_update, ++ .final = mips_poly1305_final, ++ .digestsize = POLY1305_DIGEST_SIZE, ++ .descsize = sizeof(struct poly1305_desc_ctx), ++ ++ .base.cra_name = "poly1305", ++ .base.cra_driver_name = "poly1305-mips", ++ .base.cra_priority = 200, ++ .base.cra_blocksize = POLY1305_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++}; ++ ++static int __init mips_poly1305_mod_init(void) ++{ ++ return crypto_register_shash(&mips_poly1305_alg); ++} ++ ++static void __exit mips_poly1305_mod_exit(void) ++{ ++ crypto_unregister_shash(&mips_poly1305_alg); ++} ++ ++module_init(mips_poly1305_mod_init); ++module_exit(mips_poly1305_mod_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_CRYPTO("poly1305"); ++MODULE_ALIAS_CRYPTO("poly1305-mips"); +--- /dev/null ++++ b/arch/mips/crypto/poly1305-mips.pl +@@ -0,0 +1,1273 @@ ++#!/usr/bin/env perl ++# SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause ++# ++# ==================================================================== ++# Written by Andy Polyakov, @dot-asm, originally for the OpenSSL ++# project. ++# ==================================================================== ++ ++# Poly1305 hash for MIPS. ++# ++# May 2016 ++# ++# Numbers are cycles per processed byte with poly1305_blocks alone. ++# ++# IALU/gcc ++# R1x000 ~5.5/+130% (big-endian) ++# Octeon II 2.50/+70% (little-endian) ++# ++# March 2019 ++# ++# Add 32-bit code path. ++# ++# October 2019 ++# ++# Modulo-scheduling reduction allows to omit dependency chain at the ++# end of inner loop and improve performance. Also optimize MIPS32R2 ++# code path for MIPS 1004K core. Per René von Dorst's suggestions. ++# ++# IALU/gcc ++# R1x000 ~9.8/? (big-endian) ++# Octeon II 3.65/+140% (little-endian) ++# MT7621/1004K 4.75/? (little-endian) ++# ++###################################################################### ++# There is a number of MIPS ABI in use, O32 and N32/64 are most ++# widely used. Then there is a new contender: NUBI. It appears that if ++# one picks the latter, it's possible to arrange code in ABI neutral ++# manner. Therefore let's stick to NUBI register layout: ++# ++($zero,$at,$t0,$t1,$t2)=map("\$$_",(0..2,24,25)); ++($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11)); ++($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8,$s9,$s10,$s11)=map("\$$_",(12..23)); ++($gp,$tp,$sp,$fp,$ra)=map("\$$_",(3,28..31)); ++# ++# The return value is placed in $a0. Following coding rules facilitate ++# interoperability: ++# ++# - never ever touch $tp, "thread pointer", former $gp [o32 can be ++# excluded from the rule, because it's specified volatile]; ++# - copy return value to $t0, former $v0 [or to $a0 if you're adapting ++# old code]; ++# - on O32 populate $a4-$a7 with 'lw $aN,4*N($sp)' if necessary; ++# ++# For reference here is register layout for N32/64 MIPS ABIs: ++# ++# ($zero,$at,$v0,$v1)=map("\$$_",(0..3)); ++# ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$$_",(4..11)); ++# ($t0,$t1,$t2,$t3,$t8,$t9)=map("\$$_",(12..15,24,25)); ++# ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7)=map("\$$_",(16..23)); ++# ($gp,$sp,$fp,$ra)=map("\$$_",(28..31)); ++# ++# ++# ++###################################################################### ++ ++$flavour = shift || "64"; # supported flavours are o32,n32,64,nubi32,nubi64 ++ ++$v0 = ($flavour =~ /nubi/i) ? $a0 : $t0; ++ ++if ($flavour =~ /64|n32/i) {{{ ++###################################################################### ++# 64-bit code path ++# ++ ++my ($ctx,$inp,$len,$padbit) = ($a0,$a1,$a2,$a3); ++my ($in0,$in1,$tmp0,$tmp1,$tmp2,$tmp3,$tmp4) = ($a4,$a5,$a6,$a7,$at,$t0,$t1); ++ ++$code.=<<___; ++#if (defined(_MIPS_ARCH_MIPS64R3) || defined(_MIPS_ARCH_MIPS64R5) || \\ ++ defined(_MIPS_ARCH_MIPS64R6)) \\ ++ && !defined(_MIPS_ARCH_MIPS64R2) ++# define _MIPS_ARCH_MIPS64R2 ++#endif ++ ++#if defined(_MIPS_ARCH_MIPS64R6) ++# define dmultu(rs,rt) ++# define mflo(rd,rs,rt) dmulu rd,rs,rt ++# define mfhi(rd,rs,rt) dmuhu rd,rs,rt ++#else ++# define dmultu(rs,rt) dmultu rs,rt ++# define mflo(rd,rs,rt) mflo rd ++# define mfhi(rd,rs,rt) mfhi rd ++#endif ++ ++#ifdef __KERNEL__ ++# define poly1305_init poly1305_init_mips ++# define poly1305_blocks poly1305_blocks_mips ++# define poly1305_emit poly1305_emit_mips ++#endif ++ ++#if defined(__MIPSEB__) && !defined(MIPSEB) ++# define MIPSEB ++#endif ++ ++#ifdef MIPSEB ++# define MSB 0 ++# define LSB 7 ++#else ++# define MSB 7 ++# define LSB 0 ++#endif ++ ++.text ++.set noat ++.set noreorder ++ ++.align 5 ++.globl poly1305_init ++.ent poly1305_init ++poly1305_init: ++ .frame $sp,0,$ra ++ .set reorder ++ ++ sd $zero,0($ctx) ++ sd $zero,8($ctx) ++ sd $zero,16($ctx) ++ ++ beqz $inp,.Lno_key ++ ++#if defined(_MIPS_ARCH_MIPS64R6) ++ andi $tmp0,$inp,7 # $inp % 8 ++ dsubu $inp,$inp,$tmp0 # align $inp ++ sll $tmp0,$tmp0,3 # byte to bit offset ++ ld $in0,0($inp) ++ ld $in1,8($inp) ++ beqz $tmp0,.Laligned_key ++ ld $tmp2,16($inp) ++ ++ subu $tmp1,$zero,$tmp0 ++# ifdef MIPSEB ++ dsllv $in0,$in0,$tmp0 ++ dsrlv $tmp3,$in1,$tmp1 ++ dsllv $in1,$in1,$tmp0 ++ dsrlv $tmp2,$tmp2,$tmp1 ++# else ++ dsrlv $in0,$in0,$tmp0 ++ dsllv $tmp3,$in1,$tmp1 ++ dsrlv $in1,$in1,$tmp0 ++ dsllv $tmp2,$tmp2,$tmp1 ++# endif ++ or $in0,$in0,$tmp3 ++ or $in1,$in1,$tmp2 ++.Laligned_key: ++#else ++ ldl $in0,0+MSB($inp) ++ ldl $in1,8+MSB($inp) ++ ldr $in0,0+LSB($inp) ++ ldr $in1,8+LSB($inp) ++#endif ++#ifdef MIPSEB ++# if defined(_MIPS_ARCH_MIPS64R2) ++ dsbh $in0,$in0 # byte swap ++ dsbh $in1,$in1 ++ dshd $in0,$in0 ++ dshd $in1,$in1 ++# else ++ ori $tmp0,$zero,0xFF ++ dsll $tmp2,$tmp0,32 ++ or $tmp0,$tmp2 # 0x000000FF000000FF ++ ++ and $tmp1,$in0,$tmp0 # byte swap ++ and $tmp3,$in1,$tmp0 ++ dsrl $tmp2,$in0,24 ++ dsrl $tmp4,$in1,24 ++ dsll $tmp1,24 ++ dsll $tmp3,24 ++ and $tmp2,$tmp0 ++ and $tmp4,$tmp0 ++ dsll $tmp0,8 # 0x0000FF000000FF00 ++ or $tmp1,$tmp2 ++ or $tmp3,$tmp4 ++ and $tmp2,$in0,$tmp0 ++ and $tmp4,$in1,$tmp0 ++ dsrl $in0,8 ++ dsrl $in1,8 ++ dsll $tmp2,8 ++ dsll $tmp4,8 ++ and $in0,$tmp0 ++ and $in1,$tmp0 ++ or $tmp1,$tmp2 ++ or $tmp3,$tmp4 ++ or $in0,$tmp1 ++ or $in1,$tmp3 ++ dsrl $tmp1,$in0,32 ++ dsrl $tmp3,$in1,32 ++ dsll $in0,32 ++ dsll $in1,32 ++ or $in0,$tmp1 ++ or $in1,$tmp3 ++# endif ++#endif ++ li $tmp0,1 ++ dsll $tmp0,32 # 0x0000000100000000 ++ daddiu $tmp0,-63 # 0x00000000ffffffc1 ++ dsll $tmp0,28 # 0x0ffffffc10000000 ++ daddiu $tmp0,-1 # 0x0ffffffc0fffffff ++ ++ and $in0,$tmp0 ++ daddiu $tmp0,-3 # 0x0ffffffc0ffffffc ++ and $in1,$tmp0 ++ ++ sd $in0,24($ctx) ++ dsrl $tmp0,$in1,2 ++ sd $in1,32($ctx) ++ daddu $tmp0,$in1 # s1 = r1 + (r1 >> 2) ++ sd $tmp0,40($ctx) ++ ++.Lno_key: ++ li $v0,0 # return 0 ++ jr $ra ++.end poly1305_init ++___ ++{ ++my $SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0x0003f000" : "0x00030000"; ++ ++my ($h0,$h1,$h2,$r0,$r1,$rs1,$d0,$d1,$d2) = ++ ($s0,$s1,$s2,$s3,$s4,$s5,$in0,$in1,$t2); ++my ($shr,$shl) = ($s6,$s7); # used on R6 ++ ++$code.=<<___; ++.align 5 ++.globl poly1305_blocks ++.ent poly1305_blocks ++poly1305_blocks: ++ .set noreorder ++ dsrl $len,4 # number of complete blocks ++ bnez $len,poly1305_blocks_internal ++ nop ++ jr $ra ++ nop ++.end poly1305_blocks ++ ++.align 5 ++.ent poly1305_blocks_internal ++poly1305_blocks_internal: ++ .set noreorder ++#if defined(_MIPS_ARCH_MIPS64R6) ++ .frame $sp,8*8,$ra ++ .mask $SAVED_REGS_MASK|0x000c0000,-8 ++ dsubu $sp,8*8 ++ sd $s7,56($sp) ++ sd $s6,48($sp) ++#else ++ .frame $sp,6*8,$ra ++ .mask $SAVED_REGS_MASK,-8 ++ dsubu $sp,6*8 ++#endif ++ sd $s5,40($sp) ++ sd $s4,32($sp) ++___ ++$code.=<<___ if ($flavour =~ /nubi/i); # optimize non-nubi prologue ++ sd $s3,24($sp) ++ sd $s2,16($sp) ++ sd $s1,8($sp) ++ sd $s0,0($sp) ++___ ++$code.=<<___; ++ .set reorder ++ ++#if defined(_MIPS_ARCH_MIPS64R6) ++ andi $shr,$inp,7 ++ dsubu $inp,$inp,$shr # align $inp ++ sll $shr,$shr,3 # byte to bit offset ++ subu $shl,$zero,$shr ++#endif ++ ++ ld $h0,0($ctx) # load hash value ++ ld $h1,8($ctx) ++ ld $h2,16($ctx) ++ ++ ld $r0,24($ctx) # load key ++ ld $r1,32($ctx) ++ ld $rs1,40($ctx) ++ ++ dsll $len,4 ++ daddu $len,$inp # end of buffer ++ b .Loop ++ ++.align 4 ++.Loop: ++#if defined(_MIPS_ARCH_MIPS64R6) ++ ld $in0,0($inp) # load input ++ ld $in1,8($inp) ++ beqz $shr,.Laligned_inp ++ ++ ld $tmp2,16($inp) ++# ifdef MIPSEB ++ dsllv $in0,$in0,$shr ++ dsrlv $tmp3,$in1,$shl ++ dsllv $in1,$in1,$shr ++ dsrlv $tmp2,$tmp2,$shl ++# else ++ dsrlv $in0,$in0,$shr ++ dsllv $tmp3,$in1,$shl ++ dsrlv $in1,$in1,$shr ++ dsllv $tmp2,$tmp2,$shl ++# endif ++ or $in0,$in0,$tmp3 ++ or $in1,$in1,$tmp2 ++.Laligned_inp: ++#else ++ ldl $in0,0+MSB($inp) # load input ++ ldl $in1,8+MSB($inp) ++ ldr $in0,0+LSB($inp) ++ ldr $in1,8+LSB($inp) ++#endif ++ daddiu $inp,16 ++#ifdef MIPSEB ++# if defined(_MIPS_ARCH_MIPS64R2) ++ dsbh $in0,$in0 # byte swap ++ dsbh $in1,$in1 ++ dshd $in0,$in0 ++ dshd $in1,$in1 ++# else ++ ori $tmp0,$zero,0xFF ++ dsll $tmp2,$tmp0,32 ++ or $tmp0,$tmp2 # 0x000000FF000000FF ++ ++ and $tmp1,$in0,$tmp0 # byte swap ++ and $tmp3,$in1,$tmp0 ++ dsrl $tmp2,$in0,24 ++ dsrl $tmp4,$in1,24 ++ dsll $tmp1,24 ++ dsll $tmp3,24 ++ and $tmp2,$tmp0 ++ and $tmp4,$tmp0 ++ dsll $tmp0,8 # 0x0000FF000000FF00 ++ or $tmp1,$tmp2 ++ or $tmp3,$tmp4 ++ and $tmp2,$in0,$tmp0 ++ and $tmp4,$in1,$tmp0 ++ dsrl $in0,8 ++ dsrl $in1,8 ++ dsll $tmp2,8 ++ dsll $tmp4,8 ++ and $in0,$tmp0 ++ and $in1,$tmp0 ++ or $tmp1,$tmp2 ++ or $tmp3,$tmp4 ++ or $in0,$tmp1 ++ or $in1,$tmp3 ++ dsrl $tmp1,$in0,32 ++ dsrl $tmp3,$in1,32 ++ dsll $in0,32 ++ dsll $in1,32 ++ or $in0,$tmp1 ++ or $in1,$tmp3 ++# endif ++#endif ++ dsrl $tmp1,$h2,2 # modulo-scheduled reduction ++ andi $h2,$h2,3 ++ dsll $tmp0,$tmp1,2 ++ ++ daddu $d0,$h0,$in0 # accumulate input ++ daddu $tmp1,$tmp0 ++ sltu $tmp0,$d0,$h0 ++ daddu $d0,$d0,$tmp1 # ... and residue ++ sltu $tmp1,$d0,$tmp1 ++ daddu $d1,$h1,$in1 ++ daddu $tmp0,$tmp1 ++ sltu $tmp1,$d1,$h1 ++ daddu $d1,$tmp0 ++ ++ dmultu ($r0,$d0) # h0*r0 ++ daddu $d2,$h2,$padbit ++ sltu $tmp0,$d1,$tmp0 ++ mflo ($h0,$r0,$d0) ++ mfhi ($h1,$r0,$d0) ++ ++ dmultu ($rs1,$d1) # h1*5*r1 ++ daddu $d2,$tmp1 ++ daddu $d2,$tmp0 ++ mflo ($tmp0,$rs1,$d1) ++ mfhi ($tmp1,$rs1,$d1) ++ ++ dmultu ($r1,$d0) # h0*r1 ++ mflo ($tmp2,$r1,$d0) ++ mfhi ($h2,$r1,$d0) ++ daddu $h0,$tmp0 ++ daddu $h1,$tmp1 ++ sltu $tmp0,$h0,$tmp0 ++ ++ dmultu ($r0,$d1) # h1*r0 ++ daddu $h1,$tmp0 ++ daddu $h1,$tmp2 ++ mflo ($tmp0,$r0,$d1) ++ mfhi ($tmp1,$r0,$d1) ++ ++ dmultu ($rs1,$d2) # h2*5*r1 ++ sltu $tmp2,$h1,$tmp2 ++ daddu $h2,$tmp2 ++ mflo ($tmp2,$rs1,$d2) ++ ++ dmultu ($r0,$d2) # h2*r0 ++ daddu $h1,$tmp0 ++ daddu $h2,$tmp1 ++ mflo ($tmp3,$r0,$d2) ++ sltu $tmp0,$h1,$tmp0 ++ daddu $h2,$tmp0 ++ ++ daddu $h1,$tmp2 ++ sltu $tmp2,$h1,$tmp2 ++ daddu $h2,$tmp2 ++ daddu $h2,$tmp3 ++ ++ bne $inp,$len,.Loop ++ ++ sd $h0,0($ctx) # store hash value ++ sd $h1,8($ctx) ++ sd $h2,16($ctx) ++ ++ .set noreorder ++#if defined(_MIPS_ARCH_MIPS64R6) ++ ld $s7,56($sp) ++ ld $s6,48($sp) ++#endif ++ ld $s5,40($sp) # epilogue ++ ld $s4,32($sp) ++___ ++$code.=<<___ if ($flavour =~ /nubi/i); # optimize non-nubi epilogue ++ ld $s3,24($sp) ++ ld $s2,16($sp) ++ ld $s1,8($sp) ++ ld $s0,0($sp) ++___ ++$code.=<<___; ++ jr $ra ++#if defined(_MIPS_ARCH_MIPS64R6) ++ daddu $sp,8*8 ++#else ++ daddu $sp,6*8 ++#endif ++.end poly1305_blocks_internal ++___ ++} ++{ ++my ($ctx,$mac,$nonce) = ($a0,$a1,$a2); ++ ++$code.=<<___; ++.align 5 ++.globl poly1305_emit ++.ent poly1305_emit ++poly1305_emit: ++ .frame $sp,0,$ra ++ .set reorder ++ ++ ld $tmp2,16($ctx) ++ ld $tmp0,0($ctx) ++ ld $tmp1,8($ctx) ++ ++ li $in0,-4 # final reduction ++ dsrl $in1,$tmp2,2 ++ and $in0,$tmp2 ++ andi $tmp2,$tmp2,3 ++ daddu $in0,$in1 ++ ++ daddu $tmp0,$tmp0,$in0 ++ sltu $in1,$tmp0,$in0 ++ daddiu $in0,$tmp0,5 # compare to modulus ++ daddu $tmp1,$tmp1,$in1 ++ sltiu $tmp3,$in0,5 ++ sltu $tmp4,$tmp1,$in1 ++ daddu $in1,$tmp1,$tmp3 ++ daddu $tmp2,$tmp2,$tmp4 ++ sltu $tmp3,$in1,$tmp3 ++ daddu $tmp2,$tmp2,$tmp3 ++ ++ dsrl $tmp2,2 # see if it carried/borrowed ++ dsubu $tmp2,$zero,$tmp2 ++ ++ xor $in0,$tmp0 ++ xor $in1,$tmp1 ++ and $in0,$tmp2 ++ and $in1,$tmp2 ++ xor $in0,$tmp0 ++ xor $in1,$tmp1 ++ ++ lwu $tmp0,0($nonce) # load nonce ++ lwu $tmp1,4($nonce) ++ lwu $tmp2,8($nonce) ++ lwu $tmp3,12($nonce) ++ dsll $tmp1,32 ++ dsll $tmp3,32 ++ or $tmp0,$tmp1 ++ or $tmp2,$tmp3 ++ ++ daddu $in0,$tmp0 # accumulate nonce ++ daddu $in1,$tmp2 ++ sltu $tmp0,$in0,$tmp0 ++ daddu $in1,$tmp0 ++ ++ dsrl $tmp0,$in0,8 # write mac value ++ dsrl $tmp1,$in0,16 ++ dsrl $tmp2,$in0,24 ++ sb $in0,0($mac) ++ dsrl $tmp3,$in0,32 ++ sb $tmp0,1($mac) ++ dsrl $tmp0,$in0,40 ++ sb $tmp1,2($mac) ++ dsrl $tmp1,$in0,48 ++ sb $tmp2,3($mac) ++ dsrl $tmp2,$in0,56 ++ sb $tmp3,4($mac) ++ dsrl $tmp3,$in1,8 ++ sb $tmp0,5($mac) ++ dsrl $tmp0,$in1,16 ++ sb $tmp1,6($mac) ++ dsrl $tmp1,$in1,24 ++ sb $tmp2,7($mac) ++ ++ sb $in1,8($mac) ++ dsrl $tmp2,$in1,32 ++ sb $tmp3,9($mac) ++ dsrl $tmp3,$in1,40 ++ sb $tmp0,10($mac) ++ dsrl $tmp0,$in1,48 ++ sb $tmp1,11($mac) ++ dsrl $tmp1,$in1,56 ++ sb $tmp2,12($mac) ++ sb $tmp3,13($mac) ++ sb $tmp0,14($mac) ++ sb $tmp1,15($mac) ++ ++ jr $ra ++.end poly1305_emit ++.rdata ++.asciiz "Poly1305 for MIPS64, CRYPTOGAMS by \@dot-asm" ++.align 2 ++___ ++} ++}}} else {{{ ++###################################################################### ++# 32-bit code path ++# ++ ++my ($ctx,$inp,$len,$padbit) = ($a0,$a1,$a2,$a3); ++my ($in0,$in1,$in2,$in3,$tmp0,$tmp1,$tmp2,$tmp3) = ++ ($a4,$a5,$a6,$a7,$at,$t0,$t1,$t2); ++ ++$code.=<<___; ++#if (defined(_MIPS_ARCH_MIPS32R3) || defined(_MIPS_ARCH_MIPS32R5) || \\ ++ defined(_MIPS_ARCH_MIPS32R6)) \\ ++ && !defined(_MIPS_ARCH_MIPS32R2) ++# define _MIPS_ARCH_MIPS32R2 ++#endif ++ ++#if defined(_MIPS_ARCH_MIPS32R6) ++# define multu(rs,rt) ++# define mflo(rd,rs,rt) mulu rd,rs,rt ++# define mfhi(rd,rs,rt) muhu rd,rs,rt ++#else ++# define multu(rs,rt) multu rs,rt ++# define mflo(rd,rs,rt) mflo rd ++# define mfhi(rd,rs,rt) mfhi rd ++#endif ++ ++#ifdef __KERNEL__ ++# define poly1305_init poly1305_init_mips ++# define poly1305_blocks poly1305_blocks_mips ++# define poly1305_emit poly1305_emit_mips ++#endif ++ ++#if defined(__MIPSEB__) && !defined(MIPSEB) ++# define MIPSEB ++#endif ++ ++#ifdef MIPSEB ++# define MSB 0 ++# define LSB 3 ++#else ++# define MSB 3 ++# define LSB 0 ++#endif ++ ++.text ++.set noat ++.set noreorder ++ ++.align 5 ++.globl poly1305_init ++.ent poly1305_init ++poly1305_init: ++ .frame $sp,0,$ra ++ .set reorder ++ ++ sw $zero,0($ctx) ++ sw $zero,4($ctx) ++ sw $zero,8($ctx) ++ sw $zero,12($ctx) ++ sw $zero,16($ctx) ++ ++ beqz $inp,.Lno_key ++ ++#if defined(_MIPS_ARCH_MIPS32R6) ++ andi $tmp0,$inp,3 # $inp % 4 ++ subu $inp,$inp,$tmp0 # align $inp ++ sll $tmp0,$tmp0,3 # byte to bit offset ++ lw $in0,0($inp) ++ lw $in1,4($inp) ++ lw $in2,8($inp) ++ lw $in3,12($inp) ++ beqz $tmp0,.Laligned_key ++ ++ lw $tmp2,16($inp) ++ subu $tmp1,$zero,$tmp0 ++# ifdef MIPSEB ++ sllv $in0,$in0,$tmp0 ++ srlv $tmp3,$in1,$tmp1 ++ sllv $in1,$in1,$tmp0 ++ or $in0,$in0,$tmp3 ++ srlv $tmp3,$in2,$tmp1 ++ sllv $in2,$in2,$tmp0 ++ or $in1,$in1,$tmp3 ++ srlv $tmp3,$in3,$tmp1 ++ sllv $in3,$in3,$tmp0 ++ or $in2,$in2,$tmp3 ++ srlv $tmp2,$tmp2,$tmp1 ++ or $in3,$in3,$tmp2 ++# else ++ srlv $in0,$in0,$tmp0 ++ sllv $tmp3,$in1,$tmp1 ++ srlv $in1,$in1,$tmp0 ++ or $in0,$in0,$tmp3 ++ sllv $tmp3,$in2,$tmp1 ++ srlv $in2,$in2,$tmp0 ++ or $in1,$in1,$tmp3 ++ sllv $tmp3,$in3,$tmp1 ++ srlv $in3,$in3,$tmp0 ++ or $in2,$in2,$tmp3 ++ sllv $tmp2,$tmp2,$tmp1 ++ or $in3,$in3,$tmp2 ++# endif ++.Laligned_key: ++#else ++ lwl $in0,0+MSB($inp) ++ lwl $in1,4+MSB($inp) ++ lwl $in2,8+MSB($inp) ++ lwl $in3,12+MSB($inp) ++ lwr $in0,0+LSB($inp) ++ lwr $in1,4+LSB($inp) ++ lwr $in2,8+LSB($inp) ++ lwr $in3,12+LSB($inp) ++#endif ++#ifdef MIPSEB ++# if defined(_MIPS_ARCH_MIPS32R2) ++ wsbh $in0,$in0 # byte swap ++ wsbh $in1,$in1 ++ wsbh $in2,$in2 ++ wsbh $in3,$in3 ++ rotr $in0,$in0,16 ++ rotr $in1,$in1,16 ++ rotr $in2,$in2,16 ++ rotr $in3,$in3,16 ++# else ++ srl $tmp0,$in0,24 # byte swap ++ srl $tmp1,$in0,8 ++ andi $tmp2,$in0,0xFF00 ++ sll $in0,$in0,24 ++ andi $tmp1,0xFF00 ++ sll $tmp2,$tmp2,8 ++ or $in0,$tmp0 ++ srl $tmp0,$in1,24 ++ or $tmp1,$tmp2 ++ srl $tmp2,$in1,8 ++ or $in0,$tmp1 ++ andi $tmp1,$in1,0xFF00 ++ sll $in1,$in1,24 ++ andi $tmp2,0xFF00 ++ sll $tmp1,$tmp1,8 ++ or $in1,$tmp0 ++ srl $tmp0,$in2,24 ++ or $tmp2,$tmp1 ++ srl $tmp1,$in2,8 ++ or $in1,$tmp2 ++ andi $tmp2,$in2,0xFF00 ++ sll $in2,$in2,24 ++ andi $tmp1,0xFF00 ++ sll $tmp2,$tmp2,8 ++ or $in2,$tmp0 ++ srl $tmp0,$in3,24 ++ or $tmp1,$tmp2 ++ srl $tmp2,$in3,8 ++ or $in2,$tmp1 ++ andi $tmp1,$in3,0xFF00 ++ sll $in3,$in3,24 ++ andi $tmp2,0xFF00 ++ sll $tmp1,$tmp1,8 ++ or $in3,$tmp0 ++ or $tmp2,$tmp1 ++ or $in3,$tmp2 ++# endif ++#endif ++ lui $tmp0,0x0fff ++ ori $tmp0,0xffff # 0x0fffffff ++ and $in0,$in0,$tmp0 ++ subu $tmp0,3 # 0x0ffffffc ++ and $in1,$in1,$tmp0 ++ and $in2,$in2,$tmp0 ++ and $in3,$in3,$tmp0 ++ ++ sw $in0,20($ctx) ++ sw $in1,24($ctx) ++ sw $in2,28($ctx) ++ sw $in3,32($ctx) ++ ++ srl $tmp1,$in1,2 ++ srl $tmp2,$in2,2 ++ srl $tmp3,$in3,2 ++ addu $in1,$in1,$tmp1 # s1 = r1 + (r1 >> 2) ++ addu $in2,$in2,$tmp2 ++ addu $in3,$in3,$tmp3 ++ sw $in1,36($ctx) ++ sw $in2,40($ctx) ++ sw $in3,44($ctx) ++.Lno_key: ++ li $v0,0 ++ jr $ra ++.end poly1305_init ++___ ++{ ++my $SAVED_REGS_MASK = ($flavour =~ /nubi/i) ? "0x00fff000" : "0x00ff0000"; ++ ++my ($h0,$h1,$h2,$h3,$h4, $r0,$r1,$r2,$r3, $rs1,$rs2,$rs3) = ++ ($s0,$s1,$s2,$s3,$s4, $s5,$s6,$s7,$s8, $s9,$s10,$s11); ++my ($d0,$d1,$d2,$d3) = ++ ($a4,$a5,$a6,$a7); ++my $shr = $t2; # used on R6 ++my $one = $t2; # used on R2 ++ ++$code.=<<___; ++.globl poly1305_blocks ++.align 5 ++.ent poly1305_blocks ++poly1305_blocks: ++ .frame $sp,16*4,$ra ++ .mask $SAVED_REGS_MASK,-4 ++ .set noreorder ++ subu $sp, $sp,4*12 ++ sw $s11,4*11($sp) ++ sw $s10,4*10($sp) ++ sw $s9, 4*9($sp) ++ sw $s8, 4*8($sp) ++ sw $s7, 4*7($sp) ++ sw $s6, 4*6($sp) ++ sw $s5, 4*5($sp) ++ sw $s4, 4*4($sp) ++___ ++$code.=<<___ if ($flavour =~ /nubi/i); # optimize non-nubi prologue ++ sw $s3, 4*3($sp) ++ sw $s2, 4*2($sp) ++ sw $s1, 4*1($sp) ++ sw $s0, 4*0($sp) ++___ ++$code.=<<___; ++ .set reorder ++ ++ srl $len,4 # number of complete blocks ++ li $one,1 ++ beqz $len,.Labort ++ ++#if defined(_MIPS_ARCH_MIPS32R6) ++ andi $shr,$inp,3 ++ subu $inp,$inp,$shr # align $inp ++ sll $shr,$shr,3 # byte to bit offset ++#endif ++ ++ lw $h0,0($ctx) # load hash value ++ lw $h1,4($ctx) ++ lw $h2,8($ctx) ++ lw $h3,12($ctx) ++ lw $h4,16($ctx) ++ ++ lw $r0,20($ctx) # load key ++ lw $r1,24($ctx) ++ lw $r2,28($ctx) ++ lw $r3,32($ctx) ++ lw $rs1,36($ctx) ++ lw $rs2,40($ctx) ++ lw $rs3,44($ctx) ++ ++ sll $len,4 ++ addu $len,$len,$inp # end of buffer ++ b .Loop ++ ++.align 4 ++.Loop: ++#if defined(_MIPS_ARCH_MIPS32R6) ++ lw $d0,0($inp) # load input ++ lw $d1,4($inp) ++ lw $d2,8($inp) ++ lw $d3,12($inp) ++ beqz $shr,.Laligned_inp ++ ++ lw $t0,16($inp) ++ subu $t1,$zero,$shr ++# ifdef MIPSEB ++ sllv $d0,$d0,$shr ++ srlv $at,$d1,$t1 ++ sllv $d1,$d1,$shr ++ or $d0,$d0,$at ++ srlv $at,$d2,$t1 ++ sllv $d2,$d2,$shr ++ or $d1,$d1,$at ++ srlv $at,$d3,$t1 ++ sllv $d3,$d3,$shr ++ or $d2,$d2,$at ++ srlv $t0,$t0,$t1 ++ or $d3,$d3,$t0 ++# else ++ srlv $d0,$d0,$shr ++ sllv $at,$d1,$t1 ++ srlv $d1,$d1,$shr ++ or $d0,$d0,$at ++ sllv $at,$d2,$t1 ++ srlv $d2,$d2,$shr ++ or $d1,$d1,$at ++ sllv $at,$d3,$t1 ++ srlv $d3,$d3,$shr ++ or $d2,$d2,$at ++ sllv $t0,$t0,$t1 ++ or $d3,$d3,$t0 ++# endif ++.Laligned_inp: ++#else ++ lwl $d0,0+MSB($inp) # load input ++ lwl $d1,4+MSB($inp) ++ lwl $d2,8+MSB($inp) ++ lwl $d3,12+MSB($inp) ++ lwr $d0,0+LSB($inp) ++ lwr $d1,4+LSB($inp) ++ lwr $d2,8+LSB($inp) ++ lwr $d3,12+LSB($inp) ++#endif ++#ifdef MIPSEB ++# if defined(_MIPS_ARCH_MIPS32R2) ++ wsbh $d0,$d0 # byte swap ++ wsbh $d1,$d1 ++ wsbh $d2,$d2 ++ wsbh $d3,$d3 ++ rotr $d0,$d0,16 ++ rotr $d1,$d1,16 ++ rotr $d2,$d2,16 ++ rotr $d3,$d3,16 ++# else ++ srl $at,$d0,24 # byte swap ++ srl $t0,$d0,8 ++ andi $t1,$d0,0xFF00 ++ sll $d0,$d0,24 ++ andi $t0,0xFF00 ++ sll $t1,$t1,8 ++ or $d0,$at ++ srl $at,$d1,24 ++ or $t0,$t1 ++ srl $t1,$d1,8 ++ or $d0,$t0 ++ andi $t0,$d1,0xFF00 ++ sll $d1,$d1,24 ++ andi $t1,0xFF00 ++ sll $t0,$t0,8 ++ or $d1,$at ++ srl $at,$d2,24 ++ or $t1,$t0 ++ srl $t0,$d2,8 ++ or $d1,$t1 ++ andi $t1,$d2,0xFF00 ++ sll $d2,$d2,24 ++ andi $t0,0xFF00 ++ sll $t1,$t1,8 ++ or $d2,$at ++ srl $at,$d3,24 ++ or $t0,$t1 ++ srl $t1,$d3,8 ++ or $d2,$t0 ++ andi $t0,$d3,0xFF00 ++ sll $d3,$d3,24 ++ andi $t1,0xFF00 ++ sll $t0,$t0,8 ++ or $d3,$at ++ or $t1,$t0 ++ or $d3,$t1 ++# endif ++#endif ++ srl $t0,$h4,2 # modulo-scheduled reduction ++ andi $h4,$h4,3 ++ sll $at,$t0,2 ++ ++ addu $d0,$d0,$h0 # accumulate input ++ addu $t0,$t0,$at ++ sltu $h0,$d0,$h0 ++ addu $d0,$d0,$t0 # ... and residue ++ sltu $at,$d0,$t0 ++ ++ addu $d1,$d1,$h1 ++ addu $h0,$h0,$at # carry ++ sltu $h1,$d1,$h1 ++ addu $d1,$d1,$h0 ++ sltu $h0,$d1,$h0 ++ ++ addu $d2,$d2,$h2 ++ addu $h1,$h1,$h0 # carry ++ sltu $h2,$d2,$h2 ++ addu $d2,$d2,$h1 ++ sltu $h1,$d2,$h1 ++ ++ addu $d3,$d3,$h3 ++ addu $h2,$h2,$h1 # carry ++ sltu $h3,$d3,$h3 ++ addu $d3,$d3,$h2 ++ ++#if defined(_MIPS_ARCH_MIPS32R2) && !defined(_MIPS_ARCH_MIPS32R6) ++ multu $r0,$d0 # d0*r0 ++ sltu $h2,$d3,$h2 ++ maddu $rs3,$d1 # d1*s3 ++ addu $h3,$h3,$h2 # carry ++ maddu $rs2,$d2 # d2*s2 ++ addu $h4,$h4,$padbit ++ maddu $rs1,$d3 # d3*s1 ++ addu $h4,$h4,$h3 ++ mfhi $at ++ mflo $h0 ++ ++ multu $r1,$d0 # d0*r1 ++ maddu $r0,$d1 # d1*r0 ++ maddu $rs3,$d2 # d2*s3 ++ maddu $rs2,$d3 # d3*s2 ++ maddu $rs1,$h4 # h4*s1 ++ maddu $at,$one # hi*1 ++ mfhi $at ++ mflo $h1 ++ ++ multu $r2,$d0 # d0*r2 ++ maddu $r1,$d1 # d1*r1 ++ maddu $r0,$d2 # d2*r0 ++ maddu $rs3,$d3 # d3*s3 ++ maddu $rs2,$h4 # h4*s2 ++ maddu $at,$one # hi*1 ++ mfhi $at ++ mflo $h2 ++ ++ mul $t0,$r0,$h4 # h4*r0 ++ ++ multu $r3,$d0 # d0*r3 ++ maddu $r2,$d1 # d1*r2 ++ maddu $r1,$d2 # d2*r1 ++ maddu $r0,$d3 # d3*r0 ++ maddu $rs3,$h4 # h4*s3 ++ maddu $at,$one # hi*1 ++ mfhi $at ++ mflo $h3 ++ ++ addiu $inp,$inp,16 ++ ++ addu $h4,$t0,$at ++#else ++ multu ($r0,$d0) # d0*r0 ++ mflo ($h0,$r0,$d0) ++ mfhi ($h1,$r0,$d0) ++ ++ sltu $h2,$d3,$h2 ++ addu $h3,$h3,$h2 # carry ++ ++ multu ($rs3,$d1) # d1*s3 ++ mflo ($at,$rs3,$d1) ++ mfhi ($t0,$rs3,$d1) ++ ++ addu $h4,$h4,$padbit ++ addiu $inp,$inp,16 ++ addu $h4,$h4,$h3 ++ ++ multu ($rs2,$d2) # d2*s2 ++ mflo ($a3,$rs2,$d2) ++ mfhi ($t1,$rs2,$d2) ++ addu $h0,$h0,$at ++ addu $h1,$h1,$t0 ++ multu ($rs1,$d3) # d3*s1 ++ sltu $at,$h0,$at ++ addu $h1,$h1,$at ++ ++ mflo ($at,$rs1,$d3) ++ mfhi ($t0,$rs1,$d3) ++ addu $h0,$h0,$a3 ++ addu $h1,$h1,$t1 ++ multu ($r1,$d0) # d0*r1 ++ sltu $a3,$h0,$a3 ++ addu $h1,$h1,$a3 ++ ++ ++ mflo ($a3,$r1,$d0) ++ mfhi ($h2,$r1,$d0) ++ addu $h0,$h0,$at ++ addu $h1,$h1,$t0 ++ multu ($r0,$d1) # d1*r0 ++ sltu $at,$h0,$at ++ addu $h1,$h1,$at ++ ++ mflo ($at,$r0,$d1) ++ mfhi ($t0,$r0,$d1) ++ addu $h1,$h1,$a3 ++ sltu $a3,$h1,$a3 ++ multu ($rs3,$d2) # d2*s3 ++ addu $h2,$h2,$a3 ++ ++ mflo ($a3,$rs3,$d2) ++ mfhi ($t1,$rs3,$d2) ++ addu $h1,$h1,$at ++ addu $h2,$h2,$t0 ++ multu ($rs2,$d3) # d3*s2 ++ sltu $at,$h1,$at ++ addu $h2,$h2,$at ++ ++ mflo ($at,$rs2,$d3) ++ mfhi ($t0,$rs2,$d3) ++ addu $h1,$h1,$a3 ++ addu $h2,$h2,$t1 ++ multu ($rs1,$h4) # h4*s1 ++ sltu $a3,$h1,$a3 ++ addu $h2,$h2,$a3 ++ ++ mflo ($a3,$rs1,$h4) ++ addu $h1,$h1,$at ++ addu $h2,$h2,$t0 ++ multu ($r2,$d0) # d0*r2 ++ sltu $at,$h1,$at ++ addu $h2,$h2,$at ++ ++ ++ mflo ($at,$r2,$d0) ++ mfhi ($h3,$r2,$d0) ++ addu $h1,$h1,$a3 ++ sltu $a3,$h1,$a3 ++ multu ($r1,$d1) # d1*r1 ++ addu $h2,$h2,$a3 ++ ++ mflo ($a3,$r1,$d1) ++ mfhi ($t1,$r1,$d1) ++ addu $h2,$h2,$at ++ sltu $at,$h2,$at ++ multu ($r0,$d2) # d2*r0 ++ addu $h3,$h3,$at ++ ++ mflo ($at,$r0,$d2) ++ mfhi ($t0,$r0,$d2) ++ addu $h2,$h2,$a3 ++ addu $h3,$h3,$t1 ++ multu ($rs3,$d3) # d3*s3 ++ sltu $a3,$h2,$a3 ++ addu $h3,$h3,$a3 ++ ++ mflo ($a3,$rs3,$d3) ++ mfhi ($t1,$rs3,$d3) ++ addu $h2,$h2,$at ++ addu $h3,$h3,$t0 ++ multu ($rs2,$h4) # h4*s2 ++ sltu $at,$h2,$at ++ addu $h3,$h3,$at ++ ++ mflo ($at,$rs2,$h4) ++ addu $h2,$h2,$a3 ++ addu $h3,$h3,$t1 ++ multu ($r3,$d0) # d0*r3 ++ sltu $a3,$h2,$a3 ++ addu $h3,$h3,$a3 ++ ++ ++ mflo ($a3,$r3,$d0) ++ mfhi ($t1,$r3,$d0) ++ addu $h2,$h2,$at ++ sltu $at,$h2,$at ++ multu ($r2,$d1) # d1*r2 ++ addu $h3,$h3,$at ++ ++ mflo ($at,$r2,$d1) ++ mfhi ($t0,$r2,$d1) ++ addu $h3,$h3,$a3 ++ sltu $a3,$h3,$a3 ++ multu ($r0,$d3) # d3*r0 ++ addu $t1,$t1,$a3 ++ ++ mflo ($a3,$r0,$d3) ++ mfhi ($d3,$r0,$d3) ++ addu $h3,$h3,$at ++ addu $t1,$t1,$t0 ++ multu ($r1,$d2) # d2*r1 ++ sltu $at,$h3,$at ++ addu $t1,$t1,$at ++ ++ mflo ($at,$r1,$d2) ++ mfhi ($t0,$r1,$d2) ++ addu $h3,$h3,$a3 ++ addu $t1,$t1,$d3 ++ multu ($rs3,$h4) # h4*s3 ++ sltu $a3,$h3,$a3 ++ addu $t1,$t1,$a3 ++ ++ mflo ($a3,$rs3,$h4) ++ addu $h3,$h3,$at ++ addu $t1,$t1,$t0 ++ multu ($r0,$h4) # h4*r0 ++ sltu $at,$h3,$at ++ addu $t1,$t1,$at ++ ++ ++ mflo ($h4,$r0,$h4) ++ addu $h3,$h3,$a3 ++ sltu $a3,$h3,$a3 ++ addu $t1,$t1,$a3 ++ addu $h4,$h4,$t1 ++ ++ li $padbit,1 # if we loop, padbit is 1 ++#endif ++ bne $inp,$len,.Loop ++ ++ sw $h0,0($ctx) # store hash value ++ sw $h1,4($ctx) ++ sw $h2,8($ctx) ++ sw $h3,12($ctx) ++ sw $h4,16($ctx) ++ ++ .set noreorder ++.Labort: ++ lw $s11,4*11($sp) ++ lw $s10,4*10($sp) ++ lw $s9, 4*9($sp) ++ lw $s8, 4*8($sp) ++ lw $s7, 4*7($sp) ++ lw $s6, 4*6($sp) ++ lw $s5, 4*5($sp) ++ lw $s4, 4*4($sp) ++___ ++$code.=<<___ if ($flavour =~ /nubi/i); # optimize non-nubi prologue ++ lw $s3, 4*3($sp) ++ lw $s2, 4*2($sp) ++ lw $s1, 4*1($sp) ++ lw $s0, 4*0($sp) ++___ ++$code.=<<___; ++ jr $ra ++ addu $sp,$sp,4*12 ++.end poly1305_blocks ++___ ++} ++{ ++my ($ctx,$mac,$nonce,$tmp4) = ($a0,$a1,$a2,$a3); ++ ++$code.=<<___; ++.align 5 ++.globl poly1305_emit ++.ent poly1305_emit ++poly1305_emit: ++ .frame $sp,0,$ra ++ .set reorder ++ ++ lw $tmp4,16($ctx) ++ lw $tmp0,0($ctx) ++ lw $tmp1,4($ctx) ++ lw $tmp2,8($ctx) ++ lw $tmp3,12($ctx) ++ ++ li $in0,-4 # final reduction ++ srl $ctx,$tmp4,2 ++ and $in0,$in0,$tmp4 ++ andi $tmp4,$tmp4,3 ++ addu $ctx,$ctx,$in0 ++ ++ addu $tmp0,$tmp0,$ctx ++ sltu $ctx,$tmp0,$ctx ++ addiu $in0,$tmp0,5 # compare to modulus ++ addu $tmp1,$tmp1,$ctx ++ sltiu $in1,$in0,5 ++ sltu $ctx,$tmp1,$ctx ++ addu $in1,$in1,$tmp1 ++ addu $tmp2,$tmp2,$ctx ++ sltu $in2,$in1,$tmp1 ++ sltu $ctx,$tmp2,$ctx ++ addu $in2,$in2,$tmp2 ++ addu $tmp3,$tmp3,$ctx ++ sltu $in3,$in2,$tmp2 ++ sltu $ctx,$tmp3,$ctx ++ addu $in3,$in3,$tmp3 ++ addu $tmp4,$tmp4,$ctx ++ sltu $ctx,$in3,$tmp3 ++ addu $ctx,$tmp4 ++ ++ srl $ctx,2 # see if it carried/borrowed ++ subu $ctx,$zero,$ctx ++ ++ xor $in0,$tmp0 ++ xor $in1,$tmp1 ++ xor $in2,$tmp2 ++ xor $in3,$tmp3 ++ and $in0,$ctx ++ and $in1,$ctx ++ and $in2,$ctx ++ and $in3,$ctx ++ xor $in0,$tmp0 ++ xor $in1,$tmp1 ++ xor $in2,$tmp2 ++ xor $in3,$tmp3 ++ ++ lw $tmp0,0($nonce) # load nonce ++ lw $tmp1,4($nonce) ++ lw $tmp2,8($nonce) ++ lw $tmp3,12($nonce) ++ ++ addu $in0,$tmp0 # accumulate nonce ++ sltu $ctx,$in0,$tmp0 ++ ++ addu $in1,$tmp1 ++ sltu $tmp1,$in1,$tmp1 ++ addu $in1,$ctx ++ sltu $ctx,$in1,$ctx ++ addu $ctx,$tmp1 ++ ++ addu $in2,$tmp2 ++ sltu $tmp2,$in2,$tmp2 ++ addu $in2,$ctx ++ sltu $ctx,$in2,$ctx ++ addu $ctx,$tmp2 ++ ++ addu $in3,$tmp3 ++ addu $in3,$ctx ++ ++ srl $tmp0,$in0,8 # write mac value ++ srl $tmp1,$in0,16 ++ srl $tmp2,$in0,24 ++ sb $in0, 0($mac) ++ sb $tmp0,1($mac) ++ srl $tmp0,$in1,8 ++ sb $tmp1,2($mac) ++ srl $tmp1,$in1,16 ++ sb $tmp2,3($mac) ++ srl $tmp2,$in1,24 ++ sb $in1, 4($mac) ++ sb $tmp0,5($mac) ++ srl $tmp0,$in2,8 ++ sb $tmp1,6($mac) ++ srl $tmp1,$in2,16 ++ sb $tmp2,7($mac) ++ srl $tmp2,$in2,24 ++ sb $in2, 8($mac) ++ sb $tmp0,9($mac) ++ srl $tmp0,$in3,8 ++ sb $tmp1,10($mac) ++ srl $tmp1,$in3,16 ++ sb $tmp2,11($mac) ++ srl $tmp2,$in3,24 ++ sb $in3, 12($mac) ++ sb $tmp0,13($mac) ++ sb $tmp1,14($mac) ++ sb $tmp2,15($mac) ++ ++ jr $ra ++.end poly1305_emit ++.rdata ++.asciiz "Poly1305 for MIPS32, CRYPTOGAMS by \@dot-asm" ++.align 2 ++___ ++} ++}}} ++ ++$output=pop and open STDOUT,">$output"; ++print $code; ++close STDOUT; +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -707,6 +707,11 @@ config CRYPTO_POLY1305_X86_64 + in IETF protocols. This is the x86_64 assembler implementation using SIMD + instructions. + ++config CRYPTO_POLY1305_MIPS ++ tristate "Poly1305 authenticator algorithm (MIPS optimized)" ++ depends on CPU_MIPS32 || (CPU_MIPS64 && 64BIT) ++ select CRYPTO_ARCH_HAVE_LIB_POLY1305 ++ + config CRYPTO_MD4 + tristate "MD4 digest algorithm" + select CRYPTO_HASH +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -39,6 +39,7 @@ config CRYPTO_LIB_DES + + config CRYPTO_LIB_POLY1305_RSIZE + int ++ default 2 if MIPS + default 4 if X86_64 + default 9 if ARM || ARM64 + default 1 diff --git a/ipq806x/backport-5.4/080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch b/ipq806x/backport-5.4/080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch new file mode 100644 index 0000000..97f73b9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0021-crypto-blake2s-generic-C-library-implementation-and-.patch @@ -0,0 +1,1097 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 8 Nov 2019 13:22:28 +0100 +Subject: [PATCH] crypto: blake2s - generic C library implementation and + selftest + +commit 66d7fb94e4ffe5acc589e0b2b4710aecc1f07a28 upstream. + +The C implementation was originally based on Samuel Neves' public +domain reference implementation but has since been heavily modified +for the kernel. We're able to do compile-time optimizations by moving +some scaffolding around the final function into the header file. + +Information: https://blake2.net/ + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Samuel Neves +Co-developed-by: Samuel Neves +[ardb: - move from lib/zinc to lib/crypto + - remove simd handling + - rewrote selftest for better coverage + - use fixed digest length for blake2s_hmac() and rename to + blake2s256_hmac() ] +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + include/crypto/blake2s.h | 106 +++++ + include/crypto/internal/blake2s.h | 19 + + lib/crypto/Kconfig | 25 ++ + lib/crypto/Makefile | 10 + + lib/crypto/blake2s-generic.c | 111 ++++++ + lib/crypto/blake2s-selftest.c | 622 ++++++++++++++++++++++++++++++ + lib/crypto/blake2s.c | 126 ++++++ + 7 files changed, 1019 insertions(+) + create mode 100644 include/crypto/blake2s.h + create mode 100644 include/crypto/internal/blake2s.h + create mode 100644 lib/crypto/blake2s-generic.c + create mode 100644 lib/crypto/blake2s-selftest.c + create mode 100644 lib/crypto/blake2s.c + +--- /dev/null ++++ b/include/crypto/blake2s.h +@@ -0,0 +1,106 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef BLAKE2S_H ++#define BLAKE2S_H ++ ++#include ++#include ++#include ++ ++#include ++ ++enum blake2s_lengths { ++ BLAKE2S_BLOCK_SIZE = 64, ++ BLAKE2S_HASH_SIZE = 32, ++ BLAKE2S_KEY_SIZE = 32, ++ ++ BLAKE2S_128_HASH_SIZE = 16, ++ BLAKE2S_160_HASH_SIZE = 20, ++ BLAKE2S_224_HASH_SIZE = 28, ++ BLAKE2S_256_HASH_SIZE = 32, ++}; ++ ++struct blake2s_state { ++ u32 h[8]; ++ u32 t[2]; ++ u32 f[2]; ++ u8 buf[BLAKE2S_BLOCK_SIZE]; ++ unsigned int buflen; ++ unsigned int outlen; ++}; ++ ++enum blake2s_iv { ++ BLAKE2S_IV0 = 0x6A09E667UL, ++ BLAKE2S_IV1 = 0xBB67AE85UL, ++ BLAKE2S_IV2 = 0x3C6EF372UL, ++ BLAKE2S_IV3 = 0xA54FF53AUL, ++ BLAKE2S_IV4 = 0x510E527FUL, ++ BLAKE2S_IV5 = 0x9B05688CUL, ++ BLAKE2S_IV6 = 0x1F83D9ABUL, ++ BLAKE2S_IV7 = 0x5BE0CD19UL, ++}; ++ ++void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen); ++void blake2s_final(struct blake2s_state *state, u8 *out); ++ ++static inline void blake2s_init_param(struct blake2s_state *state, ++ const u32 param) ++{ ++ *state = (struct blake2s_state){{ ++ BLAKE2S_IV0 ^ param, ++ BLAKE2S_IV1, ++ BLAKE2S_IV2, ++ BLAKE2S_IV3, ++ BLAKE2S_IV4, ++ BLAKE2S_IV5, ++ BLAKE2S_IV6, ++ BLAKE2S_IV7, ++ }}; ++} ++ ++static inline void blake2s_init(struct blake2s_state *state, ++ const size_t outlen) ++{ ++ blake2s_init_param(state, 0x01010000 | outlen); ++ state->outlen = outlen; ++} ++ ++static inline void blake2s_init_key(struct blake2s_state *state, ++ const size_t outlen, const void *key, ++ const size_t keylen) ++{ ++ WARN_ON(IS_ENABLED(DEBUG) && (!outlen || outlen > BLAKE2S_HASH_SIZE || ++ !key || !keylen || keylen > BLAKE2S_KEY_SIZE)); ++ ++ blake2s_init_param(state, 0x01010000 | keylen << 8 | outlen); ++ memcpy(state->buf, key, keylen); ++ state->buflen = BLAKE2S_BLOCK_SIZE; ++ state->outlen = outlen; ++} ++ ++static inline void blake2s(u8 *out, const u8 *in, const u8 *key, ++ const size_t outlen, const size_t inlen, ++ const size_t keylen) ++{ ++ struct blake2s_state state; ++ ++ WARN_ON(IS_ENABLED(DEBUG) && ((!in && inlen > 0) || !out || !outlen || ++ outlen > BLAKE2S_HASH_SIZE || keylen > BLAKE2S_KEY_SIZE || ++ (!key && keylen))); ++ ++ if (keylen) ++ blake2s_init_key(&state, outlen, key, keylen); ++ else ++ blake2s_init(&state, outlen); ++ ++ blake2s_update(&state, in, inlen); ++ blake2s_final(&state, out); ++} ++ ++void blake2s256_hmac(u8 *out, const u8 *in, const u8 *key, const size_t inlen, ++ const size_t keylen); ++ ++#endif /* BLAKE2S_H */ +--- /dev/null ++++ b/include/crypto/internal/blake2s.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++ ++#ifndef BLAKE2S_INTERNAL_H ++#define BLAKE2S_INTERNAL_H ++ ++#include ++ ++void blake2s_compress_generic(struct blake2s_state *state,const u8 *block, ++ size_t nblocks, const u32 inc); ++ ++void blake2s_compress_arch(struct blake2s_state *state,const u8 *block, ++ size_t nblocks, const u32 inc); ++ ++static inline void blake2s_set_lastblock(struct blake2s_state *state) ++{ ++ state->f[0] = -1; ++} ++ ++#endif /* BLAKE2S_INTERNAL_H */ +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -8,6 +8,31 @@ config CRYPTO_LIB_AES + config CRYPTO_LIB_ARC4 + tristate + ++config CRYPTO_ARCH_HAVE_LIB_BLAKE2S ++ tristate ++ help ++ Declares whether the architecture provides an arch-specific ++ accelerated implementation of the Blake2s library interface, ++ either builtin or as a module. ++ ++config CRYPTO_LIB_BLAKE2S_GENERIC ++ tristate ++ help ++ This symbol can be depended upon by arch implementations of the ++ Blake2s library interface that require the generic code as a ++ fallback, e.g., for SIMD implementations. If no arch specific ++ implementation is enabled, this implementation serves the users ++ of CRYPTO_LIB_BLAKE2S. ++ ++config CRYPTO_LIB_BLAKE2S ++ tristate "BLAKE2s hash function library" ++ depends on CRYPTO_ARCH_HAVE_LIB_BLAKE2S || !CRYPTO_ARCH_HAVE_LIB_BLAKE2S ++ select CRYPTO_LIB_BLAKE2S_GENERIC if CRYPTO_ARCH_HAVE_LIB_BLAKE2S=n ++ help ++ Enable the Blake2s library interface. This interface may be fulfilled ++ by either the generic implementation or an arch-specific one, if one ++ is available and enabled. ++ + config CRYPTO_ARCH_HAVE_LIB_CHACHA + tristate + help +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -10,6 +10,12 @@ libaes-y := aes.o + obj-$(CONFIG_CRYPTO_LIB_ARC4) += libarc4.o + libarc4-y := arc4.o + ++obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC) += libblake2s-generic.o ++libblake2s-generic-y += blake2s-generic.o ++ ++obj-$(CONFIG_CRYPTO_LIB_BLAKE2S) += libblake2s.o ++libblake2s-y += blake2s.o ++ + obj-$(CONFIG_CRYPTO_LIB_DES) += libdes.o + libdes-y := des.o + +@@ -18,3 +24,7 @@ libpoly1305-y := poly1305.o + + obj-$(CONFIG_CRYPTO_LIB_SHA256) += libsha256.o + libsha256-y := sha256.o ++ ++ifneq ($(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS),y) ++libblake2s-y += blake2s-selftest.o ++endif +--- /dev/null ++++ b/lib/crypto/blake2s-generic.c +@@ -0,0 +1,111 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is an implementation of the BLAKE2s hash and PRF functions. ++ * ++ * Information: https://blake2.net/ ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const u8 blake2s_sigma[10][16] = { ++ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, ++ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, ++ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, ++ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, ++ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, ++ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, ++ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, ++ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, ++ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, ++ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, ++}; ++ ++static inline void blake2s_increment_counter(struct blake2s_state *state, ++ const u32 inc) ++{ ++ state->t[0] += inc; ++ state->t[1] += (state->t[0] < inc); ++} ++ ++void blake2s_compress_generic(struct blake2s_state *state,const u8 *block, ++ size_t nblocks, const u32 inc) ++{ ++ u32 m[16]; ++ u32 v[16]; ++ int i; ++ ++ WARN_ON(IS_ENABLED(DEBUG) && ++ (nblocks > 1 && inc != BLAKE2S_BLOCK_SIZE)); ++ ++ while (nblocks > 0) { ++ blake2s_increment_counter(state, inc); ++ memcpy(m, block, BLAKE2S_BLOCK_SIZE); ++ le32_to_cpu_array(m, ARRAY_SIZE(m)); ++ memcpy(v, state->h, 32); ++ v[ 8] = BLAKE2S_IV0; ++ v[ 9] = BLAKE2S_IV1; ++ v[10] = BLAKE2S_IV2; ++ v[11] = BLAKE2S_IV3; ++ v[12] = BLAKE2S_IV4 ^ state->t[0]; ++ v[13] = BLAKE2S_IV5 ^ state->t[1]; ++ v[14] = BLAKE2S_IV6 ^ state->f[0]; ++ v[15] = BLAKE2S_IV7 ^ state->f[1]; ++ ++#define G(r, i, a, b, c, d) do { \ ++ a += b + m[blake2s_sigma[r][2 * i + 0]]; \ ++ d = ror32(d ^ a, 16); \ ++ c += d; \ ++ b = ror32(b ^ c, 12); \ ++ a += b + m[blake2s_sigma[r][2 * i + 1]]; \ ++ d = ror32(d ^ a, 8); \ ++ c += d; \ ++ b = ror32(b ^ c, 7); \ ++} while (0) ++ ++#define ROUND(r) do { \ ++ G(r, 0, v[0], v[ 4], v[ 8], v[12]); \ ++ G(r, 1, v[1], v[ 5], v[ 9], v[13]); \ ++ G(r, 2, v[2], v[ 6], v[10], v[14]); \ ++ G(r, 3, v[3], v[ 7], v[11], v[15]); \ ++ G(r, 4, v[0], v[ 5], v[10], v[15]); \ ++ G(r, 5, v[1], v[ 6], v[11], v[12]); \ ++ G(r, 6, v[2], v[ 7], v[ 8], v[13]); \ ++ G(r, 7, v[3], v[ 4], v[ 9], v[14]); \ ++} while (0) ++ ROUND(0); ++ ROUND(1); ++ ROUND(2); ++ ROUND(3); ++ ROUND(4); ++ ROUND(5); ++ ROUND(6); ++ ROUND(7); ++ ROUND(8); ++ ROUND(9); ++ ++#undef G ++#undef ROUND ++ ++ for (i = 0; i < 8; ++i) ++ state->h[i] ^= v[i] ^ v[i + 8]; ++ ++ block += BLAKE2S_BLOCK_SIZE; ++ --nblocks; ++ } ++} ++ ++EXPORT_SYMBOL(blake2s_compress_generic); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("BLAKE2s hash function"); ++MODULE_AUTHOR("Jason A. Donenfeld "); +--- /dev/null ++++ b/lib/crypto/blake2s-selftest.c +@@ -0,0 +1,622 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include ++#include ++ ++/* ++ * blake2s_testvecs[] generated with the program below (using libb2-dev and ++ * libssl-dev [OpenSSL]) ++ * ++ * #include ++ * #include ++ * #include ++ * ++ * #include ++ * #include ++ * ++ * #define BLAKE2S_TESTVEC_COUNT 256 ++ * ++ * static void print_vec(const uint8_t vec[], int len) ++ * { ++ * int i; ++ * ++ * printf(" { "); ++ * for (i = 0; i < len; i++) { ++ * if (i && (i % 12) == 0) ++ * printf("\n "); ++ * printf("0x%02x, ", vec[i]); ++ * } ++ * printf("},\n"); ++ * } ++ * ++ * int main(void) ++ * { ++ * uint8_t key[BLAKE2S_KEYBYTES]; ++ * uint8_t buf[BLAKE2S_TESTVEC_COUNT]; ++ * uint8_t hash[BLAKE2S_OUTBYTES]; ++ * int i, j; ++ * ++ * key[0] = key[1] = 1; ++ * for (i = 2; i < BLAKE2S_KEYBYTES; ++i) ++ * key[i] = key[i - 2] + key[i - 1]; ++ * ++ * for (i = 0; i < BLAKE2S_TESTVEC_COUNT; ++i) ++ * buf[i] = (uint8_t)i; ++ * ++ * printf("static const u8 blake2s_testvecs[][BLAKE2S_HASH_SIZE] __initconst = {\n"); ++ * ++ * for (i = 0; i < BLAKE2S_TESTVEC_COUNT; ++i) { ++ * int outlen = 1 + i % BLAKE2S_OUTBYTES; ++ * int keylen = (13 * i) % (BLAKE2S_KEYBYTES + 1); ++ * ++ * blake2s(hash, buf, key + BLAKE2S_KEYBYTES - keylen, outlen, i, ++ * keylen); ++ * print_vec(hash, outlen); ++ * } ++ * printf("};\n\n"); ++ * ++ * printf("static const u8 blake2s_hmac_testvecs[][BLAKE2S_HASH_SIZE] __initconst = {\n"); ++ * ++ * HMAC(EVP_blake2s256(), key, sizeof(key), buf, sizeof(buf), hash, NULL); ++ * print_vec(hash, BLAKE2S_OUTBYTES); ++ * ++ * HMAC(EVP_blake2s256(), buf, sizeof(buf), key, sizeof(key), hash, NULL); ++ * print_vec(hash, BLAKE2S_OUTBYTES); ++ * ++ * printf("};\n"); ++ * ++ * return 0; ++ *} ++ */ ++static const u8 blake2s_testvecs[][BLAKE2S_HASH_SIZE] __initconst = { ++ { 0xa1, }, ++ { 0x7c, 0x89, }, ++ { 0x74, 0x0e, 0xd4, }, ++ { 0x47, 0x0c, 0x21, 0x15, }, ++ { 0x18, 0xd6, 0x9c, 0xa6, 0xc4, }, ++ { 0x13, 0x5d, 0x16, 0x63, 0x2e, 0xf9, }, ++ { 0x2c, 0xb5, 0x04, 0xb7, 0x99, 0xe2, 0x73, }, ++ { 0x9a, 0x0f, 0xd2, 0x39, 0xd6, 0x68, 0x1b, 0x92, }, ++ { 0xc8, 0xde, 0x7a, 0xea, 0x2f, 0xf4, 0xd2, 0xe3, 0x2b, }, ++ { 0x5b, 0xf9, 0x43, 0x52, 0x0c, 0x12, 0xba, 0xb5, 0x93, 0x9f, }, ++ { 0xc6, 0x2c, 0x4e, 0x80, 0xfc, 0x32, 0x5b, 0x33, 0xb8, 0xb8, 0x0a, }, ++ { 0xa7, 0x5c, 0xfd, 0x3a, 0xcc, 0xbf, 0x90, 0xca, 0xb7, 0x97, 0xde, 0xd8, }, ++ { 0x66, 0xca, 0x3c, 0xc4, 0x19, 0xef, 0x92, 0x66, 0x3f, 0x21, 0x8f, 0xda, ++ 0xb7, }, ++ { 0xba, 0xe5, 0xbb, 0x30, 0x25, 0x94, 0x6d, 0xc3, 0x89, 0x09, 0xc4, 0x25, ++ 0x52, 0x3e, }, ++ { 0xa2, 0xef, 0x0e, 0x52, 0x0b, 0x5f, 0xa2, 0x01, 0x6d, 0x0a, 0x25, 0xbc, ++ 0x57, 0xe2, 0x27, }, ++ { 0x4f, 0xe0, 0xf9, 0x52, 0x12, 0xda, 0x84, 0xb7, 0xab, 0xae, 0xb0, 0xa6, ++ 0x47, 0x2a, 0xc7, 0xf5, }, ++ { 0x56, 0xe7, 0xa8, 0x1c, 0x4c, 0xca, 0xed, 0x90, 0x31, 0xec, 0x87, 0x43, ++ 0xe7, 0x72, 0x08, 0xec, 0xbe, }, ++ { 0x7e, 0xdf, 0x80, 0x1c, 0x93, 0x33, 0xfd, 0x53, 0x44, 0xba, 0xfd, 0x96, ++ 0xe1, 0xbb, 0xb5, 0x65, 0xa5, 0x00, }, ++ { 0xec, 0x6b, 0xed, 0xf7, 0x7b, 0x62, 0x1d, 0x7d, 0xf4, 0x82, 0xf3, 0x1e, ++ 0x18, 0xff, 0x2b, 0xc4, 0x06, 0x20, 0x2a, }, ++ { 0x74, 0x98, 0xd7, 0x68, 0x63, 0xed, 0x87, 0xe4, 0x5d, 0x8d, 0x9e, 0x1d, ++ 0xfd, 0x2a, 0xbb, 0x86, 0xac, 0xe9, 0x2a, 0x89, }, ++ { 0x89, 0xc3, 0x88, 0xce, 0x2b, 0x33, 0x1e, 0x10, 0xd1, 0x37, 0x20, 0x86, ++ 0x28, 0x43, 0x70, 0xd9, 0xfb, 0x96, 0xd9, 0xb5, 0xd3, }, ++ { 0xcb, 0x56, 0x74, 0x41, 0x8d, 0x80, 0x01, 0x9a, 0x6b, 0x38, 0xe1, 0x41, ++ 0xad, 0x9c, 0x62, 0x74, 0xce, 0x35, 0xd5, 0x6c, 0x89, 0x6e, }, ++ { 0x79, 0xaf, 0x94, 0x59, 0x99, 0x26, 0xe1, 0xc9, 0x34, 0xfe, 0x7c, 0x22, ++ 0xf7, 0x43, 0xd7, 0x65, 0xd4, 0x48, 0x18, 0xac, 0x3d, 0xfd, 0x93, }, ++ { 0x85, 0x0d, 0xff, 0xb8, 0x3e, 0x87, 0x41, 0xb0, 0x95, 0xd3, 0x3d, 0x00, ++ 0x47, 0x55, 0x9e, 0xd2, 0x69, 0xea, 0xbf, 0xe9, 0x7a, 0x2d, 0x61, 0x45, }, ++ { 0x03, 0xe0, 0x85, 0xec, 0x54, 0xb5, 0x16, 0x53, 0xa8, 0xc4, 0x71, 0xe9, ++ 0x6a, 0xe7, 0xcb, 0xc4, 0x15, 0x02, 0xfc, 0x34, 0xa4, 0xa4, 0x28, 0x13, ++ 0xd1, }, ++ { 0xe3, 0x34, 0x4b, 0xe1, 0xd0, 0x4b, 0x55, 0x61, 0x8f, 0xc0, 0x24, 0x05, ++ 0xe6, 0xe0, 0x3d, 0x70, 0x24, 0x4d, 0xda, 0xb8, 0x91, 0x05, 0x29, 0x07, ++ 0x01, 0x3e, }, ++ { 0x61, 0xff, 0x01, 0x72, 0xb1, 0x4d, 0xf6, 0xfe, 0xd1, 0xd1, 0x08, 0x74, ++ 0xe6, 0x91, 0x44, 0xeb, 0x61, 0xda, 0x40, 0xaf, 0xfc, 0x8c, 0x91, 0x6b, ++ 0xec, 0x13, 0xed, }, ++ { 0xd4, 0x40, 0xd2, 0xa0, 0x7f, 0xc1, 0x58, 0x0c, 0x85, 0xa0, 0x86, 0xc7, ++ 0x86, 0xb9, 0x61, 0xc9, 0xea, 0x19, 0x86, 0x1f, 0xab, 0x07, 0xce, 0x37, ++ 0x72, 0x67, 0x09, 0xfc, }, ++ { 0x9e, 0xf8, 0x18, 0x67, 0x93, 0x10, 0x9b, 0x39, 0x75, 0xe8, 0x8b, 0x38, ++ 0x82, 0x7d, 0xb8, 0xb7, 0xa5, 0xaf, 0xe6, 0x6a, 0x22, 0x5e, 0x1f, 0x9c, ++ 0x95, 0x29, 0x19, 0xf2, 0x4b, }, ++ { 0xc8, 0x62, 0x25, 0xf5, 0x98, 0xc9, 0xea, 0xe5, 0x29, 0x3a, 0xd3, 0x22, ++ 0xeb, 0xeb, 0x07, 0x7c, 0x15, 0x07, 0xee, 0x15, 0x61, 0xbb, 0x05, 0x30, ++ 0x99, 0x7f, 0x11, 0xf6, 0x0a, 0x1d, }, ++ { 0x68, 0x70, 0xf7, 0x90, 0xa1, 0x8b, 0x1f, 0x0f, 0xbb, 0xce, 0xd2, 0x0e, ++ 0x33, 0x1f, 0x7f, 0xa9, 0x78, 0xa8, 0xa6, 0x81, 0x66, 0xab, 0x8d, 0xcd, ++ 0x58, 0x55, 0x3a, 0x0b, 0x7a, 0xdb, 0xb5, }, ++ { 0xdd, 0x35, 0xd2, 0xb4, 0xf6, 0xc7, 0xea, 0xab, 0x64, 0x24, 0x4e, 0xfe, ++ 0xe5, 0x3d, 0x4e, 0x95, 0x8b, 0x6d, 0x6c, 0xbc, 0xb0, 0xf8, 0x88, 0x61, ++ 0x09, 0xb7, 0x78, 0xa3, 0x31, 0xfe, 0xd9, 0x2f, }, ++ { 0x0a, }, ++ { 0x6e, 0xd4, }, ++ { 0x64, 0xe9, 0xd1, }, ++ { 0x30, 0xdd, 0x71, 0xef, }, ++ { 0x11, 0xb5, 0x0c, 0x87, 0xc9, }, ++ { 0x06, 0x1c, 0x6d, 0x04, 0x82, 0xd0, }, ++ { 0x5c, 0x42, 0x0b, 0xee, 0xc5, 0x9c, 0xb2, }, ++ { 0xe8, 0x29, 0xd6, 0xb4, 0x5d, 0xf7, 0x2b, 0x93, }, ++ { 0x18, 0xca, 0x27, 0x72, 0x43, 0x39, 0x16, 0xbc, 0x6a, }, ++ { 0x39, 0x8f, 0xfd, 0x64, 0xf5, 0x57, 0x23, 0xb0, 0x45, 0xf8, }, ++ { 0xbb, 0x3a, 0x78, 0x6b, 0x02, 0x1d, 0x0b, 0x16, 0xe3, 0xb2, 0x9a, }, ++ { 0xb8, 0xb4, 0x0b, 0xe5, 0xd4, 0x1d, 0x0d, 0x85, 0x49, 0x91, 0x35, 0xfa, }, ++ { 0x6d, 0x48, 0x2a, 0x0c, 0x42, 0x08, 0xbd, 0xa9, 0x78, 0x6f, 0x18, 0xaf, ++ 0xe2, }, ++ { 0x10, 0x45, 0xd4, 0x58, 0x88, 0xec, 0x4e, 0x1e, 0xf6, 0x14, 0x92, 0x64, ++ 0x7e, 0xb0, }, ++ { 0x8b, 0x0b, 0x95, 0xee, 0x92, 0xc6, 0x3b, 0x91, 0xf1, 0x1e, 0xeb, 0x51, ++ 0x98, 0x0a, 0x8d, }, ++ { 0xa3, 0x50, 0x4d, 0xa5, 0x1d, 0x03, 0x68, 0xe9, 0x57, 0x78, 0xd6, 0x04, ++ 0xf1, 0xc3, 0x94, 0xd8, }, ++ { 0xb8, 0x66, 0x6e, 0xdd, 0x46, 0x15, 0xae, 0x3d, 0x83, 0x7e, 0xcf, 0xe7, ++ 0x2c, 0xe8, 0x8f, 0xc7, 0x34, }, ++ { 0x2e, 0xc0, 0x1f, 0x29, 0xea, 0xf6, 0xb9, 0xe2, 0xc2, 0x93, 0xeb, 0x41, ++ 0x0d, 0xf0, 0x0a, 0x13, 0x0e, 0xa2, }, ++ { 0x71, 0xb8, 0x33, 0xa9, 0x1b, 0xac, 0xf1, 0xb5, 0x42, 0x8f, 0x5e, 0x81, ++ 0x34, 0x43, 0xb7, 0xa4, 0x18, 0x5c, 0x47, }, ++ { 0xda, 0x45, 0xb8, 0x2e, 0x82, 0x1e, 0xc0, 0x59, 0x77, 0x9d, 0xfa, 0xb4, ++ 0x1c, 0x5e, 0xa0, 0x2b, 0x33, 0x96, 0x5a, 0x58, }, ++ { 0xe3, 0x09, 0x05, 0xa9, 0xeb, 0x48, 0x13, 0xad, 0x71, 0x88, 0x81, 0x9a, ++ 0x3e, 0x2c, 0xe1, 0x23, 0x99, 0x13, 0x35, 0x9f, 0xb5, }, ++ { 0xb7, 0x86, 0x2d, 0x16, 0xe1, 0x04, 0x00, 0x47, 0x47, 0x61, 0x31, 0xfb, ++ 0x14, 0xac, 0xd8, 0xe9, 0xe3, 0x49, 0xbd, 0xf7, 0x9c, 0x3f, }, ++ { 0x7f, 0xd9, 0x95, 0xa8, 0xa7, 0xa0, 0xcc, 0xba, 0xef, 0xb1, 0x0a, 0xa9, ++ 0x21, 0x62, 0x08, 0x0f, 0x1b, 0xff, 0x7b, 0x9d, 0xae, 0xb2, 0x95, }, ++ { 0x85, 0x99, 0xea, 0x33, 0xe0, 0x56, 0xff, 0x13, 0xc6, 0x61, 0x8c, 0xf9, ++ 0x57, 0x05, 0x03, 0x11, 0xf9, 0xfb, 0x3a, 0xf7, 0xce, 0xbb, 0x52, 0x30, }, ++ { 0xb2, 0x72, 0x9c, 0xf8, 0x77, 0x4e, 0x8f, 0x6b, 0x01, 0x6c, 0xff, 0x4e, ++ 0x4f, 0x02, 0xd2, 0xbc, 0xeb, 0x51, 0x28, 0x99, 0x50, 0xab, 0xc4, 0x42, ++ 0xe3, }, ++ { 0x8b, 0x0a, 0xb5, 0x90, 0x8f, 0xf5, 0x7b, 0xdd, 0xba, 0x47, 0x37, 0xc9, ++ 0x2a, 0xd5, 0x4b, 0x25, 0x08, 0x8b, 0x02, 0x17, 0xa7, 0x9e, 0x6b, 0x6e, ++ 0xe3, 0x90, }, ++ { 0x90, 0xdd, 0xf7, 0x75, 0xa7, 0xa3, 0x99, 0x5e, 0x5b, 0x7d, 0x75, 0xc3, ++ 0x39, 0x6b, 0xa0, 0xe2, 0x44, 0x53, 0xb1, 0x9e, 0xc8, 0xf1, 0x77, 0x10, ++ 0x58, 0x06, 0x9a, }, ++ { 0x99, 0x52, 0xf0, 0x49, 0xa8, 0x8c, 0xec, 0xa6, 0x97, 0x32, 0x13, 0xb5, ++ 0xf7, 0xa3, 0x8e, 0xfb, 0x4b, 0x59, 0x31, 0x3d, 0x01, 0x59, 0x98, 0x5d, ++ 0x53, 0x03, 0x1a, 0x39, }, ++ { 0x9f, 0xe0, 0xc2, 0xe5, 0x5d, 0x93, 0xd6, 0x9b, 0x47, 0x8f, 0x9b, 0xe0, ++ 0x26, 0x35, 0x84, 0x20, 0x1d, 0xc5, 0x53, 0x10, 0x0f, 0x22, 0xb9, 0xb5, ++ 0xd4, 0x36, 0xb1, 0xac, 0x73, }, ++ { 0x30, 0x32, 0x20, 0x3b, 0x10, 0x28, 0xec, 0x1f, 0x4f, 0x9b, 0x47, 0x59, ++ 0xeb, 0x7b, 0xee, 0x45, 0xfb, 0x0c, 0x49, 0xd8, 0x3d, 0x69, 0xbd, 0x90, ++ 0x2c, 0xf0, 0x9e, 0x8d, 0xbf, 0xd5, }, ++ { 0x2a, 0x37, 0x73, 0x7f, 0xf9, 0x96, 0x19, 0xaa, 0x25, 0xd8, 0x13, 0x28, ++ 0x01, 0x29, 0x89, 0xdf, 0x6e, 0x0c, 0x9b, 0x43, 0x44, 0x51, 0xe9, 0x75, ++ 0x26, 0x0c, 0xb7, 0x87, 0x66, 0x0b, 0x5f, }, ++ { 0x23, 0xdf, 0x96, 0x68, 0x91, 0x86, 0xd0, 0x93, 0x55, 0x33, 0x24, 0xf6, ++ 0xba, 0x08, 0x75, 0x5b, 0x59, 0x11, 0x69, 0xb8, 0xb9, 0xe5, 0x2c, 0x77, ++ 0x02, 0xf6, 0x47, 0xee, 0x81, 0xdd, 0xb9, 0x06, }, ++ { 0x9d, }, ++ { 0x9d, 0x7d, }, ++ { 0xfd, 0xc3, 0xda, }, ++ { 0xe8, 0x82, 0xcd, 0x21, }, ++ { 0xc3, 0x1d, 0x42, 0x4c, 0x74, }, ++ { 0xe9, 0xda, 0xf1, 0xa2, 0xe5, 0x7c, }, ++ { 0x52, 0xb8, 0x6f, 0x81, 0x5c, 0x3a, 0x4c, }, ++ { 0x5b, 0x39, 0x26, 0xfc, 0x92, 0x5e, 0xe0, 0x49, }, ++ { 0x59, 0xe4, 0x7c, 0x93, 0x1c, 0xf9, 0x28, 0x93, 0xde, }, ++ { 0xde, 0xdf, 0xb2, 0x43, 0x61, 0x0b, 0x86, 0x16, 0x4c, 0x2e, }, ++ { 0x14, 0x8f, 0x75, 0x51, 0xaf, 0xb9, 0xee, 0x51, 0x5a, 0xae, 0x23, }, ++ { 0x43, 0x5f, 0x50, 0xd5, 0x70, 0xb0, 0x5b, 0x87, 0xf5, 0xd9, 0xb3, 0x6d, }, ++ { 0x66, 0x0a, 0x64, 0x93, 0x79, 0x71, 0x94, 0x40, 0xb7, 0x68, 0x2d, 0xd3, ++ 0x63, }, ++ { 0x15, 0x00, 0xc4, 0x0c, 0x7d, 0x1b, 0x10, 0xa9, 0x73, 0x1b, 0x90, 0x6f, ++ 0xe6, 0xa9, }, ++ { 0x34, 0x75, 0xf3, 0x86, 0x8f, 0x56, 0xcf, 0x2a, 0x0a, 0xf2, 0x62, 0x0a, ++ 0xf6, 0x0e, 0x20, }, ++ { 0xb1, 0xde, 0xc9, 0xf5, 0xdb, 0xf3, 0x2f, 0x4c, 0xd6, 0x41, 0x7d, 0x39, ++ 0x18, 0x3e, 0xc7, 0xc3, }, ++ { 0xc5, 0x89, 0xb2, 0xf8, 0xb8, 0xc0, 0xa3, 0xb9, 0x3b, 0x10, 0x6d, 0x7c, ++ 0x92, 0xfc, 0x7f, 0x34, 0x41, }, ++ { 0xc4, 0xd8, 0xef, 0xba, 0xef, 0xd2, 0xaa, 0xc5, 0x6c, 0x8e, 0x3e, 0xbb, ++ 0x12, 0xfc, 0x0f, 0x72, 0xbf, 0x0f, }, ++ { 0xdd, 0x91, 0xd1, 0x15, 0x9e, 0x7d, 0xf8, 0xc1, 0xb9, 0x14, 0x63, 0x96, ++ 0xb5, 0xcb, 0x83, 0x1d, 0x35, 0x1c, 0xec, }, ++ { 0xa9, 0xf8, 0x52, 0xc9, 0x67, 0x76, 0x2b, 0xad, 0xfb, 0xd8, 0x3a, 0xa6, ++ 0x74, 0x02, 0xae, 0xb8, 0x25, 0x2c, 0x63, 0x49, }, ++ { 0x77, 0x1f, 0x66, 0x70, 0xfd, 0x50, 0x29, 0xaa, 0xeb, 0xdc, 0xee, 0xba, ++ 0x75, 0x98, 0xdc, 0x93, 0x12, 0x3f, 0xdc, 0x7c, 0x38, }, ++ { 0xe2, 0xe1, 0x89, 0x5c, 0x37, 0x38, 0x6a, 0xa3, 0x40, 0xac, 0x3f, 0xb0, ++ 0xca, 0xfc, 0xa7, 0xf3, 0xea, 0xf9, 0x0f, 0x5d, 0x8e, 0x39, }, ++ { 0x0f, 0x67, 0xc8, 0x38, 0x01, 0xb1, 0xb7, 0xb8, 0xa2, 0xe7, 0x0a, 0x6d, ++ 0xd2, 0x63, 0x69, 0x9e, 0xcc, 0xf0, 0xf2, 0xbe, 0x9b, 0x98, 0xdd, }, ++ { 0x13, 0xe1, 0x36, 0x30, 0xfe, 0xc6, 0x01, 0x8a, 0xa1, 0x63, 0x96, 0x59, ++ 0xc2, 0xa9, 0x68, 0x3f, 0x58, 0xd4, 0x19, 0x0c, 0x40, 0xf3, 0xde, 0x02, }, ++ { 0xa3, 0x9e, 0xce, 0xda, 0x42, 0xee, 0x8c, 0x6c, 0x5a, 0x7d, 0xdc, 0x89, ++ 0x02, 0x77, 0xdd, 0xe7, 0x95, 0xbb, 0xff, 0x0d, 0xa4, 0xb5, 0x38, 0x1e, ++ 0xaf, }, ++ { 0x9a, 0xf6, 0xb5, 0x9a, 0x4f, 0xa9, 0x4f, 0x2c, 0x35, 0x3c, 0x24, 0xdc, ++ 0x97, 0x6f, 0xd9, 0xa1, 0x7d, 0x1a, 0x85, 0x0b, 0xf5, 0xda, 0x2e, 0xe7, ++ 0xb1, 0x1d, }, ++ { 0x84, 0x1e, 0x8e, 0x3d, 0x45, 0xa5, 0xf2, 0x27, 0xf3, 0x31, 0xfe, 0xb9, ++ 0xfb, 0xc5, 0x45, 0x99, 0x99, 0xdd, 0x93, 0x43, 0x02, 0xee, 0x58, 0xaf, ++ 0xee, 0x6a, 0xbe, }, ++ { 0x07, 0x2f, 0xc0, 0xa2, 0x04, 0xc4, 0xab, 0x7c, 0x26, 0xbb, 0xa8, 0xd8, ++ 0xe3, 0x1c, 0x75, 0x15, 0x64, 0x5d, 0x02, 0x6a, 0xf0, 0x86, 0xe9, 0xcd, ++ 0x5c, 0xef, 0xa3, 0x25, }, ++ { 0x2f, 0x3b, 0x1f, 0xb5, 0x91, 0x8f, 0x86, 0xe0, 0xdc, 0x31, 0x48, 0xb6, ++ 0xa1, 0x8c, 0xfd, 0x75, 0xbb, 0x7d, 0x3d, 0xc1, 0xf0, 0x10, 0x9a, 0xd8, ++ 0x4b, 0x0e, 0xe3, 0x94, 0x9f, }, ++ { 0x29, 0xbb, 0x8f, 0x6c, 0xd1, 0xf2, 0xb6, 0xaf, 0xe5, 0xe3, 0x2d, 0xdc, ++ 0x6f, 0xa4, 0x53, 0x88, 0xd8, 0xcf, 0x4d, 0x45, 0x42, 0x62, 0xdb, 0xdf, ++ 0xf8, 0x45, 0xc2, 0x13, 0xec, 0x35, }, ++ { 0x06, 0x3c, 0xe3, 0x2c, 0x15, 0xc6, 0x43, 0x03, 0x81, 0xfb, 0x08, 0x76, ++ 0x33, 0xcb, 0x02, 0xc1, 0xba, 0x33, 0xe5, 0xe0, 0xd1, 0x92, 0xa8, 0x46, ++ 0x28, 0x3f, 0x3e, 0x9d, 0x2c, 0x44, 0x54, }, ++ { 0xea, 0xbb, 0x96, 0xf8, 0xd1, 0x8b, 0x04, 0x11, 0x40, 0x78, 0x42, 0x02, ++ 0x19, 0xd1, 0xbc, 0x65, 0x92, 0xd3, 0xc3, 0xd6, 0xd9, 0x19, 0xe7, 0xc3, ++ 0x40, 0x97, 0xbd, 0xd4, 0xed, 0xfa, 0x5e, 0x28, }, ++ { 0x02, }, ++ { 0x52, 0xa8, }, ++ { 0x38, 0x25, 0x0d, }, ++ { 0xe3, 0x04, 0xd4, 0x92, }, ++ { 0x97, 0xdb, 0xf7, 0x81, 0xca, }, ++ { 0x8a, 0x56, 0x9d, 0x62, 0x56, 0xcc, }, ++ { 0xa1, 0x8e, 0x3c, 0x72, 0x8f, 0x63, 0x03, }, ++ { 0xf7, 0xf3, 0x39, 0x09, 0x0a, 0xa1, 0xbb, 0x23, }, ++ { 0x6b, 0x03, 0xc0, 0xe9, 0xd9, 0x83, 0x05, 0x22, 0x01, }, ++ { 0x1b, 0x4b, 0xf5, 0xd6, 0x4f, 0x05, 0x75, 0x91, 0x4c, 0x7f, }, ++ { 0x4c, 0x8c, 0x25, 0x20, 0x21, 0xcb, 0xc2, 0x4b, 0x3a, 0x5b, 0x8d, }, ++ { 0x56, 0xe2, 0x77, 0xa0, 0xb6, 0x9f, 0x81, 0xec, 0x83, 0x75, 0xc4, 0xf9, }, ++ { 0x71, 0x70, 0x0f, 0xad, 0x4d, 0x35, 0x81, 0x9d, 0x88, 0x69, 0xf9, 0xaa, ++ 0xd3, }, ++ { 0x50, 0x6e, 0x86, 0x6e, 0x43, 0xc0, 0xc2, 0x44, 0xc2, 0xe2, 0xa0, 0x1c, ++ 0xb7, 0x9a, }, ++ { 0xe4, 0x7e, 0x72, 0xc6, 0x12, 0x8e, 0x7c, 0xfc, 0xbd, 0xe2, 0x08, 0x31, ++ 0x3d, 0x47, 0x3d, }, ++ { 0x08, 0x97, 0x5b, 0x80, 0xae, 0xc4, 0x1d, 0x50, 0x77, 0xdf, 0x1f, 0xd0, ++ 0x24, 0xf0, 0x17, 0xc0, }, ++ { 0x01, 0xb6, 0x29, 0xf4, 0xaf, 0x78, 0x5f, 0xb6, 0x91, 0xdd, 0x76, 0x76, ++ 0xd2, 0xfd, 0x0c, 0x47, 0x40, }, ++ { 0xa1, 0xd8, 0x09, 0x97, 0x7a, 0xa6, 0xc8, 0x94, 0xf6, 0x91, 0x7b, 0xae, ++ 0x2b, 0x9f, 0x0d, 0x83, 0x48, 0xf7, }, ++ { 0x12, 0xd5, 0x53, 0x7d, 0x9a, 0xb0, 0xbe, 0xd9, 0xed, 0xe9, 0x9e, 0xee, ++ 0x61, 0x5b, 0x42, 0xf2, 0xc0, 0x73, 0xc0, }, ++ { 0xd5, 0x77, 0xd6, 0x5c, 0x6e, 0xa5, 0x69, 0x2b, 0x3b, 0x8c, 0xd6, 0x7d, ++ 0x1d, 0xbe, 0x2c, 0xa1, 0x02, 0x21, 0xcd, 0x29, }, ++ { 0xa4, 0x98, 0x80, 0xca, 0x22, 0xcf, 0x6a, 0xab, 0x5e, 0x40, 0x0d, 0x61, ++ 0x08, 0x21, 0xef, 0xc0, 0x6c, 0x52, 0xb4, 0xb0, 0x53, }, ++ { 0xbf, 0xaf, 0x8f, 0x3b, 0x7a, 0x97, 0x33, 0xe5, 0xca, 0x07, 0x37, 0xfd, ++ 0x15, 0xdf, 0xce, 0x26, 0x2a, 0xb1, 0xa7, 0x0b, 0xb3, 0xac, }, ++ { 0x16, 0x22, 0xe1, 0xbc, 0x99, 0x4e, 0x01, 0xf0, 0xfa, 0xff, 0x8f, 0xa5, ++ 0x0c, 0x61, 0xb0, 0xad, 0xcc, 0xb1, 0xe1, 0x21, 0x46, 0xfa, 0x2e, }, ++ { 0x11, 0x5b, 0x0b, 0x2b, 0xe6, 0x14, 0xc1, 0xd5, 0x4d, 0x71, 0x5e, 0x17, ++ 0xea, 0x23, 0xdd, 0x6c, 0xbd, 0x1d, 0xbe, 0x12, 0x1b, 0xee, 0x4c, 0x1a, }, ++ { 0x40, 0x88, 0x22, 0xf3, 0x20, 0x6c, 0xed, 0xe1, 0x36, 0x34, 0x62, 0x2c, ++ 0x98, 0x83, 0x52, 0xe2, 0x25, 0xee, 0xe9, 0xf5, 0xe1, 0x17, 0xf0, 0x5c, ++ 0xae, }, ++ { 0xc3, 0x76, 0x37, 0xde, 0x95, 0x8c, 0xca, 0x2b, 0x0c, 0x23, 0xe7, 0xb5, ++ 0x38, 0x70, 0x61, 0xcc, 0xff, 0xd3, 0x95, 0x7b, 0xf3, 0xff, 0x1f, 0x9d, ++ 0x59, 0x00, }, ++ { 0x0c, 0x19, 0x52, 0x05, 0x22, 0x53, 0xcb, 0x48, 0xd7, 0x10, 0x0e, 0x7e, ++ 0x14, 0x69, 0xb5, 0xa2, 0x92, 0x43, 0xa3, 0x9e, 0x4b, 0x8f, 0x51, 0x2c, ++ 0x5a, 0x2c, 0x3b, }, ++ { 0xe1, 0x9d, 0x70, 0x70, 0x28, 0xec, 0x86, 0x40, 0x55, 0x33, 0x56, 0xda, ++ 0x88, 0xca, 0xee, 0xc8, 0x6a, 0x20, 0xb1, 0xe5, 0x3d, 0x57, 0xf8, 0x3c, ++ 0x10, 0x07, 0x2a, 0xc4, }, ++ { 0x0b, 0xae, 0xf1, 0xc4, 0x79, 0xee, 0x1b, 0x3d, 0x27, 0x35, 0x8d, 0x14, ++ 0xd6, 0xae, 0x4e, 0x3c, 0xe9, 0x53, 0x50, 0xb5, 0xcc, 0x0c, 0xf7, 0xdf, ++ 0xee, 0xa1, 0x74, 0xd6, 0x71, }, ++ { 0xe6, 0xa4, 0xf4, 0x99, 0x98, 0xb9, 0x80, 0xea, 0x96, 0x7f, 0x4f, 0x33, ++ 0xcf, 0x74, 0x25, 0x6f, 0x17, 0x6c, 0xbf, 0xf5, 0x5c, 0x38, 0xd0, 0xff, ++ 0x96, 0xcb, 0x13, 0xf9, 0xdf, 0xfd, }, ++ { 0xbe, 0x92, 0xeb, 0xba, 0x44, 0x2c, 0x24, 0x74, 0xd4, 0x03, 0x27, 0x3c, ++ 0x5d, 0x5b, 0x03, 0x30, 0x87, 0x63, 0x69, 0xe0, 0xb8, 0x94, 0xf4, 0x44, ++ 0x7e, 0xad, 0xcd, 0x20, 0x12, 0x16, 0x79, }, ++ { 0x30, 0xf1, 0xc4, 0x8e, 0x05, 0x90, 0x2a, 0x97, 0x63, 0x94, 0x46, 0xff, ++ 0xce, 0xd8, 0x67, 0xa7, 0xac, 0x33, 0x8c, 0x95, 0xb7, 0xcd, 0xa3, 0x23, ++ 0x98, 0x9d, 0x76, 0x6c, 0x9d, 0xa8, 0xd6, 0x8a, }, ++ { 0xbe, }, ++ { 0x17, 0x6c, }, ++ { 0x1a, 0x42, 0x4f, }, ++ { 0xba, 0xaf, 0xb7, 0x65, }, ++ { 0xc2, 0x63, 0x43, 0x6a, 0xea, }, ++ { 0xe4, 0x4d, 0xad, 0xf2, 0x0b, 0x02, }, ++ { 0x04, 0xc7, 0xc4, 0x7f, 0xa9, 0x2b, 0xce, }, ++ { 0x66, 0xf6, 0x67, 0xcb, 0x03, 0x53, 0xc8, 0xf1, }, ++ { 0x56, 0xa3, 0x60, 0x78, 0xc9, 0x5f, 0x70, 0x1b, 0x5e, }, ++ { 0x99, 0xff, 0x81, 0x7c, 0x13, 0x3c, 0x29, 0x79, 0x4b, 0x65, }, ++ { 0x51, 0x10, 0x50, 0x93, 0x01, 0x93, 0xb7, 0x01, 0xc9, 0x18, 0xb7, }, ++ { 0x8e, 0x3c, 0x42, 0x1e, 0x5e, 0x7d, 0xc1, 0x50, 0x70, 0x1f, 0x00, 0x98, }, ++ { 0x5f, 0xd9, 0x9b, 0xc8, 0xd7, 0xb2, 0x72, 0x62, 0x1a, 0x1e, 0xba, 0x92, ++ 0xe9, }, ++ { 0x70, 0x2b, 0xba, 0xfe, 0xad, 0x5d, 0x96, 0x3f, 0x27, 0xc2, 0x41, 0x6d, ++ 0xc4, 0xb3, }, ++ { 0xae, 0xe0, 0xd5, 0xd4, 0xc7, 0xae, 0x15, 0x5e, 0xdc, 0xdd, 0x33, 0x60, ++ 0xd7, 0xd3, 0x5e, }, ++ { 0x79, 0x8e, 0xbc, 0x9e, 0x20, 0xb9, 0x19, 0x4b, 0x63, 0x80, 0xf3, 0x16, ++ 0xaf, 0x39, 0xbd, 0x92, }, ++ { 0xc2, 0x0e, 0x85, 0xa0, 0x0b, 0x9a, 0xb0, 0xec, 0xde, 0x38, 0xd3, 0x10, ++ 0xd9, 0xa7, 0x66, 0x27, 0xcf, }, ++ { 0x0e, 0x3b, 0x75, 0x80, 0x67, 0x14, 0x0c, 0x02, 0x90, 0xd6, 0xb3, 0x02, ++ 0x81, 0xf6, 0xa6, 0x87, 0xce, 0x58, }, ++ { 0x79, 0xb5, 0xe9, 0x5d, 0x52, 0x4d, 0xf7, 0x59, 0xf4, 0x2e, 0x27, 0xdd, ++ 0xb3, 0xed, 0x57, 0x5b, 0x82, 0xea, 0x6f, }, ++ { 0xa2, 0x97, 0xf5, 0x80, 0x02, 0x3d, 0xde, 0xa3, 0xf9, 0xf6, 0xab, 0xe3, ++ 0x57, 0x63, 0x7b, 0x9b, 0x10, 0x42, 0x6f, 0xf2, }, ++ { 0x12, 0x7a, 0xfc, 0xb7, 0x67, 0x06, 0x0c, 0x78, 0x1a, 0xfe, 0x88, 0x4f, ++ 0xc6, 0xac, 0x52, 0x96, 0x64, 0x28, 0x97, 0x84, 0x06, }, ++ { 0xc5, 0x04, 0x44, 0x6b, 0xb2, 0xa5, 0xa4, 0x66, 0xe1, 0x76, 0xa2, 0x51, ++ 0xf9, 0x59, 0x69, 0x97, 0x56, 0x0b, 0xbf, 0x50, 0xb3, 0x34, }, ++ { 0x21, 0x32, 0x6b, 0x42, 0xb5, 0xed, 0x71, 0x8d, 0xf7, 0x5a, 0x35, 0xe3, ++ 0x90, 0xe2, 0xee, 0xaa, 0x89, 0xf6, 0xc9, 0x9c, 0x4d, 0x73, 0xf4, }, ++ { 0x4c, 0xa6, 0x09, 0xf4, 0x48, 0xe7, 0x46, 0xbc, 0x49, 0xfc, 0xe5, 0xda, ++ 0xd1, 0x87, 0x13, 0x17, 0x4c, 0x59, 0x71, 0x26, 0x5b, 0x2c, 0x42, 0xb7, }, ++ { 0x13, 0x63, 0xf3, 0x40, 0x02, 0xe5, 0xa3, 0x3a, 0x5e, 0x8e, 0xf8, 0xb6, ++ 0x8a, 0x49, 0x60, 0x76, 0x34, 0x72, 0x94, 0x73, 0xf6, 0xd9, 0x21, 0x6a, ++ 0x26, }, ++ { 0xdf, 0x75, 0x16, 0x10, 0x1b, 0x5e, 0x81, 0xc3, 0xc8, 0xde, 0x34, 0x24, ++ 0xb0, 0x98, 0xeb, 0x1b, 0x8f, 0xa1, 0x9b, 0x05, 0xee, 0xa5, 0xe9, 0x35, ++ 0xf4, 0x1d, }, ++ { 0xcd, 0x21, 0x93, 0x6e, 0x5b, 0xa0, 0x26, 0x2b, 0x21, 0x0e, 0xa0, 0xb9, ++ 0x1c, 0xb5, 0xbb, 0xb8, 0xf8, 0x1e, 0xff, 0x5c, 0xa8, 0xf9, 0x39, 0x46, ++ 0x4e, 0x29, 0x26, }, ++ { 0x73, 0x7f, 0x0e, 0x3b, 0x0b, 0x5c, 0xf9, 0x60, 0xaa, 0x88, 0xa1, 0x09, ++ 0xb1, 0x5d, 0x38, 0x7b, 0x86, 0x8f, 0x13, 0x7a, 0x8d, 0x72, 0x7a, 0x98, ++ 0x1a, 0x5b, 0xff, 0xc9, }, ++ { 0xd3, 0x3c, 0x61, 0x71, 0x44, 0x7e, 0x31, 0x74, 0x98, 0x9d, 0x9a, 0xd2, ++ 0x27, 0xf3, 0x46, 0x43, 0x42, 0x51, 0xd0, 0x5f, 0xe9, 0x1c, 0x5c, 0x69, ++ 0xbf, 0xf6, 0xbe, 0x3c, 0x40, }, ++ { 0x31, 0x99, 0x31, 0x9f, 0xaa, 0x43, 0x2e, 0x77, 0x3e, 0x74, 0x26, 0x31, ++ 0x5e, 0x61, 0xf1, 0x87, 0xe2, 0xeb, 0x9b, 0xcd, 0xd0, 0x3a, 0xee, 0x20, ++ 0x7e, 0x10, 0x0a, 0x0b, 0x7e, 0xfa, }, ++ { 0xa4, 0x27, 0x80, 0x67, 0x81, 0x2a, 0xa7, 0x62, 0xf7, 0x6e, 0xda, 0xd4, ++ 0x5c, 0x39, 0x74, 0xad, 0x7e, 0xbe, 0xad, 0xa5, 0x84, 0x7f, 0xa9, 0x30, ++ 0x5d, 0xdb, 0xe2, 0x05, 0x43, 0xf7, 0x1b, }, ++ { 0x0b, 0x37, 0xd8, 0x02, 0xe1, 0x83, 0xd6, 0x80, 0xf2, 0x35, 0xc2, 0xb0, ++ 0x37, 0xef, 0xef, 0x5e, 0x43, 0x93, 0xf0, 0x49, 0x45, 0x0a, 0xef, 0xb5, ++ 0x76, 0x70, 0x12, 0x44, 0xc4, 0xdb, 0xf5, 0x7a, }, ++ { 0x1f, }, ++ { 0x82, 0x60, }, ++ { 0xcc, 0xe3, 0x08, }, ++ { 0x56, 0x17, 0xe4, 0x59, }, ++ { 0xe2, 0xd7, 0x9e, 0xc4, 0x4c, }, ++ { 0xb2, 0xad, 0xd3, 0x78, 0x58, 0x5a, }, ++ { 0xce, 0x43, 0xb4, 0x02, 0x96, 0xab, 0x3c, }, ++ { 0xe6, 0x05, 0x1a, 0x73, 0x22, 0x32, 0xbb, 0x77, }, ++ { 0x23, 0xe7, 0xda, 0xfe, 0x2c, 0xef, 0x8c, 0x22, 0xec, }, ++ { 0xe9, 0x8e, 0x55, 0x38, 0xd1, 0xd7, 0x35, 0x23, 0x98, 0xc7, }, ++ { 0xb5, 0x81, 0x1a, 0xe5, 0xb5, 0xa5, 0xd9, 0x4d, 0xca, 0x41, 0xe7, }, ++ { 0x41, 0x16, 0x16, 0x95, 0x8d, 0x9e, 0x0c, 0xea, 0x8c, 0x71, 0x9a, 0xc1, }, ++ { 0x7c, 0x33, 0xc0, 0xa4, 0x00, 0x62, 0xea, 0x60, 0x67, 0xe4, 0x20, 0xbc, ++ 0x5b, }, ++ { 0xdb, 0xb1, 0xdc, 0xfd, 0x08, 0xc0, 0xde, 0x82, 0xd1, 0xde, 0x38, 0xc0, ++ 0x90, 0x48, }, ++ { 0x37, 0x18, 0x2e, 0x0d, 0x61, 0xaa, 0x61, 0xd7, 0x86, 0x20, 0x16, 0x60, ++ 0x04, 0xd9, 0xd5, }, ++ { 0xb0, 0xcf, 0x2c, 0x4c, 0x5e, 0x5b, 0x4f, 0x2a, 0x23, 0x25, 0x58, 0x47, ++ 0xe5, 0x31, 0x06, 0x70, }, ++ { 0x91, 0xa0, 0xa3, 0x86, 0x4e, 0xe0, 0x72, 0x38, 0x06, 0x67, 0x59, 0x5c, ++ 0x70, 0x25, 0xdb, 0x33, 0x27, }, ++ { 0x44, 0x58, 0x66, 0xb8, 0x58, 0xc7, 0x13, 0xed, 0x4c, 0xc0, 0xf4, 0x9a, ++ 0x1e, 0x67, 0x75, 0x33, 0xb6, 0xb8, }, ++ { 0x7f, 0x98, 0x4a, 0x8e, 0x50, 0xa2, 0x5c, 0xcd, 0x59, 0xde, 0x72, 0xb3, ++ 0x9d, 0xc3, 0x09, 0x8a, 0xab, 0x56, 0xf1, }, ++ { 0x80, 0x96, 0x49, 0x1a, 0x59, 0xa2, 0xc5, 0xd5, 0xa7, 0x20, 0x8a, 0xb7, ++ 0x27, 0x62, 0x84, 0x43, 0xc6, 0xe1, 0x1b, 0x5d, }, ++ { 0x6b, 0xb7, 0x2b, 0x26, 0x62, 0x14, 0x70, 0x19, 0x3d, 0x4d, 0xac, 0xac, ++ 0x63, 0x58, 0x5e, 0x94, 0xb5, 0xb7, 0xe8, 0xe8, 0xa2, }, ++ { 0x20, 0xa8, 0xc0, 0xfd, 0x63, 0x3d, 0x6e, 0x98, 0xcf, 0x0c, 0x49, 0x98, ++ 0xe4, 0x5a, 0xfe, 0x8c, 0xaa, 0x70, 0x82, 0x1c, 0x7b, 0x74, }, ++ { 0xc8, 0xe8, 0xdd, 0xdf, 0x69, 0x30, 0x01, 0xc2, 0x0f, 0x7e, 0x2f, 0x11, ++ 0xcc, 0x3e, 0x17, 0xa5, 0x69, 0x40, 0x3f, 0x0e, 0x79, 0x7f, 0xcf, }, ++ { 0xdb, 0x61, 0xc0, 0xe2, 0x2e, 0x49, 0x07, 0x31, 0x1d, 0x91, 0x42, 0x8a, ++ 0xfc, 0x5e, 0xd3, 0xf8, 0x56, 0x1f, 0x2b, 0x73, 0xfd, 0x9f, 0xb2, 0x8e, }, ++ { 0x0c, 0x89, 0x55, 0x0c, 0x1f, 0x59, 0x2c, 0x9d, 0x1b, 0x29, 0x1d, 0x41, ++ 0x1d, 0xe6, 0x47, 0x8f, 0x8c, 0x2b, 0xea, 0x8f, 0xf0, 0xff, 0x21, 0x70, ++ 0x88, }, ++ { 0x12, 0x18, 0x95, 0xa6, 0x59, 0xb1, 0x31, 0x24, 0x45, 0x67, 0x55, 0xa4, ++ 0x1a, 0x2d, 0x48, 0x67, 0x1b, 0x43, 0x88, 0x2d, 0x8e, 0xa0, 0x70, 0xb3, ++ 0xc6, 0xbb, }, ++ { 0xe7, 0xb1, 0x1d, 0xb2, 0x76, 0x4d, 0x68, 0x68, 0x68, 0x23, 0x02, 0x55, ++ 0x3a, 0xe2, 0xe5, 0xd5, 0x4b, 0x43, 0xf9, 0x34, 0x77, 0x5c, 0xa1, 0xf5, ++ 0x55, 0xfd, 0x4f, }, ++ { 0x8c, 0x87, 0x5a, 0x08, 0x3a, 0x73, 0xad, 0x61, 0xe1, 0xe7, 0x99, 0x7e, ++ 0xf0, 0x5d, 0xe9, 0x5d, 0x16, 0x43, 0x80, 0x2f, 0xd0, 0x66, 0x34, 0xe2, ++ 0x42, 0x64, 0x3b, 0x1a, }, ++ { 0x39, 0xc1, 0x99, 0xcf, 0x22, 0xbf, 0x16, 0x8f, 0x9f, 0x80, 0x7f, 0x95, ++ 0x0a, 0x05, 0x67, 0x27, 0xe7, 0x15, 0xdf, 0x9d, 0xb2, 0xfe, 0x1c, 0xb5, ++ 0x1d, 0x60, 0x8f, 0x8a, 0x1d, }, ++ { 0x9b, 0x6e, 0x08, 0x09, 0x06, 0x73, 0xab, 0x68, 0x02, 0x62, 0x1a, 0xe4, ++ 0xd4, 0xdf, 0xc7, 0x02, 0x4c, 0x6a, 0x5f, 0xfd, 0x23, 0xac, 0xae, 0x6d, ++ 0x43, 0xa4, 0x7a, 0x50, 0x60, 0x3c, }, ++ { 0x1d, 0xb4, 0xc6, 0xe1, 0xb1, 0x4b, 0xe3, 0xf2, 0xe2, 0x1a, 0x73, 0x1b, ++ 0xa0, 0x92, 0xa7, 0xf5, 0xff, 0x8f, 0x8b, 0x5d, 0xdf, 0xa8, 0x04, 0xb3, ++ 0xb0, 0xf7, 0xcc, 0x12, 0xfa, 0x35, 0x46, }, ++ { 0x49, 0x45, 0x97, 0x11, 0x0f, 0x1c, 0x60, 0x8e, 0xe8, 0x47, 0x30, 0xcf, ++ 0x60, 0xa8, 0x71, 0xc5, 0x1b, 0xe9, 0x39, 0x4d, 0x49, 0xb6, 0x12, 0x1f, ++ 0x24, 0xab, 0x37, 0xff, 0x83, 0xc2, 0xe1, 0x3a, }, ++ { 0x60, }, ++ { 0x24, 0x26, }, ++ { 0x47, 0xeb, 0xc9, }, ++ { 0x4a, 0xd0, 0xbc, 0xf0, }, ++ { 0x8e, 0x2b, 0xc9, 0x85, 0x3c, }, ++ { 0xa2, 0x07, 0x15, 0xb8, 0x12, 0x74, }, ++ { 0x0f, 0xdb, 0x5b, 0x33, 0x69, 0xfe, 0x4b, }, ++ { 0xa2, 0x86, 0x54, 0xf4, 0xfd, 0xb2, 0xd4, 0xe6, }, ++ { 0xbb, 0x84, 0x78, 0x49, 0x27, 0x8e, 0x61, 0xda, 0x60, }, ++ { 0x04, 0xc3, 0xcd, 0xaa, 0x8f, 0xa7, 0x03, 0xc9, 0xf9, 0xb6, }, ++ { 0xf8, 0x27, 0x1d, 0x61, 0xdc, 0x21, 0x42, 0xdd, 0xad, 0x92, 0x40, }, ++ { 0x12, 0x87, 0xdf, 0xc2, 0x41, 0x45, 0x5a, 0x36, 0x48, 0x5b, 0x51, 0x2b, }, ++ { 0xbb, 0x37, 0x5d, 0x1f, 0xf1, 0x68, 0x7a, 0xc4, 0xa5, 0xd2, 0xa4, 0x91, ++ 0x8d, }, ++ { 0x5b, 0x27, 0xd1, 0x04, 0x54, 0x52, 0x9f, 0xa3, 0x47, 0x86, 0x33, 0x33, ++ 0xbf, 0xa0, }, ++ { 0xcf, 0x04, 0xea, 0xf8, 0x03, 0x2a, 0x43, 0xff, 0xa6, 0x68, 0x21, 0x4c, ++ 0xd5, 0x4b, 0xed, }, ++ { 0xaf, 0xb8, 0xbc, 0x63, 0x0f, 0x18, 0x4d, 0xe2, 0x7a, 0xdd, 0x46, 0x44, ++ 0xc8, 0x24, 0x0a, 0xb7, }, ++ { 0x3e, 0xdc, 0x36, 0xe4, 0x89, 0xb1, 0xfa, 0xc6, 0x40, 0x93, 0x2e, 0x75, ++ 0xb2, 0x15, 0xd1, 0xb1, 0x10, }, ++ { 0x6c, 0xd8, 0x20, 0x3b, 0x82, 0x79, 0xf9, 0xc8, 0xbc, 0x9d, 0xe0, 0x35, ++ 0xbe, 0x1b, 0x49, 0x1a, 0xbc, 0x3a, }, ++ { 0x78, 0x65, 0x2c, 0xbe, 0x35, 0x67, 0xdc, 0x78, 0xd4, 0x41, 0xf6, 0xc9, ++ 0xde, 0xde, 0x1f, 0x18, 0x13, 0x31, 0x11, }, ++ { 0x8a, 0x7f, 0xb1, 0x33, 0x8f, 0x0c, 0x3c, 0x0a, 0x06, 0x61, 0xf0, 0x47, ++ 0x29, 0x1b, 0x29, 0xbc, 0x1c, 0x47, 0xef, 0x7a, }, ++ { 0x65, 0x91, 0xf1, 0xe6, 0xb3, 0x96, 0xd3, 0x8c, 0xc2, 0x4a, 0x59, 0x35, ++ 0x72, 0x8e, 0x0b, 0x9a, 0x87, 0xca, 0x34, 0x7b, 0x63, }, ++ { 0x5f, 0x08, 0x87, 0x80, 0x56, 0x25, 0x89, 0x77, 0x61, 0x8c, 0x64, 0xa1, ++ 0x59, 0x6d, 0x59, 0x62, 0xe8, 0x4a, 0xc8, 0x58, 0x99, 0xd1, }, ++ { 0x23, 0x87, 0x1d, 0xed, 0x6f, 0xf2, 0x91, 0x90, 0xe2, 0xfe, 0x43, 0x21, ++ 0xaf, 0x97, 0xc6, 0xbc, 0xd7, 0x15, 0xc7, 0x2d, 0x08, 0x77, 0x91, }, ++ { 0x90, 0x47, 0x9a, 0x9e, 0x3a, 0xdf, 0xf3, 0xc9, 0x4c, 0x1e, 0xa7, 0xd4, ++ 0x6a, 0x32, 0x90, 0xfe, 0xb7, 0xb6, 0x7b, 0xfa, 0x96, 0x61, 0xfb, 0xa4, }, ++ { 0xb1, 0x67, 0x60, 0x45, 0xb0, 0x96, 0xc5, 0x15, 0x9f, 0x4d, 0x26, 0xd7, ++ 0x9d, 0xf1, 0xf5, 0x6d, 0x21, 0x00, 0x94, 0x31, 0x64, 0x94, 0xd3, 0xa7, ++ 0xd3, }, ++ { 0x02, 0x3e, 0xaf, 0xf3, 0x79, 0x73, 0xa5, 0xf5, 0xcc, 0x7a, 0x7f, 0xfb, ++ 0x79, 0x2b, 0x85, 0x8c, 0x88, 0x72, 0x06, 0xbe, 0xfe, 0xaf, 0xc1, 0x16, ++ 0xa6, 0xd6, }, ++ { 0x2a, 0xb0, 0x1a, 0xe5, 0xaa, 0x6e, 0xb3, 0xae, 0x53, 0x85, 0x33, 0x80, ++ 0x75, 0xae, 0x30, 0xe6, 0xb8, 0x72, 0x42, 0xf6, 0x25, 0x4f, 0x38, 0x88, ++ 0x55, 0xd1, 0xa9, }, ++ { 0x90, 0xd8, 0x0c, 0xc0, 0x93, 0x4b, 0x4f, 0x9e, 0x65, 0x6c, 0xa1, 0x54, ++ 0xa6, 0xf6, 0x6e, 0xca, 0xd2, 0xbb, 0x7e, 0x6a, 0x1c, 0xd3, 0xce, 0x46, ++ 0xef, 0xb0, 0x00, 0x8d, }, ++ { 0xed, 0x9c, 0x49, 0xcd, 0xc2, 0xde, 0x38, 0x0e, 0xe9, 0x98, 0x6c, 0xc8, ++ 0x90, 0x9e, 0x3c, 0xd4, 0xd3, 0xeb, 0x88, 0x32, 0xc7, 0x28, 0xe3, 0x94, ++ 0x1c, 0x9f, 0x8b, 0xf3, 0xcb, }, ++ { 0xac, 0xe7, 0x92, 0x16, 0xb4, 0x14, 0xa0, 0xe4, 0x04, 0x79, 0xa2, 0xf4, ++ 0x31, 0xe6, 0x0c, 0x26, 0xdc, 0xbf, 0x2f, 0x69, 0x1b, 0x55, 0x94, 0x67, ++ 0xda, 0x0c, 0xd7, 0x32, 0x1f, 0xef, }, ++ { 0x68, 0x63, 0x85, 0x57, 0x95, 0x9e, 0x42, 0x27, 0x41, 0x43, 0x42, 0x02, ++ 0xa5, 0x78, 0xa7, 0xc6, 0x43, 0xc1, 0x6a, 0xba, 0x70, 0x80, 0xcd, 0x04, ++ 0xb6, 0x78, 0x76, 0x29, 0xf3, 0xe8, 0xa0, }, ++ { 0xe6, 0xac, 0x8d, 0x9d, 0xf0, 0xc0, 0xf7, 0xf7, 0xe3, 0x3e, 0x4e, 0x28, ++ 0x0f, 0x59, 0xb2, 0x67, 0x9e, 0x84, 0x34, 0x42, 0x96, 0x30, 0x2b, 0xca, ++ 0x49, 0xb6, 0xc5, 0x9a, 0x84, 0x59, 0xa7, 0x81, }, ++ { 0x7e, }, ++ { 0x1e, 0x21, }, ++ { 0x26, 0xd3, 0xdd, }, ++ { 0x2c, 0xd4, 0xb3, 0x3d, }, ++ { 0x86, 0x7b, 0x76, 0x3c, 0xf0, }, ++ { 0x12, 0xc3, 0x70, 0x1d, 0x55, 0x18, }, ++ { 0x96, 0xc2, 0xbd, 0x61, 0x55, 0xf4, 0x24, }, ++ { 0x20, 0x51, 0xf7, 0x86, 0x58, 0x8f, 0x07, 0x2a, }, ++ { 0x93, 0x15, 0xa8, 0x1d, 0xda, 0x97, 0xee, 0x0e, 0x6c, }, ++ { 0x39, 0x93, 0xdf, 0xd5, 0x0e, 0xca, 0xdc, 0x7a, 0x92, 0xce, }, ++ { 0x60, 0xd5, 0xfd, 0xf5, 0x1b, 0x26, 0x82, 0x26, 0x73, 0x02, 0xbc, }, ++ { 0x98, 0xf2, 0x34, 0xe1, 0xf5, 0xfb, 0x00, 0xac, 0x10, 0x4a, 0x38, 0x9f, }, ++ { 0xda, 0x3a, 0x92, 0x8a, 0xd0, 0xcd, 0x12, 0xcd, 0x15, 0xbb, 0xab, 0x77, ++ 0x66, }, ++ { 0xa2, 0x92, 0x1a, 0xe5, 0xca, 0x0c, 0x30, 0x75, 0xeb, 0xaf, 0x00, 0x31, ++ 0x55, 0x66, }, ++ { 0x06, 0xea, 0xfd, 0x3e, 0x86, 0x38, 0x62, 0x4e, 0xa9, 0x12, 0xa4, 0x12, ++ 0x43, 0xbf, 0xa1, }, ++ { 0xe4, 0x71, 0x7b, 0x94, 0xdb, 0xa0, 0xd2, 0xff, 0x9b, 0xeb, 0xad, 0x8e, ++ 0x95, 0x8a, 0xc5, 0xed, }, ++ { 0x25, 0x5a, 0x77, 0x71, 0x41, 0x0e, 0x7a, 0xe9, 0xed, 0x0c, 0x10, 0xef, ++ 0xf6, 0x2b, 0x3a, 0xba, 0x60, }, ++ { 0xee, 0xe2, 0xa3, 0x67, 0x64, 0x1d, 0xc6, 0x04, 0xc4, 0xe1, 0x68, 0xd2, ++ 0x6e, 0xd2, 0x91, 0x75, 0x53, 0x07, }, ++ { 0xe0, 0xf6, 0x4d, 0x8f, 0x68, 0xfc, 0x06, 0x7e, 0x18, 0x79, 0x7f, 0x2b, ++ 0x6d, 0xef, 0x46, 0x7f, 0xab, 0xb2, 0xad, }, ++ { 0x3d, 0x35, 0x88, 0x9f, 0x2e, 0xcf, 0x96, 0x45, 0x07, 0x60, 0x71, 0x94, ++ 0x00, 0x8d, 0xbf, 0xf4, 0xef, 0x46, 0x2e, 0x3c, }, ++ { 0x43, 0xcf, 0x98, 0xf7, 0x2d, 0xf4, 0x17, 0xe7, 0x8c, 0x05, 0x2d, 0x9b, ++ 0x24, 0xfb, 0x4d, 0xea, 0x4a, 0xec, 0x01, 0x25, 0x29, }, ++ { 0x8e, 0x73, 0x9a, 0x78, 0x11, 0xfe, 0x48, 0xa0, 0x3b, 0x1a, 0x26, 0xdf, ++ 0x25, 0xe9, 0x59, 0x1c, 0x70, 0x07, 0x9f, 0xdc, 0xa0, 0xa6, }, ++ { 0xe8, 0x47, 0x71, 0xc7, 0x3e, 0xdf, 0xb5, 0x13, 0xb9, 0x85, 0x13, 0xa8, ++ 0x54, 0x47, 0x6e, 0x59, 0x96, 0x09, 0x13, 0x5f, 0x82, 0x16, 0x0b, }, ++ { 0xfb, 0xc0, 0x8c, 0x03, 0x21, 0xb3, 0xc4, 0xb5, 0x43, 0x32, 0x6c, 0xea, ++ 0x7f, 0xa8, 0x43, 0x91, 0xe8, 0x4e, 0x3f, 0xbf, 0x45, 0x58, 0x6a, 0xa3, }, ++ { 0x55, 0xf8, 0xf3, 0x00, 0x76, 0x09, 0xef, 0x69, 0x5d, 0xd2, 0x8a, 0xf2, ++ 0x65, 0xc3, 0xcb, 0x9b, 0x43, 0xfd, 0xb1, 0x7e, 0x7f, 0xa1, 0x94, 0xb0, ++ 0xd7, }, ++ { 0xaa, 0x13, 0xc1, 0x51, 0x40, 0x6d, 0x8d, 0x4c, 0x0a, 0x95, 0x64, 0x7b, ++ 0xd1, 0x96, 0xb6, 0x56, 0xb4, 0x5b, 0xcf, 0xd6, 0xd9, 0x15, 0x97, 0xdd, ++ 0xb6, 0xef, }, ++ { 0xaf, 0xb7, 0x36, 0xb0, 0x04, 0xdb, 0xd7, 0x9c, 0x9a, 0x44, 0xc4, 0xf6, ++ 0x1f, 0x12, 0x21, 0x2d, 0x59, 0x30, 0x54, 0xab, 0x27, 0x61, 0xa3, 0x57, ++ 0xef, 0xf8, 0x53, }, ++ { 0x97, 0x34, 0x45, 0x3e, 0xce, 0x7c, 0x35, 0xa2, 0xda, 0x9f, 0x4b, 0x46, ++ 0x6c, 0x11, 0x67, 0xff, 0x2f, 0x76, 0x58, 0x15, 0x71, 0xfa, 0x44, 0x89, ++ 0x89, 0xfd, 0xf7, 0x99, }, ++ { 0x1f, 0xb1, 0x62, 0xeb, 0x83, 0xc5, 0x9c, 0x89, 0xf9, 0x2c, 0xd2, 0x03, ++ 0x61, 0xbc, 0xbb, 0xa5, 0x74, 0x0e, 0x9b, 0x7e, 0x82, 0x3e, 0x70, 0x0a, ++ 0xa9, 0x8f, 0x2b, 0x59, 0xfb, }, ++ { 0xf8, 0xca, 0x5e, 0x3a, 0x4f, 0x9e, 0x10, 0x69, 0x10, 0xd5, 0x4c, 0xeb, ++ 0x1a, 0x0f, 0x3c, 0x6a, 0x98, 0xf5, 0xb0, 0x97, 0x5b, 0x37, 0x2f, 0x0d, ++ 0xbd, 0x42, 0x4b, 0x69, 0xa1, 0x82, }, ++ { 0x12, 0x8c, 0x6d, 0x52, 0x08, 0xef, 0x74, 0xb2, 0xe6, 0xaa, 0xd3, 0xb0, ++ 0x26, 0xb0, 0xd9, 0x94, 0xb6, 0x11, 0x45, 0x0e, 0x36, 0x71, 0x14, 0x2d, ++ 0x41, 0x8c, 0x21, 0x53, 0x31, 0xe9, 0x68, }, ++ { 0xee, 0xea, 0x0d, 0x89, 0x47, 0x7e, 0x72, 0xd1, 0xd8, 0xce, 0x58, 0x4c, ++ 0x94, 0x1f, 0x0d, 0x51, 0x08, 0xa3, 0xb6, 0x3d, 0xe7, 0x82, 0x46, 0x92, ++ 0xd6, 0x98, 0x6b, 0x07, 0x10, 0x65, 0x52, 0x65, }, ++}; ++ ++static const u8 blake2s_hmac_testvecs[][BLAKE2S_HASH_SIZE] __initconst = { ++ { 0xce, 0xe1, 0x57, 0x69, 0x82, 0xdc, 0xbf, 0x43, 0xad, 0x56, 0x4c, 0x70, ++ 0xed, 0x68, 0x16, 0x96, 0xcf, 0xa4, 0x73, 0xe8, 0xe8, 0xfc, 0x32, 0x79, ++ 0x08, 0x0a, 0x75, 0x82, 0xda, 0x3f, 0x05, 0x11, }, ++ { 0x77, 0x2f, 0x0c, 0x71, 0x41, 0xf4, 0x4b, 0x2b, 0xb3, 0xc6, 0xb6, 0xf9, ++ 0x60, 0xde, 0xe4, 0x52, 0x38, 0x66, 0xe8, 0xbf, 0x9b, 0x96, 0xc4, 0x9f, ++ 0x60, 0xd9, 0x24, 0x37, 0x99, 0xd6, 0xec, 0x31, }, ++}; ++ ++bool __init blake2s_selftest(void) ++{ ++ u8 key[BLAKE2S_KEY_SIZE]; ++ u8 buf[ARRAY_SIZE(blake2s_testvecs)]; ++ u8 hash[BLAKE2S_HASH_SIZE]; ++ struct blake2s_state state; ++ bool success = true; ++ int i, l; ++ ++ key[0] = key[1] = 1; ++ for (i = 2; i < sizeof(key); ++i) ++ key[i] = key[i - 2] + key[i - 1]; ++ ++ for (i = 0; i < sizeof(buf); ++i) ++ buf[i] = (u8)i; ++ ++ for (i = l = 0; i < ARRAY_SIZE(blake2s_testvecs); l = (l + 37) % ++i) { ++ int outlen = 1 + i % BLAKE2S_HASH_SIZE; ++ int keylen = (13 * i) % (BLAKE2S_KEY_SIZE + 1); ++ ++ blake2s(hash, buf, key + BLAKE2S_KEY_SIZE - keylen, outlen, i, ++ keylen); ++ if (memcmp(hash, blake2s_testvecs[i], outlen)) { ++ pr_err("blake2s self-test %d: FAIL\n", i + 1); ++ success = false; ++ } ++ ++ if (!keylen) ++ blake2s_init(&state, outlen); ++ else ++ blake2s_init_key(&state, outlen, ++ key + BLAKE2S_KEY_SIZE - keylen, ++ keylen); ++ ++ blake2s_update(&state, buf, l); ++ blake2s_update(&state, buf + l, i - l); ++ blake2s_final(&state, hash); ++ if (memcmp(hash, blake2s_testvecs[i], outlen)) { ++ pr_err("blake2s init/update/final self-test %d: FAIL\n", ++ i + 1); ++ success = false; ++ } ++ } ++ ++ if (success) { ++ blake2s256_hmac(hash, buf, key, sizeof(buf), sizeof(key)); ++ success &= !memcmp(hash, blake2s_hmac_testvecs[0], BLAKE2S_HASH_SIZE); ++ ++ blake2s256_hmac(hash, key, buf, sizeof(key), sizeof(buf)); ++ success &= !memcmp(hash, blake2s_hmac_testvecs[1], BLAKE2S_HASH_SIZE); ++ ++ if (!success) ++ pr_err("blake2s256_hmac self-test: FAIL\n"); ++ } ++ ++ return success; ++} +--- /dev/null ++++ b/lib/crypto/blake2s.c +@@ -0,0 +1,126 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is an implementation of the BLAKE2s hash and PRF functions. ++ * ++ * Information: https://blake2.net/ ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++bool blake2s_selftest(void); ++ ++void blake2s_update(struct blake2s_state *state, const u8 *in, size_t inlen) ++{ ++ const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen; ++ ++ if (unlikely(!inlen)) ++ return; ++ if (inlen > fill) { ++ memcpy(state->buf + state->buflen, in, fill); ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S)) ++ blake2s_compress_arch(state, state->buf, 1, ++ BLAKE2S_BLOCK_SIZE); ++ else ++ blake2s_compress_generic(state, state->buf, 1, ++ BLAKE2S_BLOCK_SIZE); ++ state->buflen = 0; ++ in += fill; ++ inlen -= fill; ++ } ++ if (inlen > BLAKE2S_BLOCK_SIZE) { ++ const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE); ++ /* Hash one less (full) block than strictly possible */ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S)) ++ blake2s_compress_arch(state, in, nblocks - 1, ++ BLAKE2S_BLOCK_SIZE); ++ else ++ blake2s_compress_generic(state, in, nblocks - 1, ++ BLAKE2S_BLOCK_SIZE); ++ in += BLAKE2S_BLOCK_SIZE * (nblocks - 1); ++ inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1); ++ } ++ memcpy(state->buf + state->buflen, in, inlen); ++ state->buflen += inlen; ++} ++EXPORT_SYMBOL(blake2s_update); ++ ++void blake2s_final(struct blake2s_state *state, u8 *out) ++{ ++ WARN_ON(IS_ENABLED(DEBUG) && !out); ++ blake2s_set_lastblock(state); ++ memset(state->buf + state->buflen, 0, ++ BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S)) ++ blake2s_compress_arch(state, state->buf, 1, state->buflen); ++ else ++ blake2s_compress_generic(state, state->buf, 1, state->buflen); ++ cpu_to_le32_array(state->h, ARRAY_SIZE(state->h)); ++ memcpy(out, state->h, state->outlen); ++ memzero_explicit(state, sizeof(*state)); ++} ++EXPORT_SYMBOL(blake2s_final); ++ ++void blake2s256_hmac(u8 *out, const u8 *in, const u8 *key, const size_t inlen, ++ const size_t keylen) ++{ ++ struct blake2s_state state; ++ u8 x_key[BLAKE2S_BLOCK_SIZE] __aligned(__alignof__(u32)) = { 0 }; ++ u8 i_hash[BLAKE2S_HASH_SIZE] __aligned(__alignof__(u32)); ++ int i; ++ ++ if (keylen > BLAKE2S_BLOCK_SIZE) { ++ blake2s_init(&state, BLAKE2S_HASH_SIZE); ++ blake2s_update(&state, key, keylen); ++ blake2s_final(&state, x_key); ++ } else ++ memcpy(x_key, key, keylen); ++ ++ for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) ++ x_key[i] ^= 0x36; ++ ++ blake2s_init(&state, BLAKE2S_HASH_SIZE); ++ blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); ++ blake2s_update(&state, in, inlen); ++ blake2s_final(&state, i_hash); ++ ++ for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) ++ x_key[i] ^= 0x5c ^ 0x36; ++ ++ blake2s_init(&state, BLAKE2S_HASH_SIZE); ++ blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); ++ blake2s_update(&state, i_hash, BLAKE2S_HASH_SIZE); ++ blake2s_final(&state, i_hash); ++ ++ memcpy(out, i_hash, BLAKE2S_HASH_SIZE); ++ memzero_explicit(x_key, BLAKE2S_BLOCK_SIZE); ++ memzero_explicit(i_hash, BLAKE2S_HASH_SIZE); ++} ++EXPORT_SYMBOL(blake2s256_hmac); ++ ++static int __init mod_init(void) ++{ ++ if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && ++ WARN_ON(!blake2s_selftest())) ++ return -ENODEV; ++ return 0; ++} ++ ++static void __exit mod_exit(void) ++{ ++} ++ ++module_init(mod_init); ++module_exit(mod_exit); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("BLAKE2s hash function"); ++MODULE_AUTHOR("Jason A. Donenfeld "); diff --git a/ipq806x/backport-5.4/080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch b/ipq806x/backport-5.4/080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch new file mode 100644 index 0000000..9adc75e --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0022-crypto-testmgr-add-test-cases-for-Blake2s.patch @@ -0,0 +1,322 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:29 +0100 +Subject: [PATCH] crypto: testmgr - add test cases for Blake2s + +commit 17e1df67023a5c9ccaeb5de8bf5b88f63127ecf7 upstream. + +As suggested by Eric for the Blake2b implementation contributed by +David, introduce a set of test vectors for Blake2s covering different +digest and key sizes. + + blake2s-128 blake2s-160 blake2s-224 blake2s-256 + --------------------------------------------------- +len=0 | klen=0 klen=1 klen=16 klen=32 +len=1 | klen=16 klen=32 klen=0 klen=1 +len=7 | klen=32 klen=0 klen=1 klen=16 +len=15 | klen=1 klen=16 klen=32 klen=0 +len=64 | klen=0 klen=1 klen=16 klen=32 +len=247 | klen=16 klen=32 klen=0 klen=1 +len=256 | klen=32 klen=0 klen=1 klen=16 + +Cc: David Sterba +Cc: Eric Biggers +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/testmgr.c | 24 +++++ + crypto/testmgr.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 275 insertions(+) + +--- a/crypto/testmgr.c ++++ b/crypto/testmgr.c +@@ -4035,6 +4035,30 @@ static const struct alg_test_desc alg_te + .test = alg_test_null, + .fips_allowed = 1, + }, { ++ .alg = "blake2s-128", ++ .test = alg_test_hash, ++ .suite = { ++ .hash = __VECS(blakes2s_128_tv_template) ++ } ++ }, { ++ .alg = "blake2s-160", ++ .test = alg_test_hash, ++ .suite = { ++ .hash = __VECS(blakes2s_160_tv_template) ++ } ++ }, { ++ .alg = "blake2s-224", ++ .test = alg_test_hash, ++ .suite = { ++ .hash = __VECS(blakes2s_224_tv_template) ++ } ++ }, { ++ .alg = "blake2s-256", ++ .test = alg_test_hash, ++ .suite = { ++ .hash = __VECS(blakes2s_256_tv_template) ++ } ++ }, { + .alg = "cbc(aes)", + .test = alg_test_skcipher, + .fips_allowed = 1, +--- a/crypto/testmgr.h ++++ b/crypto/testmgr.h +@@ -31567,4 +31567,255 @@ static const struct aead_testvec essiv_h + }, + }; + ++static const char blake2_ordered_sequence[] = ++ "\x00\x01\x02\x03\x04\x05\x06\x07" ++ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" ++ "\x10\x11\x12\x13\x14\x15\x16\x17" ++ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" ++ "\x20\x21\x22\x23\x24\x25\x26\x27" ++ "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" ++ "\x30\x31\x32\x33\x34\x35\x36\x37" ++ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" ++ "\x40\x41\x42\x43\x44\x45\x46\x47" ++ "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" ++ "\x50\x51\x52\x53\x54\x55\x56\x57" ++ "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" ++ "\x60\x61\x62\x63\x64\x65\x66\x67" ++ "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" ++ "\x70\x71\x72\x73\x74\x75\x76\x77" ++ "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" ++ "\x80\x81\x82\x83\x84\x85\x86\x87" ++ "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" ++ "\x90\x91\x92\x93\x94\x95\x96\x97" ++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" ++ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" ++ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" ++ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" ++ "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" ++ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" ++ "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" ++ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" ++ "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" ++ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" ++ "\xe8\xe9\xea\xeb\xec\xed\xee\xef" ++ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" ++ "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; ++ ++static const struct hash_testvec blakes2s_128_tv_template[] = {{ ++ .digest = (u8[]){ 0x64, 0x55, 0x0d, 0x6f, 0xfe, 0x2c, 0x0a, 0x01, ++ 0xa1, 0x4a, 0xba, 0x1e, 0xad, 0xe0, 0x20, 0x0c, }, ++}, { ++ .plaintext = blake2_ordered_sequence, ++ .psize = 64, ++ .digest = (u8[]){ 0xdc, 0x66, 0xca, 0x8f, 0x03, 0x86, 0x58, 0x01, ++ 0xb0, 0xff, 0xe0, 0x6e, 0xd8, 0xa1, 0xa9, 0x0e, }, ++}, { ++ .ksize = 16, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 1, ++ .digest = (u8[]){ 0x88, 0x1e, 0x42, 0xe7, 0xbb, 0x35, 0x80, 0x82, ++ 0x63, 0x7c, 0x0a, 0x0f, 0xd7, 0xec, 0x6c, 0x2f, }, ++}, { ++ .ksize = 32, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 7, ++ .digest = (u8[]){ 0xcf, 0x9e, 0x07, 0x2a, 0xd5, 0x22, 0xf2, 0xcd, ++ 0xa2, 0xd8, 0x25, 0x21, 0x80, 0x86, 0x73, 0x1c, }, ++}, { ++ .ksize = 1, ++ .key = "B", ++ .plaintext = blake2_ordered_sequence, ++ .psize = 15, ++ .digest = (u8[]){ 0xf6, 0x33, 0x5a, 0x2c, 0x22, 0xa0, 0x64, 0xb2, ++ 0xb6, 0x3f, 0xeb, 0xbc, 0xd1, 0xc3, 0xe5, 0xb2, }, ++}, { ++ .ksize = 16, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 247, ++ .digest = (u8[]){ 0x72, 0x66, 0x49, 0x60, 0xf9, 0x4a, 0xea, 0xbe, ++ 0x1f, 0xf4, 0x60, 0xce, 0xb7, 0x81, 0xcb, 0x09, }, ++}, { ++ .ksize = 32, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 256, ++ .digest = (u8[]){ 0xd5, 0xa4, 0x0e, 0xc3, 0x16, 0xc7, 0x51, 0xa6, ++ 0x3c, 0xd0, 0xd9, 0x11, 0x57, 0xfa, 0x1e, 0xbb, }, ++}}; ++ ++static const struct hash_testvec blakes2s_160_tv_template[] = {{ ++ .plaintext = blake2_ordered_sequence, ++ .psize = 7, ++ .digest = (u8[]){ 0xb4, 0xf2, 0x03, 0x49, 0x37, 0xed, 0xb1, 0x3e, ++ 0x5b, 0x2a, 0xca, 0x64, 0x82, 0x74, 0xf6, 0x62, ++ 0xe3, 0xf2, 0x84, 0xff, }, ++}, { ++ .plaintext = blake2_ordered_sequence, ++ .psize = 256, ++ .digest = (u8[]){ 0xaa, 0x56, 0x9b, 0xdc, 0x98, 0x17, 0x75, 0xf2, ++ 0xb3, 0x68, 0x83, 0xb7, 0x9b, 0x8d, 0x48, 0xb1, ++ 0x9b, 0x2d, 0x35, 0x05, }, ++}, { ++ .ksize = 1, ++ .key = "B", ++ .digest = (u8[]){ 0x50, 0x16, 0xe7, 0x0c, 0x01, 0xd0, 0xd3, 0xc3, ++ 0xf4, 0x3e, 0xb1, 0x6e, 0x97, 0xa9, 0x4e, 0xd1, ++ 0x79, 0x65, 0x32, 0x93, }, ++}, { ++ .ksize = 32, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 1, ++ .digest = (u8[]){ 0x1c, 0x2b, 0xcd, 0x9a, 0x68, 0xca, 0x8c, 0x71, ++ 0x90, 0x29, 0x6c, 0x54, 0xfa, 0x56, 0x4a, 0xef, ++ 0xa2, 0x3a, 0x56, 0x9c, }, ++}, { ++ .ksize = 16, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 15, ++ .digest = (u8[]){ 0x36, 0xc3, 0x5f, 0x9a, 0xdc, 0x7e, 0xbf, 0x19, ++ 0x68, 0xaa, 0xca, 0xd8, 0x81, 0xbf, 0x09, 0x34, ++ 0x83, 0x39, 0x0f, 0x30, }, ++}, { ++ .ksize = 1, ++ .key = "B", ++ .plaintext = blake2_ordered_sequence, ++ .psize = 64, ++ .digest = (u8[]){ 0x86, 0x80, 0x78, 0xa4, 0x14, 0xec, 0x03, 0xe5, ++ 0xb6, 0x9a, 0x52, 0x0e, 0x42, 0xee, 0x39, 0x9d, ++ 0xac, 0xa6, 0x81, 0x63, }, ++}, { ++ .ksize = 32, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 247, ++ .digest = (u8[]){ 0x2d, 0xd8, 0xd2, 0x53, 0x66, 0xfa, 0xa9, 0x01, ++ 0x1c, 0x9c, 0xaf, 0xa3, 0xe2, 0x9d, 0x9b, 0x10, ++ 0x0a, 0xf6, 0x73, 0xe8, }, ++}}; ++ ++static const struct hash_testvec blakes2s_224_tv_template[] = {{ ++ .plaintext = blake2_ordered_sequence, ++ .psize = 1, ++ .digest = (u8[]){ 0x61, 0xb9, 0x4e, 0xc9, 0x46, 0x22, 0xa3, 0x91, ++ 0xd2, 0xae, 0x42, 0xe6, 0x45, 0x6c, 0x90, 0x12, ++ 0xd5, 0x80, 0x07, 0x97, 0xb8, 0x86, 0x5a, 0xfc, ++ 0x48, 0x21, 0x97, 0xbb, }, ++}, { ++ .plaintext = blake2_ordered_sequence, ++ .psize = 247, ++ .digest = (u8[]){ 0x9e, 0xda, 0xc7, 0x20, 0x2c, 0xd8, 0x48, 0x2e, ++ 0x31, 0x94, 0xab, 0x46, 0x6d, 0x94, 0xd8, 0xb4, ++ 0x69, 0xcd, 0xae, 0x19, 0x6d, 0x9e, 0x41, 0xcc, ++ 0x2b, 0xa4, 0xd5, 0xf6, }, ++}, { ++ .ksize = 16, ++ .key = blake2_ordered_sequence, ++ .digest = (u8[]){ 0x32, 0xc0, 0xac, 0xf4, 0x3b, 0xd3, 0x07, 0x9f, ++ 0xbe, 0xfb, 0xfa, 0x4d, 0x6b, 0x4e, 0x56, 0xb3, ++ 0xaa, 0xd3, 0x27, 0xf6, 0x14, 0xbf, 0xb9, 0x32, ++ 0xa7, 0x19, 0xfc, 0xb8, }, ++}, { ++ .ksize = 1, ++ .key = "B", ++ .plaintext = blake2_ordered_sequence, ++ .psize = 7, ++ .digest = (u8[]){ 0x73, 0xad, 0x5e, 0x6d, 0xb9, 0x02, 0x8e, 0x76, ++ 0xf2, 0x66, 0x42, 0x4b, 0x4c, 0xfa, 0x1f, 0xe6, ++ 0x2e, 0x56, 0x40, 0xe5, 0xa2, 0xb0, 0x3c, 0xe8, ++ 0x7b, 0x45, 0xfe, 0x05, }, ++}, { ++ .ksize = 32, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 15, ++ .digest = (u8[]){ 0x16, 0x60, 0xfb, 0x92, 0x54, 0xb3, 0x6e, 0x36, ++ 0x81, 0xf4, 0x16, 0x41, 0xc3, 0x3d, 0xd3, 0x43, ++ 0x84, 0xed, 0x10, 0x6f, 0x65, 0x80, 0x7a, 0x3e, ++ 0x25, 0xab, 0xc5, 0x02, }, ++}, { ++ .ksize = 16, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 64, ++ .digest = (u8[]){ 0xca, 0xaa, 0x39, 0x67, 0x9c, 0xf7, 0x6b, 0xc7, ++ 0xb6, 0x82, 0xca, 0x0e, 0x65, 0x36, 0x5b, 0x7c, ++ 0x24, 0x00, 0xfa, 0x5f, 0xda, 0x06, 0x91, 0x93, ++ 0x6a, 0x31, 0x83, 0xb5, }, ++}, { ++ .ksize = 1, ++ .key = "B", ++ .plaintext = blake2_ordered_sequence, ++ .psize = 256, ++ .digest = (u8[]){ 0x90, 0x02, 0x26, 0xb5, 0x06, 0x9c, 0x36, 0x86, ++ 0x94, 0x91, 0x90, 0x1e, 0x7d, 0x2a, 0x71, 0xb2, ++ 0x48, 0xb5, 0xe8, 0x16, 0xfd, 0x64, 0x33, 0x45, ++ 0xb3, 0xd7, 0xec, 0xcc, }, ++}}; ++ ++static const struct hash_testvec blakes2s_256_tv_template[] = {{ ++ .plaintext = blake2_ordered_sequence, ++ .psize = 15, ++ .digest = (u8[]){ 0xd9, 0x7c, 0x82, 0x8d, 0x81, 0x82, 0xa7, 0x21, ++ 0x80, 0xa0, 0x6a, 0x78, 0x26, 0x83, 0x30, 0x67, ++ 0x3f, 0x7c, 0x4e, 0x06, 0x35, 0x94, 0x7c, 0x04, ++ 0xc0, 0x23, 0x23, 0xfd, 0x45, 0xc0, 0xa5, 0x2d, }, ++}, { ++ .ksize = 32, ++ .key = blake2_ordered_sequence, ++ .digest = (u8[]){ 0x48, 0xa8, 0x99, 0x7d, 0xa4, 0x07, 0x87, 0x6b, ++ 0x3d, 0x79, 0xc0, 0xd9, 0x23, 0x25, 0xad, 0x3b, ++ 0x89, 0xcb, 0xb7, 0x54, 0xd8, 0x6a, 0xb7, 0x1a, ++ 0xee, 0x04, 0x7a, 0xd3, 0x45, 0xfd, 0x2c, 0x49, }, ++}, { ++ .ksize = 1, ++ .key = "B", ++ .plaintext = blake2_ordered_sequence, ++ .psize = 1, ++ .digest = (u8[]){ 0x22, 0x27, 0xae, 0xaa, 0x6e, 0x81, 0x56, 0x03, ++ 0xa7, 0xe3, 0xa1, 0x18, 0xa5, 0x9a, 0x2c, 0x18, ++ 0xf4, 0x63, 0xbc, 0x16, 0x70, 0xf1, 0xe7, 0x4b, ++ 0x00, 0x6d, 0x66, 0x16, 0xae, 0x9e, 0x74, 0x4e, }, ++}, { ++ .ksize = 16, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 7, ++ .digest = (u8[]){ 0x58, 0x5d, 0xa8, 0x60, 0x1c, 0xa4, 0xd8, 0x03, ++ 0x86, 0x86, 0x84, 0x64, 0xd7, 0xa0, 0x8e, 0x15, ++ 0x2f, 0x05, 0xa2, 0x1b, 0xbc, 0xef, 0x7a, 0x34, ++ 0xb3, 0xc5, 0xbc, 0x4b, 0xf0, 0x32, 0xeb, 0x12, }, ++}, { ++ .ksize = 32, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 64, ++ .digest = (u8[]){ 0x89, 0x75, 0xb0, 0x57, 0x7f, 0xd3, 0x55, 0x66, ++ 0xd7, 0x50, 0xb3, 0x62, 0xb0, 0x89, 0x7a, 0x26, ++ 0xc3, 0x99, 0x13, 0x6d, 0xf0, 0x7b, 0xab, 0xab, ++ 0xbd, 0xe6, 0x20, 0x3f, 0xf2, 0x95, 0x4e, 0xd4, }, ++}, { ++ .ksize = 1, ++ .key = "B", ++ .plaintext = blake2_ordered_sequence, ++ .psize = 247, ++ .digest = (u8[]){ 0x2e, 0x74, 0x1c, 0x1d, 0x03, 0xf4, 0x9d, 0x84, ++ 0x6f, 0xfc, 0x86, 0x32, 0x92, 0x49, 0x7e, 0x66, ++ 0xd7, 0xc3, 0x10, 0x88, 0xfe, 0x28, 0xb3, 0xe0, ++ 0xbf, 0x50, 0x75, 0xad, 0x8e, 0xa4, 0xe6, 0xb2, }, ++}, { ++ .ksize = 16, ++ .key = blake2_ordered_sequence, ++ .plaintext = blake2_ordered_sequence, ++ .psize = 256, ++ .digest = (u8[]){ 0xb9, 0xd2, 0x81, 0x0e, 0x3a, 0xb1, 0x62, 0x9b, ++ 0xad, 0x44, 0x05, 0xf4, 0x92, 0x2e, 0x99, 0xc1, ++ 0x4a, 0x47, 0xbb, 0x5b, 0x6f, 0xb2, 0x96, 0xed, ++ 0xd5, 0x06, 0xb5, 0x3a, 0x7c, 0x7a, 0x65, 0x1d, }, ++}}; ++ + #endif /* _CRYPTO_TESTMGR_H */ diff --git a/ipq806x/backport-5.4/080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch b/ipq806x/backport-5.4/080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch new file mode 100644 index 0000000..e25edf5 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0023-crypto-blake2s-implement-generic-shash-driver.patch @@ -0,0 +1,245 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:30 +0100 +Subject: [PATCH] crypto: blake2s - implement generic shash driver + +commit 7f9b0880925f1f9d7d59504ea0892d2ae9cfc233 upstream. + +Wire up our newly added Blake2s implementation via the shash API. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/Kconfig | 18 ++++ + crypto/Makefile | 1 + + crypto/blake2s_generic.c | 171 ++++++++++++++++++++++++++++++ + include/crypto/internal/blake2s.h | 5 + + 4 files changed, 195 insertions(+) + create mode 100644 crypto/blake2s_generic.c + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -639,6 +639,24 @@ config CRYPTO_XXHASH + xxHash non-cryptographic hash algorithm. Extremely fast, working at + speeds close to RAM limits. + ++config CRYPTO_BLAKE2S ++ tristate "BLAKE2s digest algorithm" ++ select CRYPTO_LIB_BLAKE2S_GENERIC ++ select CRYPTO_HASH ++ help ++ Implementation of cryptographic hash function BLAKE2s ++ optimized for 8-32bit platforms and can produce digests of any size ++ between 1 to 32. The keyed hash is also implemented. ++ ++ This module provides the following algorithms: ++ ++ - blake2s-128 ++ - blake2s-160 ++ - blake2s-224 ++ - blake2s-256 ++ ++ See https://blake2.net for further information. ++ + config CRYPTO_CRCT10DIF + tristate "CRCT10DIF algorithm" + select CRYPTO_HASH +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -74,6 +74,7 @@ obj-$(CONFIG_CRYPTO_STREEBOG) += streebo + obj-$(CONFIG_CRYPTO_WP512) += wp512.o + CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149 + obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o ++obj-$(CONFIG_CRYPTO_BLAKE2S) += blake2s_generic.o + obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o + obj-$(CONFIG_CRYPTO_ECB) += ecb.o + obj-$(CONFIG_CRYPTO_CBC) += cbc.o +--- /dev/null ++++ b/crypto/blake2s_generic.c +@@ -0,0 +1,171 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++static int crypto_blake2s_setkey(struct crypto_shash *tfm, const u8 *key, ++ unsigned int keylen) ++{ ++ struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(tfm); ++ ++ if (keylen == 0 || keylen > BLAKE2S_KEY_SIZE) { ++ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++ } ++ ++ memcpy(tctx->key, key, keylen); ++ tctx->keylen = keylen; ++ ++ return 0; ++} ++ ++static int crypto_blake2s_init(struct shash_desc *desc) ++{ ++ struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); ++ struct blake2s_state *state = shash_desc_ctx(desc); ++ const int outlen = crypto_shash_digestsize(desc->tfm); ++ ++ if (tctx->keylen) ++ blake2s_init_key(state, outlen, tctx->key, tctx->keylen); ++ else ++ blake2s_init(state, outlen); ++ ++ return 0; ++} ++ ++static int crypto_blake2s_update(struct shash_desc *desc, const u8 *in, ++ unsigned int inlen) ++{ ++ struct blake2s_state *state = shash_desc_ctx(desc); ++ const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen; ++ ++ if (unlikely(!inlen)) ++ return 0; ++ if (inlen > fill) { ++ memcpy(state->buf + state->buflen, in, fill); ++ blake2s_compress_generic(state, state->buf, 1, BLAKE2S_BLOCK_SIZE); ++ state->buflen = 0; ++ in += fill; ++ inlen -= fill; ++ } ++ if (inlen > BLAKE2S_BLOCK_SIZE) { ++ const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE); ++ /* Hash one less (full) block than strictly possible */ ++ blake2s_compress_generic(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE); ++ in += BLAKE2S_BLOCK_SIZE * (nblocks - 1); ++ inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1); ++ } ++ memcpy(state->buf + state->buflen, in, inlen); ++ state->buflen += inlen; ++ ++ return 0; ++} ++ ++static int crypto_blake2s_final(struct shash_desc *desc, u8 *out) ++{ ++ struct blake2s_state *state = shash_desc_ctx(desc); ++ ++ blake2s_set_lastblock(state); ++ memset(state->buf + state->buflen, 0, ++ BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */ ++ blake2s_compress_generic(state, state->buf, 1, state->buflen); ++ cpu_to_le32_array(state->h, ARRAY_SIZE(state->h)); ++ memcpy(out, state->h, state->outlen); ++ memzero_explicit(state, sizeof(*state)); ++ ++ return 0; ++} ++ ++static struct shash_alg blake2s_algs[] = {{ ++ .base.cra_name = "blake2s-128", ++ .base.cra_driver_name = "blake2s-128-generic", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_128_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}, { ++ .base.cra_name = "blake2s-160", ++ .base.cra_driver_name = "blake2s-160-generic", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_160_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}, { ++ .base.cra_name = "blake2s-224", ++ .base.cra_driver_name = "blake2s-224-generic", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_224_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}, { ++ .base.cra_name = "blake2s-256", ++ .base.cra_driver_name = "blake2s-256-generic", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_256_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}}; ++ ++static int __init blake2s_mod_init(void) ++{ ++ return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); ++} ++ ++static void __exit blake2s_mod_exit(void) ++{ ++ crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); ++} ++ ++subsys_initcall(blake2s_mod_init); ++module_exit(blake2s_mod_exit); ++ ++MODULE_ALIAS_CRYPTO("blake2s-128"); ++MODULE_ALIAS_CRYPTO("blake2s-128-generic"); ++MODULE_ALIAS_CRYPTO("blake2s-160"); ++MODULE_ALIAS_CRYPTO("blake2s-160-generic"); ++MODULE_ALIAS_CRYPTO("blake2s-224"); ++MODULE_ALIAS_CRYPTO("blake2s-224-generic"); ++MODULE_ALIAS_CRYPTO("blake2s-256"); ++MODULE_ALIAS_CRYPTO("blake2s-256-generic"); ++MODULE_LICENSE("GPL v2"); +--- a/include/crypto/internal/blake2s.h ++++ b/include/crypto/internal/blake2s.h +@@ -5,6 +5,11 @@ + + #include + ++struct blake2s_tfm_ctx { ++ u8 key[BLAKE2S_KEY_SIZE]; ++ unsigned int keylen; ++}; ++ + void blake2s_compress_generic(struct blake2s_state *state,const u8 *block, + size_t nblocks, const u32 inc); + diff --git a/ipq806x/backport-5.4/080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch b/ipq806x/backport-5.4/080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch new file mode 100644 index 0000000..0440558 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0024-crypto-blake2s-x86_64-SIMD-implementation.patch @@ -0,0 +1,557 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 8 Nov 2019 13:22:31 +0100 +Subject: [PATCH] crypto: blake2s - x86_64 SIMD implementation + +commit ed0356eda153f6a95649e11feb7b07083caf9e20 upstream. + +These implementations from Samuel Neves support AVX and AVX-512VL. +Originally this used AVX-512F, but Skylake thermal throttling made +AVX-512VL more attractive and possible to do with negligable difference. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Samuel Neves +Co-developed-by: Samuel Neves +[ardb: move to arch/x86/crypto, wire into lib/crypto framework] +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/Makefile | 2 + + arch/x86/crypto/blake2s-core.S | 258 +++++++++++++++++++++++++++++++++ + arch/x86/crypto/blake2s-glue.c | 233 +++++++++++++++++++++++++++++ + crypto/Kconfig | 6 + + 4 files changed, 499 insertions(+) + create mode 100644 arch/x86/crypto/blake2s-core.S + create mode 100644 arch/x86/crypto/blake2s-glue.c + +--- a/arch/x86/crypto/Makefile ++++ b/arch/x86/crypto/Makefile +@@ -48,6 +48,7 @@ ifeq ($(avx_supported),yes) + obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o + obj-$(CONFIG_CRYPTO_TWOFISH_AVX_X86_64) += twofish-avx-x86_64.o + obj-$(CONFIG_CRYPTO_SERPENT_AVX_X86_64) += serpent-avx-x86_64.o ++ obj-$(CONFIG_CRYPTO_BLAKE2S_X86) += blake2s-x86_64.o + endif + + # These modules require assembler to support AVX2. +@@ -70,6 +71,7 @@ serpent-sse2-x86_64-y := serpent-sse2-x8 + aegis128-aesni-y := aegis128-aesni-asm.o aegis128-aesni-glue.o + + nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o ++blake2s-x86_64-y := blake2s-core.o blake2s-glue.o + + ifeq ($(avx_supported),yes) + camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o \ +--- /dev/null ++++ b/arch/x86/crypto/blake2s-core.S +@@ -0,0 +1,258 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * Copyright (C) 2017-2019 Samuel Neves . All Rights Reserved. ++ */ ++ ++#include ++ ++.section .rodata.cst32.BLAKE2S_IV, "aM", @progbits, 32 ++.align 32 ++IV: .octa 0xA54FF53A3C6EF372BB67AE856A09E667 ++ .octa 0x5BE0CD191F83D9AB9B05688C510E527F ++.section .rodata.cst16.ROT16, "aM", @progbits, 16 ++.align 16 ++ROT16: .octa 0x0D0C0F0E09080B0A0504070601000302 ++.section .rodata.cst16.ROR328, "aM", @progbits, 16 ++.align 16 ++ROR328: .octa 0x0C0F0E0D080B0A090407060500030201 ++.section .rodata.cst64.BLAKE2S_SIGMA, "aM", @progbits, 160 ++.align 64 ++SIGMA: ++.byte 0, 2, 4, 6, 1, 3, 5, 7, 14, 8, 10, 12, 15, 9, 11, 13 ++.byte 14, 4, 9, 13, 10, 8, 15, 6, 5, 1, 0, 11, 3, 12, 2, 7 ++.byte 11, 12, 5, 15, 8, 0, 2, 13, 9, 10, 3, 7, 4, 14, 6, 1 ++.byte 7, 3, 13, 11, 9, 1, 12, 14, 15, 2, 5, 4, 8, 6, 10, 0 ++.byte 9, 5, 2, 10, 0, 7, 4, 15, 3, 14, 11, 6, 13, 1, 12, 8 ++.byte 2, 6, 0, 8, 12, 10, 11, 3, 1, 4, 7, 15, 9, 13, 5, 14 ++.byte 12, 1, 14, 4, 5, 15, 13, 10, 8, 0, 6, 9, 11, 7, 3, 2 ++.byte 13, 7, 12, 3, 11, 14, 1, 9, 2, 5, 15, 8, 10, 0, 4, 6 ++.byte 6, 14, 11, 0, 15, 9, 3, 8, 10, 12, 13, 1, 5, 2, 7, 4 ++.byte 10, 8, 7, 1, 2, 4, 6, 5, 13, 15, 9, 3, 0, 11, 14, 12 ++#ifdef CONFIG_AS_AVX512 ++.section .rodata.cst64.BLAKE2S_SIGMA2, "aM", @progbits, 640 ++.align 64 ++SIGMA2: ++.long 0, 2, 4, 6, 1, 3, 5, 7, 14, 8, 10, 12, 15, 9, 11, 13 ++.long 8, 2, 13, 15, 10, 9, 12, 3, 6, 4, 0, 14, 5, 11, 1, 7 ++.long 11, 13, 8, 6, 5, 10, 14, 3, 2, 4, 12, 15, 1, 0, 7, 9 ++.long 11, 10, 7, 0, 8, 15, 1, 13, 3, 6, 2, 12, 4, 14, 9, 5 ++.long 4, 10, 9, 14, 15, 0, 11, 8, 1, 7, 3, 13, 2, 5, 6, 12 ++.long 2, 11, 4, 15, 14, 3, 10, 8, 13, 6, 5, 7, 0, 12, 1, 9 ++.long 4, 8, 15, 9, 14, 11, 13, 5, 3, 2, 1, 12, 6, 10, 7, 0 ++.long 6, 13, 0, 14, 12, 2, 1, 11, 15, 4, 5, 8, 7, 9, 3, 10 ++.long 15, 5, 4, 13, 10, 7, 3, 11, 12, 2, 0, 6, 9, 8, 1, 14 ++.long 8, 7, 14, 11, 13, 15, 0, 12, 10, 4, 5, 6, 3, 2, 1, 9 ++#endif /* CONFIG_AS_AVX512 */ ++ ++.text ++#ifdef CONFIG_AS_SSSE3 ++ENTRY(blake2s_compress_ssse3) ++ testq %rdx,%rdx ++ je .Lendofloop ++ movdqu (%rdi),%xmm0 ++ movdqu 0x10(%rdi),%xmm1 ++ movdqa ROT16(%rip),%xmm12 ++ movdqa ROR328(%rip),%xmm13 ++ movdqu 0x20(%rdi),%xmm14 ++ movq %rcx,%xmm15 ++ leaq SIGMA+0xa0(%rip),%r8 ++ jmp .Lbeginofloop ++ .align 32 ++.Lbeginofloop: ++ movdqa %xmm0,%xmm10 ++ movdqa %xmm1,%xmm11 ++ paddq %xmm15,%xmm14 ++ movdqa IV(%rip),%xmm2 ++ movdqa %xmm14,%xmm3 ++ pxor IV+0x10(%rip),%xmm3 ++ leaq SIGMA(%rip),%rcx ++.Lroundloop: ++ movzbl (%rcx),%eax ++ movd (%rsi,%rax,4),%xmm4 ++ movzbl 0x1(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm5 ++ movzbl 0x2(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm6 ++ movzbl 0x3(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm7 ++ punpckldq %xmm5,%xmm4 ++ punpckldq %xmm7,%xmm6 ++ punpcklqdq %xmm6,%xmm4 ++ paddd %xmm4,%xmm0 ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm12,%xmm3 ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm8 ++ psrld $0xc,%xmm1 ++ pslld $0x14,%xmm8 ++ por %xmm8,%xmm1 ++ movzbl 0x4(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm5 ++ movzbl 0x5(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm6 ++ movzbl 0x6(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm7 ++ movzbl 0x7(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm4 ++ punpckldq %xmm6,%xmm5 ++ punpckldq %xmm4,%xmm7 ++ punpcklqdq %xmm7,%xmm5 ++ paddd %xmm5,%xmm0 ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm13,%xmm3 ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm8 ++ psrld $0x7,%xmm1 ++ pslld $0x19,%xmm8 ++ por %xmm8,%xmm1 ++ pshufd $0x93,%xmm0,%xmm0 ++ pshufd $0x4e,%xmm3,%xmm3 ++ pshufd $0x39,%xmm2,%xmm2 ++ movzbl 0x8(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm6 ++ movzbl 0x9(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm7 ++ movzbl 0xa(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm4 ++ movzbl 0xb(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm5 ++ punpckldq %xmm7,%xmm6 ++ punpckldq %xmm5,%xmm4 ++ punpcklqdq %xmm4,%xmm6 ++ paddd %xmm6,%xmm0 ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm12,%xmm3 ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm8 ++ psrld $0xc,%xmm1 ++ pslld $0x14,%xmm8 ++ por %xmm8,%xmm1 ++ movzbl 0xc(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm7 ++ movzbl 0xd(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm4 ++ movzbl 0xe(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm5 ++ movzbl 0xf(%rcx),%eax ++ movd (%rsi,%rax,4),%xmm6 ++ punpckldq %xmm4,%xmm7 ++ punpckldq %xmm6,%xmm5 ++ punpcklqdq %xmm5,%xmm7 ++ paddd %xmm7,%xmm0 ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm13,%xmm3 ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm8 ++ psrld $0x7,%xmm1 ++ pslld $0x19,%xmm8 ++ por %xmm8,%xmm1 ++ pshufd $0x39,%xmm0,%xmm0 ++ pshufd $0x4e,%xmm3,%xmm3 ++ pshufd $0x93,%xmm2,%xmm2 ++ addq $0x10,%rcx ++ cmpq %r8,%rcx ++ jnz .Lroundloop ++ pxor %xmm2,%xmm0 ++ pxor %xmm3,%xmm1 ++ pxor %xmm10,%xmm0 ++ pxor %xmm11,%xmm1 ++ addq $0x40,%rsi ++ decq %rdx ++ jnz .Lbeginofloop ++ movdqu %xmm0,(%rdi) ++ movdqu %xmm1,0x10(%rdi) ++ movdqu %xmm14,0x20(%rdi) ++.Lendofloop: ++ ret ++ENDPROC(blake2s_compress_ssse3) ++#endif /* CONFIG_AS_SSSE3 */ ++ ++#ifdef CONFIG_AS_AVX512 ++ENTRY(blake2s_compress_avx512) ++ vmovdqu (%rdi),%xmm0 ++ vmovdqu 0x10(%rdi),%xmm1 ++ vmovdqu 0x20(%rdi),%xmm4 ++ vmovq %rcx,%xmm5 ++ vmovdqa IV(%rip),%xmm14 ++ vmovdqa IV+16(%rip),%xmm15 ++ jmp .Lblake2s_compress_avx512_mainloop ++.align 32 ++.Lblake2s_compress_avx512_mainloop: ++ vmovdqa %xmm0,%xmm10 ++ vmovdqa %xmm1,%xmm11 ++ vpaddq %xmm5,%xmm4,%xmm4 ++ vmovdqa %xmm14,%xmm2 ++ vpxor %xmm15,%xmm4,%xmm3 ++ vmovdqu (%rsi),%ymm6 ++ vmovdqu 0x20(%rsi),%ymm7 ++ addq $0x40,%rsi ++ leaq SIGMA2(%rip),%rax ++ movb $0xa,%cl ++.Lblake2s_compress_avx512_roundloop: ++ addq $0x40,%rax ++ vmovdqa -0x40(%rax),%ymm8 ++ vmovdqa -0x20(%rax),%ymm9 ++ vpermi2d %ymm7,%ymm6,%ymm8 ++ vpermi2d %ymm7,%ymm6,%ymm9 ++ vmovdqa %ymm8,%ymm6 ++ vmovdqa %ymm9,%ymm7 ++ vpaddd %xmm8,%xmm0,%xmm0 ++ vpaddd %xmm1,%xmm0,%xmm0 ++ vpxor %xmm0,%xmm3,%xmm3 ++ vprord $0x10,%xmm3,%xmm3 ++ vpaddd %xmm3,%xmm2,%xmm2 ++ vpxor %xmm2,%xmm1,%xmm1 ++ vprord $0xc,%xmm1,%xmm1 ++ vextracti128 $0x1,%ymm8,%xmm8 ++ vpaddd %xmm8,%xmm0,%xmm0 ++ vpaddd %xmm1,%xmm0,%xmm0 ++ vpxor %xmm0,%xmm3,%xmm3 ++ vprord $0x8,%xmm3,%xmm3 ++ vpaddd %xmm3,%xmm2,%xmm2 ++ vpxor %xmm2,%xmm1,%xmm1 ++ vprord $0x7,%xmm1,%xmm1 ++ vpshufd $0x93,%xmm0,%xmm0 ++ vpshufd $0x4e,%xmm3,%xmm3 ++ vpshufd $0x39,%xmm2,%xmm2 ++ vpaddd %xmm9,%xmm0,%xmm0 ++ vpaddd %xmm1,%xmm0,%xmm0 ++ vpxor %xmm0,%xmm3,%xmm3 ++ vprord $0x10,%xmm3,%xmm3 ++ vpaddd %xmm3,%xmm2,%xmm2 ++ vpxor %xmm2,%xmm1,%xmm1 ++ vprord $0xc,%xmm1,%xmm1 ++ vextracti128 $0x1,%ymm9,%xmm9 ++ vpaddd %xmm9,%xmm0,%xmm0 ++ vpaddd %xmm1,%xmm0,%xmm0 ++ vpxor %xmm0,%xmm3,%xmm3 ++ vprord $0x8,%xmm3,%xmm3 ++ vpaddd %xmm3,%xmm2,%xmm2 ++ vpxor %xmm2,%xmm1,%xmm1 ++ vprord $0x7,%xmm1,%xmm1 ++ vpshufd $0x39,%xmm0,%xmm0 ++ vpshufd $0x4e,%xmm3,%xmm3 ++ vpshufd $0x93,%xmm2,%xmm2 ++ decb %cl ++ jne .Lblake2s_compress_avx512_roundloop ++ vpxor %xmm10,%xmm0,%xmm0 ++ vpxor %xmm11,%xmm1,%xmm1 ++ vpxor %xmm2,%xmm0,%xmm0 ++ vpxor %xmm3,%xmm1,%xmm1 ++ decq %rdx ++ jne .Lblake2s_compress_avx512_mainloop ++ vmovdqu %xmm0,(%rdi) ++ vmovdqu %xmm1,0x10(%rdi) ++ vmovdqu %xmm4,0x20(%rdi) ++ vzeroupper ++ retq ++ENDPROC(blake2s_compress_avx512) ++#endif /* CONFIG_AS_AVX512 */ +--- /dev/null ++++ b/arch/x86/crypto/blake2s-glue.c +@@ -0,0 +1,233 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++asmlinkage void blake2s_compress_ssse3(struct blake2s_state *state, ++ const u8 *block, const size_t nblocks, ++ const u32 inc); ++asmlinkage void blake2s_compress_avx512(struct blake2s_state *state, ++ const u8 *block, const size_t nblocks, ++ const u32 inc); ++ ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(blake2s_use_ssse3); ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(blake2s_use_avx512); ++ ++void blake2s_compress_arch(struct blake2s_state *state, ++ const u8 *block, size_t nblocks, ++ const u32 inc) ++{ ++ /* SIMD disables preemption, so relax after processing each page. */ ++ BUILD_BUG_ON(PAGE_SIZE / BLAKE2S_BLOCK_SIZE < 8); ++ ++ if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) { ++ blake2s_compress_generic(state, block, nblocks, inc); ++ return; ++ } ++ ++ for (;;) { ++ const size_t blocks = min_t(size_t, nblocks, ++ PAGE_SIZE / BLAKE2S_BLOCK_SIZE); ++ ++ kernel_fpu_begin(); ++ if (IS_ENABLED(CONFIG_AS_AVX512) && ++ static_branch_likely(&blake2s_use_avx512)) ++ blake2s_compress_avx512(state, block, blocks, inc); ++ else ++ blake2s_compress_ssse3(state, block, blocks, inc); ++ kernel_fpu_end(); ++ ++ nblocks -= blocks; ++ if (!nblocks) ++ break; ++ block += blocks * BLAKE2S_BLOCK_SIZE; ++ } ++} ++EXPORT_SYMBOL(blake2s_compress_arch); ++ ++static int crypto_blake2s_setkey(struct crypto_shash *tfm, const u8 *key, ++ unsigned int keylen) ++{ ++ struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(tfm); ++ ++ if (keylen == 0 || keylen > BLAKE2S_KEY_SIZE) { ++ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++ } ++ ++ memcpy(tctx->key, key, keylen); ++ tctx->keylen = keylen; ++ ++ return 0; ++} ++ ++static int crypto_blake2s_init(struct shash_desc *desc) ++{ ++ struct blake2s_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); ++ struct blake2s_state *state = shash_desc_ctx(desc); ++ const int outlen = crypto_shash_digestsize(desc->tfm); ++ ++ if (tctx->keylen) ++ blake2s_init_key(state, outlen, tctx->key, tctx->keylen); ++ else ++ blake2s_init(state, outlen); ++ ++ return 0; ++} ++ ++static int crypto_blake2s_update(struct shash_desc *desc, const u8 *in, ++ unsigned int inlen) ++{ ++ struct blake2s_state *state = shash_desc_ctx(desc); ++ const size_t fill = BLAKE2S_BLOCK_SIZE - state->buflen; ++ ++ if (unlikely(!inlen)) ++ return 0; ++ if (inlen > fill) { ++ memcpy(state->buf + state->buflen, in, fill); ++ blake2s_compress_arch(state, state->buf, 1, BLAKE2S_BLOCK_SIZE); ++ state->buflen = 0; ++ in += fill; ++ inlen -= fill; ++ } ++ if (inlen > BLAKE2S_BLOCK_SIZE) { ++ const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE); ++ /* Hash one less (full) block than strictly possible */ ++ blake2s_compress_arch(state, in, nblocks - 1, BLAKE2S_BLOCK_SIZE); ++ in += BLAKE2S_BLOCK_SIZE * (nblocks - 1); ++ inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1); ++ } ++ memcpy(state->buf + state->buflen, in, inlen); ++ state->buflen += inlen; ++ ++ return 0; ++} ++ ++static int crypto_blake2s_final(struct shash_desc *desc, u8 *out) ++{ ++ struct blake2s_state *state = shash_desc_ctx(desc); ++ ++ blake2s_set_lastblock(state); ++ memset(state->buf + state->buflen, 0, ++ BLAKE2S_BLOCK_SIZE - state->buflen); /* Padding */ ++ blake2s_compress_arch(state, state->buf, 1, state->buflen); ++ cpu_to_le32_array(state->h, ARRAY_SIZE(state->h)); ++ memcpy(out, state->h, state->outlen); ++ memzero_explicit(state, sizeof(*state)); ++ ++ return 0; ++} ++ ++static struct shash_alg blake2s_algs[] = {{ ++ .base.cra_name = "blake2s-128", ++ .base.cra_driver_name = "blake2s-128-x86", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_128_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}, { ++ .base.cra_name = "blake2s-160", ++ .base.cra_driver_name = "blake2s-160-x86", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_160_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}, { ++ .base.cra_name = "blake2s-224", ++ .base.cra_driver_name = "blake2s-224-x86", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_224_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}, { ++ .base.cra_name = "blake2s-256", ++ .base.cra_driver_name = "blake2s-256-x86", ++ .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, ++ .base.cra_ctxsize = sizeof(struct blake2s_tfm_ctx), ++ .base.cra_priority = 200, ++ .base.cra_blocksize = BLAKE2S_BLOCK_SIZE, ++ .base.cra_module = THIS_MODULE, ++ ++ .digestsize = BLAKE2S_256_HASH_SIZE, ++ .setkey = crypto_blake2s_setkey, ++ .init = crypto_blake2s_init, ++ .update = crypto_blake2s_update, ++ .final = crypto_blake2s_final, ++ .descsize = sizeof(struct blake2s_state), ++}}; ++ ++static int __init blake2s_mod_init(void) ++{ ++ if (!boot_cpu_has(X86_FEATURE_SSSE3)) ++ return 0; ++ ++ static_branch_enable(&blake2s_use_ssse3); ++ ++ if (IS_ENABLED(CONFIG_AS_AVX512) && ++ boot_cpu_has(X86_FEATURE_AVX) && ++ boot_cpu_has(X86_FEATURE_AVX2) && ++ boot_cpu_has(X86_FEATURE_AVX512F) && ++ boot_cpu_has(X86_FEATURE_AVX512VL) && ++ cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM | ++ XFEATURE_MASK_AVX512, NULL)) ++ static_branch_enable(&blake2s_use_avx512); ++ ++ return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); ++} ++ ++static void __exit blake2s_mod_exit(void) ++{ ++ if (boot_cpu_has(X86_FEATURE_SSSE3)) ++ crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); ++} ++ ++module_init(blake2s_mod_init); ++module_exit(blake2s_mod_exit); ++ ++MODULE_ALIAS_CRYPTO("blake2s-128"); ++MODULE_ALIAS_CRYPTO("blake2s-128-x86"); ++MODULE_ALIAS_CRYPTO("blake2s-160"); ++MODULE_ALIAS_CRYPTO("blake2s-160-x86"); ++MODULE_ALIAS_CRYPTO("blake2s-224"); ++MODULE_ALIAS_CRYPTO("blake2s-224-x86"); ++MODULE_ALIAS_CRYPTO("blake2s-256"); ++MODULE_ALIAS_CRYPTO("blake2s-256-x86"); ++MODULE_LICENSE("GPL v2"); +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -657,6 +657,12 @@ config CRYPTO_BLAKE2S + + See https://blake2.net for further information. + ++config CRYPTO_BLAKE2S_X86 ++ tristate "BLAKE2s digest algorithm (x86 accelerated version)" ++ depends on X86 && 64BIT ++ select CRYPTO_LIB_BLAKE2S_GENERIC ++ select CRYPTO_ARCH_HAVE_LIB_BLAKE2S ++ + config CRYPTO_CRCT10DIF + tristate "CRCT10DIF algorithm" + select CRYPTO_HASH diff --git a/ipq806x/backport-5.4/080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch b/ipq806x/backport-5.4/080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch new file mode 100644 index 0000000..e58dda9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0025-crypto-curve25519-generic-C-library-implementations.patch @@ -0,0 +1,1849 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 8 Nov 2019 13:22:32 +0100 +Subject: [PATCH] crypto: curve25519 - generic C library implementations + +commit 0ed42a6f431e930b2e8fae21955406e09fe75d70 upstream. + +This contains two formally verified C implementations of the Curve25519 +scalar multiplication function, one for 32-bit systems, and one for +64-bit systems whose compiler supports efficient 128-bit integer types. +Not only are these implementations formally verified, but they are also +the fastest available C implementations. They have been modified to be +friendly to kernel space and to be generally less horrendous looking, +but still an effort has been made to retain their formally verified +characteristic, and so the C might look slightly unidiomatic. + +The 64-bit version comes from HACL*: https://github.com/project-everest/hacl-star +The 32-bit version comes from Fiat: https://github.com/mit-plv/fiat-crypto + +Information: https://cr.yp.to/ecdh.html + +Signed-off-by: Jason A. Donenfeld +[ardb: - move from lib/zinc to lib/crypto + - replace .c #includes with Kconfig based object selection + - drop simd handling and simplify support for per-arch versions ] +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + include/crypto/curve25519.h | 71 +++ + lib/crypto/Kconfig | 25 + + lib/crypto/Makefile | 5 + + lib/crypto/curve25519-fiat32.c | 864 +++++++++++++++++++++++++++++++++ + lib/crypto/curve25519-hacl64.c | 788 ++++++++++++++++++++++++++++++ + lib/crypto/curve25519.c | 25 + + 6 files changed, 1778 insertions(+) + create mode 100644 include/crypto/curve25519.h + create mode 100644 lib/crypto/curve25519-fiat32.c + create mode 100644 lib/crypto/curve25519-hacl64.c + create mode 100644 lib/crypto/curve25519.c + +--- /dev/null ++++ b/include/crypto/curve25519.h +@@ -0,0 +1,71 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef CURVE25519_H ++#define CURVE25519_H ++ ++#include // For crypto_memneq. ++#include ++#include ++ ++enum curve25519_lengths { ++ CURVE25519_KEY_SIZE = 32 ++}; ++ ++extern const u8 curve25519_null_point[]; ++extern const u8 curve25519_base_point[]; ++ ++void curve25519_generic(u8 out[CURVE25519_KEY_SIZE], ++ const u8 scalar[CURVE25519_KEY_SIZE], ++ const u8 point[CURVE25519_KEY_SIZE]); ++ ++void curve25519_arch(u8 out[CURVE25519_KEY_SIZE], ++ const u8 scalar[CURVE25519_KEY_SIZE], ++ const u8 point[CURVE25519_KEY_SIZE]); ++ ++void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE]); ++ ++static inline ++bool __must_check curve25519(u8 mypublic[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE], ++ const u8 basepoint[CURVE25519_KEY_SIZE]) ++{ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519)) ++ curve25519_arch(mypublic, secret, basepoint); ++ else ++ curve25519_generic(mypublic, secret, basepoint); ++ return crypto_memneq(mypublic, curve25519_null_point, ++ CURVE25519_KEY_SIZE); ++} ++ ++static inline bool ++__must_check curve25519_generate_public(u8 pub[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE]) ++{ ++ if (unlikely(!crypto_memneq(secret, curve25519_null_point, ++ CURVE25519_KEY_SIZE))) ++ return false; ++ ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519)) ++ curve25519_base_arch(pub, secret); ++ else ++ curve25519_generic(pub, secret, curve25519_base_point); ++ return crypto_memneq(pub, curve25519_null_point, CURVE25519_KEY_SIZE); ++} ++ ++static inline void curve25519_clamp_secret(u8 secret[CURVE25519_KEY_SIZE]) ++{ ++ secret[0] &= 248; ++ secret[31] = (secret[31] & 127) | 64; ++} ++ ++static inline void curve25519_generate_secret(u8 secret[CURVE25519_KEY_SIZE]) ++{ ++ get_random_bytes_wait(secret, CURVE25519_KEY_SIZE); ++ curve25519_clamp_secret(secret); ++} ++ ++#endif /* CURVE25519_H */ +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -59,6 +59,31 @@ config CRYPTO_LIB_CHACHA + by either the generic implementation or an arch-specific one, if one + is available and enabled. + ++config CRYPTO_ARCH_HAVE_LIB_CURVE25519 ++ tristate ++ help ++ Declares whether the architecture provides an arch-specific ++ accelerated implementation of the Curve25519 library interface, ++ either builtin or as a module. ++ ++config CRYPTO_LIB_CURVE25519_GENERIC ++ tristate ++ help ++ This symbol can be depended upon by arch implementations of the ++ Curve25519 library interface that require the generic code as a ++ fallback, e.g., for SIMD implementations. If no arch specific ++ implementation is enabled, this implementation serves the users ++ of CRYPTO_LIB_CURVE25519. ++ ++config CRYPTO_LIB_CURVE25519 ++ tristate "Curve25519 scalar multiplication library" ++ depends on CRYPTO_ARCH_HAVE_LIB_CURVE25519 || !CRYPTO_ARCH_HAVE_LIB_CURVE25519 ++ select CRYPTO_LIB_CURVE25519_GENERIC if CRYPTO_ARCH_HAVE_LIB_CURVE25519=n ++ help ++ Enable the Curve25519 library interface. This interface may be ++ fulfilled by either the generic implementation or an arch-specific ++ one, if one is available and enabled. ++ + config CRYPTO_LIB_DES + tristate + +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -16,6 +16,11 @@ libblake2s-generic-y += blake2s-gener + obj-$(CONFIG_CRYPTO_LIB_BLAKE2S) += libblake2s.o + libblake2s-y += blake2s.o + ++obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC) += libcurve25519.o ++libcurve25519-y := curve25519-fiat32.o ++libcurve25519-$(CONFIG_ARCH_SUPPORTS_INT128) := curve25519-hacl64.o ++libcurve25519-y += curve25519.o ++ + obj-$(CONFIG_CRYPTO_LIB_DES) += libdes.o + libdes-y := des.o + +--- /dev/null ++++ b/lib/crypto/curve25519-fiat32.c +@@ -0,0 +1,864 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2016 The fiat-crypto Authors. ++ * Copyright (C) 2018-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is a machine-generated formally verified implementation of Curve25519 ++ * ECDH from: . Though originally ++ * machine generated, it has been tweaked to be suitable for use in the kernel. ++ * It is optimized for 32-bit machines and machines that cannot work efficiently ++ * with 128-bit integer types. ++ */ ++ ++#include ++#include ++#include ++ ++/* fe means field element. Here the field is \Z/(2^255-19). An element t, ++ * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 ++ * t[3]+2^102 t[4]+...+2^230 t[9]. ++ * fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc. ++ * Multiplication and carrying produce fe from fe_loose. ++ */ ++typedef struct fe { u32 v[10]; } fe; ++ ++/* fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc ++ * Addition and subtraction produce fe_loose from (fe, fe). ++ */ ++typedef struct fe_loose { u32 v[10]; } fe_loose; ++ ++static __always_inline void fe_frombytes_impl(u32 h[10], const u8 *s) ++{ ++ /* Ignores top bit of s. */ ++ u32 a0 = get_unaligned_le32(s); ++ u32 a1 = get_unaligned_le32(s+4); ++ u32 a2 = get_unaligned_le32(s+8); ++ u32 a3 = get_unaligned_le32(s+12); ++ u32 a4 = get_unaligned_le32(s+16); ++ u32 a5 = get_unaligned_le32(s+20); ++ u32 a6 = get_unaligned_le32(s+24); ++ u32 a7 = get_unaligned_le32(s+28); ++ h[0] = a0&((1<<26)-1); /* 26 used, 32-26 left. 26 */ ++ h[1] = (a0>>26) | ((a1&((1<<19)-1))<< 6); /* (32-26) + 19 = 6+19 = 25 */ ++ h[2] = (a1>>19) | ((a2&((1<<13)-1))<<13); /* (32-19) + 13 = 13+13 = 26 */ ++ h[3] = (a2>>13) | ((a3&((1<< 6)-1))<<19); /* (32-13) + 6 = 19+ 6 = 25 */ ++ h[4] = (a3>> 6); /* (32- 6) = 26 */ ++ h[5] = a4&((1<<25)-1); /* 25 */ ++ h[6] = (a4>>25) | ((a5&((1<<19)-1))<< 7); /* (32-25) + 19 = 7+19 = 26 */ ++ h[7] = (a5>>19) | ((a6&((1<<12)-1))<<13); /* (32-19) + 12 = 13+12 = 25 */ ++ h[8] = (a6>>12) | ((a7&((1<< 6)-1))<<20); /* (32-12) + 6 = 20+ 6 = 26 */ ++ h[9] = (a7>> 6)&((1<<25)-1); /* 25 */ ++} ++ ++static __always_inline void fe_frombytes(fe *h, const u8 *s) ++{ ++ fe_frombytes_impl(h->v, s); ++} ++ ++static __always_inline u8 /*bool*/ ++addcarryx_u25(u8 /*bool*/ c, u32 a, u32 b, u32 *low) ++{ ++ /* This function extracts 25 bits of result and 1 bit of carry ++ * (26 total), so a 32-bit intermediate is sufficient. ++ */ ++ u32 x = a + b + c; ++ *low = x & ((1 << 25) - 1); ++ return (x >> 25) & 1; ++} ++ ++static __always_inline u8 /*bool*/ ++addcarryx_u26(u8 /*bool*/ c, u32 a, u32 b, u32 *low) ++{ ++ /* This function extracts 26 bits of result and 1 bit of carry ++ * (27 total), so a 32-bit intermediate is sufficient. ++ */ ++ u32 x = a + b + c; ++ *low = x & ((1 << 26) - 1); ++ return (x >> 26) & 1; ++} ++ ++static __always_inline u8 /*bool*/ ++subborrow_u25(u8 /*bool*/ c, u32 a, u32 b, u32 *low) ++{ ++ /* This function extracts 25 bits of result and 1 bit of borrow ++ * (26 total), so a 32-bit intermediate is sufficient. ++ */ ++ u32 x = a - b - c; ++ *low = x & ((1 << 25) - 1); ++ return x >> 31; ++} ++ ++static __always_inline u8 /*bool*/ ++subborrow_u26(u8 /*bool*/ c, u32 a, u32 b, u32 *low) ++{ ++ /* This function extracts 26 bits of result and 1 bit of borrow ++ *(27 total), so a 32-bit intermediate is sufficient. ++ */ ++ u32 x = a - b - c; ++ *low = x & ((1 << 26) - 1); ++ return x >> 31; ++} ++ ++static __always_inline u32 cmovznz32(u32 t, u32 z, u32 nz) ++{ ++ t = -!!t; /* all set if nonzero, 0 if 0 */ ++ return (t&nz) | ((~t)&z); ++} ++ ++static __always_inline void fe_freeze(u32 out[10], const u32 in1[10]) ++{ ++ { const u32 x17 = in1[9]; ++ { const u32 x18 = in1[8]; ++ { const u32 x16 = in1[7]; ++ { const u32 x14 = in1[6]; ++ { const u32 x12 = in1[5]; ++ { const u32 x10 = in1[4]; ++ { const u32 x8 = in1[3]; ++ { const u32 x6 = in1[2]; ++ { const u32 x4 = in1[1]; ++ { const u32 x2 = in1[0]; ++ { u32 x20; u8/*bool*/ x21 = subborrow_u26(0x0, x2, 0x3ffffed, &x20); ++ { u32 x23; u8/*bool*/ x24 = subborrow_u25(x21, x4, 0x1ffffff, &x23); ++ { u32 x26; u8/*bool*/ x27 = subborrow_u26(x24, x6, 0x3ffffff, &x26); ++ { u32 x29; u8/*bool*/ x30 = subborrow_u25(x27, x8, 0x1ffffff, &x29); ++ { u32 x32; u8/*bool*/ x33 = subborrow_u26(x30, x10, 0x3ffffff, &x32); ++ { u32 x35; u8/*bool*/ x36 = subborrow_u25(x33, x12, 0x1ffffff, &x35); ++ { u32 x38; u8/*bool*/ x39 = subborrow_u26(x36, x14, 0x3ffffff, &x38); ++ { u32 x41; u8/*bool*/ x42 = subborrow_u25(x39, x16, 0x1ffffff, &x41); ++ { u32 x44; u8/*bool*/ x45 = subborrow_u26(x42, x18, 0x3ffffff, &x44); ++ { u32 x47; u8/*bool*/ x48 = subborrow_u25(x45, x17, 0x1ffffff, &x47); ++ { u32 x49 = cmovznz32(x48, 0x0, 0xffffffff); ++ { u32 x50 = (x49 & 0x3ffffed); ++ { u32 x52; u8/*bool*/ x53 = addcarryx_u26(0x0, x20, x50, &x52); ++ { u32 x54 = (x49 & 0x1ffffff); ++ { u32 x56; u8/*bool*/ x57 = addcarryx_u25(x53, x23, x54, &x56); ++ { u32 x58 = (x49 & 0x3ffffff); ++ { u32 x60; u8/*bool*/ x61 = addcarryx_u26(x57, x26, x58, &x60); ++ { u32 x62 = (x49 & 0x1ffffff); ++ { u32 x64; u8/*bool*/ x65 = addcarryx_u25(x61, x29, x62, &x64); ++ { u32 x66 = (x49 & 0x3ffffff); ++ { u32 x68; u8/*bool*/ x69 = addcarryx_u26(x65, x32, x66, &x68); ++ { u32 x70 = (x49 & 0x1ffffff); ++ { u32 x72; u8/*bool*/ x73 = addcarryx_u25(x69, x35, x70, &x72); ++ { u32 x74 = (x49 & 0x3ffffff); ++ { u32 x76; u8/*bool*/ x77 = addcarryx_u26(x73, x38, x74, &x76); ++ { u32 x78 = (x49 & 0x1ffffff); ++ { u32 x80; u8/*bool*/ x81 = addcarryx_u25(x77, x41, x78, &x80); ++ { u32 x82 = (x49 & 0x3ffffff); ++ { u32 x84; u8/*bool*/ x85 = addcarryx_u26(x81, x44, x82, &x84); ++ { u32 x86 = (x49 & 0x1ffffff); ++ { u32 x88; addcarryx_u25(x85, x47, x86, &x88); ++ out[0] = x52; ++ out[1] = x56; ++ out[2] = x60; ++ out[3] = x64; ++ out[4] = x68; ++ out[5] = x72; ++ out[6] = x76; ++ out[7] = x80; ++ out[8] = x84; ++ out[9] = x88; ++ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ++} ++ ++static __always_inline void fe_tobytes(u8 s[32], const fe *f) ++{ ++ u32 h[10]; ++ fe_freeze(h, f->v); ++ s[0] = h[0] >> 0; ++ s[1] = h[0] >> 8; ++ s[2] = h[0] >> 16; ++ s[3] = (h[0] >> 24) | (h[1] << 2); ++ s[4] = h[1] >> 6; ++ s[5] = h[1] >> 14; ++ s[6] = (h[1] >> 22) | (h[2] << 3); ++ s[7] = h[2] >> 5; ++ s[8] = h[2] >> 13; ++ s[9] = (h[2] >> 21) | (h[3] << 5); ++ s[10] = h[3] >> 3; ++ s[11] = h[3] >> 11; ++ s[12] = (h[3] >> 19) | (h[4] << 6); ++ s[13] = h[4] >> 2; ++ s[14] = h[4] >> 10; ++ s[15] = h[4] >> 18; ++ s[16] = h[5] >> 0; ++ s[17] = h[5] >> 8; ++ s[18] = h[5] >> 16; ++ s[19] = (h[5] >> 24) | (h[6] << 1); ++ s[20] = h[6] >> 7; ++ s[21] = h[6] >> 15; ++ s[22] = (h[6] >> 23) | (h[7] << 3); ++ s[23] = h[7] >> 5; ++ s[24] = h[7] >> 13; ++ s[25] = (h[7] >> 21) | (h[8] << 4); ++ s[26] = h[8] >> 4; ++ s[27] = h[8] >> 12; ++ s[28] = (h[8] >> 20) | (h[9] << 6); ++ s[29] = h[9] >> 2; ++ s[30] = h[9] >> 10; ++ s[31] = h[9] >> 18; ++} ++ ++/* h = f */ ++static __always_inline void fe_copy(fe *h, const fe *f) ++{ ++ memmove(h, f, sizeof(u32) * 10); ++} ++ ++static __always_inline void fe_copy_lt(fe_loose *h, const fe *f) ++{ ++ memmove(h, f, sizeof(u32) * 10); ++} ++ ++/* h = 0 */ ++static __always_inline void fe_0(fe *h) ++{ ++ memset(h, 0, sizeof(u32) * 10); ++} ++ ++/* h = 1 */ ++static __always_inline void fe_1(fe *h) ++{ ++ memset(h, 0, sizeof(u32) * 10); ++ h->v[0] = 1; ++} ++ ++static void fe_add_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) ++{ ++ { const u32 x20 = in1[9]; ++ { const u32 x21 = in1[8]; ++ { const u32 x19 = in1[7]; ++ { const u32 x17 = in1[6]; ++ { const u32 x15 = in1[5]; ++ { const u32 x13 = in1[4]; ++ { const u32 x11 = in1[3]; ++ { const u32 x9 = in1[2]; ++ { const u32 x7 = in1[1]; ++ { const u32 x5 = in1[0]; ++ { const u32 x38 = in2[9]; ++ { const u32 x39 = in2[8]; ++ { const u32 x37 = in2[7]; ++ { const u32 x35 = in2[6]; ++ { const u32 x33 = in2[5]; ++ { const u32 x31 = in2[4]; ++ { const u32 x29 = in2[3]; ++ { const u32 x27 = in2[2]; ++ { const u32 x25 = in2[1]; ++ { const u32 x23 = in2[0]; ++ out[0] = (x5 + x23); ++ out[1] = (x7 + x25); ++ out[2] = (x9 + x27); ++ out[3] = (x11 + x29); ++ out[4] = (x13 + x31); ++ out[5] = (x15 + x33); ++ out[6] = (x17 + x35); ++ out[7] = (x19 + x37); ++ out[8] = (x21 + x39); ++ out[9] = (x20 + x38); ++ }}}}}}}}}}}}}}}}}}}} ++} ++ ++/* h = f + g ++ * Can overlap h with f or g. ++ */ ++static __always_inline void fe_add(fe_loose *h, const fe *f, const fe *g) ++{ ++ fe_add_impl(h->v, f->v, g->v); ++} ++ ++static void fe_sub_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) ++{ ++ { const u32 x20 = in1[9]; ++ { const u32 x21 = in1[8]; ++ { const u32 x19 = in1[7]; ++ { const u32 x17 = in1[6]; ++ { const u32 x15 = in1[5]; ++ { const u32 x13 = in1[4]; ++ { const u32 x11 = in1[3]; ++ { const u32 x9 = in1[2]; ++ { const u32 x7 = in1[1]; ++ { const u32 x5 = in1[0]; ++ { const u32 x38 = in2[9]; ++ { const u32 x39 = in2[8]; ++ { const u32 x37 = in2[7]; ++ { const u32 x35 = in2[6]; ++ { const u32 x33 = in2[5]; ++ { const u32 x31 = in2[4]; ++ { const u32 x29 = in2[3]; ++ { const u32 x27 = in2[2]; ++ { const u32 x25 = in2[1]; ++ { const u32 x23 = in2[0]; ++ out[0] = ((0x7ffffda + x5) - x23); ++ out[1] = ((0x3fffffe + x7) - x25); ++ out[2] = ((0x7fffffe + x9) - x27); ++ out[3] = ((0x3fffffe + x11) - x29); ++ out[4] = ((0x7fffffe + x13) - x31); ++ out[5] = ((0x3fffffe + x15) - x33); ++ out[6] = ((0x7fffffe + x17) - x35); ++ out[7] = ((0x3fffffe + x19) - x37); ++ out[8] = ((0x7fffffe + x21) - x39); ++ out[9] = ((0x3fffffe + x20) - x38); ++ }}}}}}}}}}}}}}}}}}}} ++} ++ ++/* h = f - g ++ * Can overlap h with f or g. ++ */ ++static __always_inline void fe_sub(fe_loose *h, const fe *f, const fe *g) ++{ ++ fe_sub_impl(h->v, f->v, g->v); ++} ++ ++static void fe_mul_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) ++{ ++ { const u32 x20 = in1[9]; ++ { const u32 x21 = in1[8]; ++ { const u32 x19 = in1[7]; ++ { const u32 x17 = in1[6]; ++ { const u32 x15 = in1[5]; ++ { const u32 x13 = in1[4]; ++ { const u32 x11 = in1[3]; ++ { const u32 x9 = in1[2]; ++ { const u32 x7 = in1[1]; ++ { const u32 x5 = in1[0]; ++ { const u32 x38 = in2[9]; ++ { const u32 x39 = in2[8]; ++ { const u32 x37 = in2[7]; ++ { const u32 x35 = in2[6]; ++ { const u32 x33 = in2[5]; ++ { const u32 x31 = in2[4]; ++ { const u32 x29 = in2[3]; ++ { const u32 x27 = in2[2]; ++ { const u32 x25 = in2[1]; ++ { const u32 x23 = in2[0]; ++ { u64 x40 = ((u64)x23 * x5); ++ { u64 x41 = (((u64)x23 * x7) + ((u64)x25 * x5)); ++ { u64 x42 = ((((u64)(0x2 * x25) * x7) + ((u64)x23 * x9)) + ((u64)x27 * x5)); ++ { u64 x43 = (((((u64)x25 * x9) + ((u64)x27 * x7)) + ((u64)x23 * x11)) + ((u64)x29 * x5)); ++ { u64 x44 = (((((u64)x27 * x9) + (0x2 * (((u64)x25 * x11) + ((u64)x29 * x7)))) + ((u64)x23 * x13)) + ((u64)x31 * x5)); ++ { u64 x45 = (((((((u64)x27 * x11) + ((u64)x29 * x9)) + ((u64)x25 * x13)) + ((u64)x31 * x7)) + ((u64)x23 * x15)) + ((u64)x33 * x5)); ++ { u64 x46 = (((((0x2 * ((((u64)x29 * x11) + ((u64)x25 * x15)) + ((u64)x33 * x7))) + ((u64)x27 * x13)) + ((u64)x31 * x9)) + ((u64)x23 * x17)) + ((u64)x35 * x5)); ++ { u64 x47 = (((((((((u64)x29 * x13) + ((u64)x31 * x11)) + ((u64)x27 * x15)) + ((u64)x33 * x9)) + ((u64)x25 * x17)) + ((u64)x35 * x7)) + ((u64)x23 * x19)) + ((u64)x37 * x5)); ++ { u64 x48 = (((((((u64)x31 * x13) + (0x2 * (((((u64)x29 * x15) + ((u64)x33 * x11)) + ((u64)x25 * x19)) + ((u64)x37 * x7)))) + ((u64)x27 * x17)) + ((u64)x35 * x9)) + ((u64)x23 * x21)) + ((u64)x39 * x5)); ++ { u64 x49 = (((((((((((u64)x31 * x15) + ((u64)x33 * x13)) + ((u64)x29 * x17)) + ((u64)x35 * x11)) + ((u64)x27 * x19)) + ((u64)x37 * x9)) + ((u64)x25 * x21)) + ((u64)x39 * x7)) + ((u64)x23 * x20)) + ((u64)x38 * x5)); ++ { u64 x50 = (((((0x2 * ((((((u64)x33 * x15) + ((u64)x29 * x19)) + ((u64)x37 * x11)) + ((u64)x25 * x20)) + ((u64)x38 * x7))) + ((u64)x31 * x17)) + ((u64)x35 * x13)) + ((u64)x27 * x21)) + ((u64)x39 * x9)); ++ { u64 x51 = (((((((((u64)x33 * x17) + ((u64)x35 * x15)) + ((u64)x31 * x19)) + ((u64)x37 * x13)) + ((u64)x29 * x21)) + ((u64)x39 * x11)) + ((u64)x27 * x20)) + ((u64)x38 * x9)); ++ { u64 x52 = (((((u64)x35 * x17) + (0x2 * (((((u64)x33 * x19) + ((u64)x37 * x15)) + ((u64)x29 * x20)) + ((u64)x38 * x11)))) + ((u64)x31 * x21)) + ((u64)x39 * x13)); ++ { u64 x53 = (((((((u64)x35 * x19) + ((u64)x37 * x17)) + ((u64)x33 * x21)) + ((u64)x39 * x15)) + ((u64)x31 * x20)) + ((u64)x38 * x13)); ++ { u64 x54 = (((0x2 * ((((u64)x37 * x19) + ((u64)x33 * x20)) + ((u64)x38 * x15))) + ((u64)x35 * x21)) + ((u64)x39 * x17)); ++ { u64 x55 = (((((u64)x37 * x21) + ((u64)x39 * x19)) + ((u64)x35 * x20)) + ((u64)x38 * x17)); ++ { u64 x56 = (((u64)x39 * x21) + (0x2 * (((u64)x37 * x20) + ((u64)x38 * x19)))); ++ { u64 x57 = (((u64)x39 * x20) + ((u64)x38 * x21)); ++ { u64 x58 = ((u64)(0x2 * x38) * x20); ++ { u64 x59 = (x48 + (x58 << 0x4)); ++ { u64 x60 = (x59 + (x58 << 0x1)); ++ { u64 x61 = (x60 + x58); ++ { u64 x62 = (x47 + (x57 << 0x4)); ++ { u64 x63 = (x62 + (x57 << 0x1)); ++ { u64 x64 = (x63 + x57); ++ { u64 x65 = (x46 + (x56 << 0x4)); ++ { u64 x66 = (x65 + (x56 << 0x1)); ++ { u64 x67 = (x66 + x56); ++ { u64 x68 = (x45 + (x55 << 0x4)); ++ { u64 x69 = (x68 + (x55 << 0x1)); ++ { u64 x70 = (x69 + x55); ++ { u64 x71 = (x44 + (x54 << 0x4)); ++ { u64 x72 = (x71 + (x54 << 0x1)); ++ { u64 x73 = (x72 + x54); ++ { u64 x74 = (x43 + (x53 << 0x4)); ++ { u64 x75 = (x74 + (x53 << 0x1)); ++ { u64 x76 = (x75 + x53); ++ { u64 x77 = (x42 + (x52 << 0x4)); ++ { u64 x78 = (x77 + (x52 << 0x1)); ++ { u64 x79 = (x78 + x52); ++ { u64 x80 = (x41 + (x51 << 0x4)); ++ { u64 x81 = (x80 + (x51 << 0x1)); ++ { u64 x82 = (x81 + x51); ++ { u64 x83 = (x40 + (x50 << 0x4)); ++ { u64 x84 = (x83 + (x50 << 0x1)); ++ { u64 x85 = (x84 + x50); ++ { u64 x86 = (x85 >> 0x1a); ++ { u32 x87 = ((u32)x85 & 0x3ffffff); ++ { u64 x88 = (x86 + x82); ++ { u64 x89 = (x88 >> 0x19); ++ { u32 x90 = ((u32)x88 & 0x1ffffff); ++ { u64 x91 = (x89 + x79); ++ { u64 x92 = (x91 >> 0x1a); ++ { u32 x93 = ((u32)x91 & 0x3ffffff); ++ { u64 x94 = (x92 + x76); ++ { u64 x95 = (x94 >> 0x19); ++ { u32 x96 = ((u32)x94 & 0x1ffffff); ++ { u64 x97 = (x95 + x73); ++ { u64 x98 = (x97 >> 0x1a); ++ { u32 x99 = ((u32)x97 & 0x3ffffff); ++ { u64 x100 = (x98 + x70); ++ { u64 x101 = (x100 >> 0x19); ++ { u32 x102 = ((u32)x100 & 0x1ffffff); ++ { u64 x103 = (x101 + x67); ++ { u64 x104 = (x103 >> 0x1a); ++ { u32 x105 = ((u32)x103 & 0x3ffffff); ++ { u64 x106 = (x104 + x64); ++ { u64 x107 = (x106 >> 0x19); ++ { u32 x108 = ((u32)x106 & 0x1ffffff); ++ { u64 x109 = (x107 + x61); ++ { u64 x110 = (x109 >> 0x1a); ++ { u32 x111 = ((u32)x109 & 0x3ffffff); ++ { u64 x112 = (x110 + x49); ++ { u64 x113 = (x112 >> 0x19); ++ { u32 x114 = ((u32)x112 & 0x1ffffff); ++ { u64 x115 = (x87 + (0x13 * x113)); ++ { u32 x116 = (u32) (x115 >> 0x1a); ++ { u32 x117 = ((u32)x115 & 0x3ffffff); ++ { u32 x118 = (x116 + x90); ++ { u32 x119 = (x118 >> 0x19); ++ { u32 x120 = (x118 & 0x1ffffff); ++ out[0] = x117; ++ out[1] = x120; ++ out[2] = (x119 + x93); ++ out[3] = x96; ++ out[4] = x99; ++ out[5] = x102; ++ out[6] = x105; ++ out[7] = x108; ++ out[8] = x111; ++ out[9] = x114; ++ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ++} ++ ++static __always_inline void fe_mul_ttt(fe *h, const fe *f, const fe *g) ++{ ++ fe_mul_impl(h->v, f->v, g->v); ++} ++ ++static __always_inline void fe_mul_tlt(fe *h, const fe_loose *f, const fe *g) ++{ ++ fe_mul_impl(h->v, f->v, g->v); ++} ++ ++static __always_inline void ++fe_mul_tll(fe *h, const fe_loose *f, const fe_loose *g) ++{ ++ fe_mul_impl(h->v, f->v, g->v); ++} ++ ++static void fe_sqr_impl(u32 out[10], const u32 in1[10]) ++{ ++ { const u32 x17 = in1[9]; ++ { const u32 x18 = in1[8]; ++ { const u32 x16 = in1[7]; ++ { const u32 x14 = in1[6]; ++ { const u32 x12 = in1[5]; ++ { const u32 x10 = in1[4]; ++ { const u32 x8 = in1[3]; ++ { const u32 x6 = in1[2]; ++ { const u32 x4 = in1[1]; ++ { const u32 x2 = in1[0]; ++ { u64 x19 = ((u64)x2 * x2); ++ { u64 x20 = ((u64)(0x2 * x2) * x4); ++ { u64 x21 = (0x2 * (((u64)x4 * x4) + ((u64)x2 * x6))); ++ { u64 x22 = (0x2 * (((u64)x4 * x6) + ((u64)x2 * x8))); ++ { u64 x23 = ((((u64)x6 * x6) + ((u64)(0x4 * x4) * x8)) + ((u64)(0x2 * x2) * x10)); ++ { u64 x24 = (0x2 * ((((u64)x6 * x8) + ((u64)x4 * x10)) + ((u64)x2 * x12))); ++ { u64 x25 = (0x2 * (((((u64)x8 * x8) + ((u64)x6 * x10)) + ((u64)x2 * x14)) + ((u64)(0x2 * x4) * x12))); ++ { u64 x26 = (0x2 * (((((u64)x8 * x10) + ((u64)x6 * x12)) + ((u64)x4 * x14)) + ((u64)x2 * x16))); ++ { u64 x27 = (((u64)x10 * x10) + (0x2 * ((((u64)x6 * x14) + ((u64)x2 * x18)) + (0x2 * (((u64)x4 * x16) + ((u64)x8 * x12)))))); ++ { u64 x28 = (0x2 * ((((((u64)x10 * x12) + ((u64)x8 * x14)) + ((u64)x6 * x16)) + ((u64)x4 * x18)) + ((u64)x2 * x17))); ++ { u64 x29 = (0x2 * (((((u64)x12 * x12) + ((u64)x10 * x14)) + ((u64)x6 * x18)) + (0x2 * (((u64)x8 * x16) + ((u64)x4 * x17))))); ++ { u64 x30 = (0x2 * (((((u64)x12 * x14) + ((u64)x10 * x16)) + ((u64)x8 * x18)) + ((u64)x6 * x17))); ++ { u64 x31 = (((u64)x14 * x14) + (0x2 * (((u64)x10 * x18) + (0x2 * (((u64)x12 * x16) + ((u64)x8 * x17)))))); ++ { u64 x32 = (0x2 * ((((u64)x14 * x16) + ((u64)x12 * x18)) + ((u64)x10 * x17))); ++ { u64 x33 = (0x2 * ((((u64)x16 * x16) + ((u64)x14 * x18)) + ((u64)(0x2 * x12) * x17))); ++ { u64 x34 = (0x2 * (((u64)x16 * x18) + ((u64)x14 * x17))); ++ { u64 x35 = (((u64)x18 * x18) + ((u64)(0x4 * x16) * x17)); ++ { u64 x36 = ((u64)(0x2 * x18) * x17); ++ { u64 x37 = ((u64)(0x2 * x17) * x17); ++ { u64 x38 = (x27 + (x37 << 0x4)); ++ { u64 x39 = (x38 + (x37 << 0x1)); ++ { u64 x40 = (x39 + x37); ++ { u64 x41 = (x26 + (x36 << 0x4)); ++ { u64 x42 = (x41 + (x36 << 0x1)); ++ { u64 x43 = (x42 + x36); ++ { u64 x44 = (x25 + (x35 << 0x4)); ++ { u64 x45 = (x44 + (x35 << 0x1)); ++ { u64 x46 = (x45 + x35); ++ { u64 x47 = (x24 + (x34 << 0x4)); ++ { u64 x48 = (x47 + (x34 << 0x1)); ++ { u64 x49 = (x48 + x34); ++ { u64 x50 = (x23 + (x33 << 0x4)); ++ { u64 x51 = (x50 + (x33 << 0x1)); ++ { u64 x52 = (x51 + x33); ++ { u64 x53 = (x22 + (x32 << 0x4)); ++ { u64 x54 = (x53 + (x32 << 0x1)); ++ { u64 x55 = (x54 + x32); ++ { u64 x56 = (x21 + (x31 << 0x4)); ++ { u64 x57 = (x56 + (x31 << 0x1)); ++ { u64 x58 = (x57 + x31); ++ { u64 x59 = (x20 + (x30 << 0x4)); ++ { u64 x60 = (x59 + (x30 << 0x1)); ++ { u64 x61 = (x60 + x30); ++ { u64 x62 = (x19 + (x29 << 0x4)); ++ { u64 x63 = (x62 + (x29 << 0x1)); ++ { u64 x64 = (x63 + x29); ++ { u64 x65 = (x64 >> 0x1a); ++ { u32 x66 = ((u32)x64 & 0x3ffffff); ++ { u64 x67 = (x65 + x61); ++ { u64 x68 = (x67 >> 0x19); ++ { u32 x69 = ((u32)x67 & 0x1ffffff); ++ { u64 x70 = (x68 + x58); ++ { u64 x71 = (x70 >> 0x1a); ++ { u32 x72 = ((u32)x70 & 0x3ffffff); ++ { u64 x73 = (x71 + x55); ++ { u64 x74 = (x73 >> 0x19); ++ { u32 x75 = ((u32)x73 & 0x1ffffff); ++ { u64 x76 = (x74 + x52); ++ { u64 x77 = (x76 >> 0x1a); ++ { u32 x78 = ((u32)x76 & 0x3ffffff); ++ { u64 x79 = (x77 + x49); ++ { u64 x80 = (x79 >> 0x19); ++ { u32 x81 = ((u32)x79 & 0x1ffffff); ++ { u64 x82 = (x80 + x46); ++ { u64 x83 = (x82 >> 0x1a); ++ { u32 x84 = ((u32)x82 & 0x3ffffff); ++ { u64 x85 = (x83 + x43); ++ { u64 x86 = (x85 >> 0x19); ++ { u32 x87 = ((u32)x85 & 0x1ffffff); ++ { u64 x88 = (x86 + x40); ++ { u64 x89 = (x88 >> 0x1a); ++ { u32 x90 = ((u32)x88 & 0x3ffffff); ++ { u64 x91 = (x89 + x28); ++ { u64 x92 = (x91 >> 0x19); ++ { u32 x93 = ((u32)x91 & 0x1ffffff); ++ { u64 x94 = (x66 + (0x13 * x92)); ++ { u32 x95 = (u32) (x94 >> 0x1a); ++ { u32 x96 = ((u32)x94 & 0x3ffffff); ++ { u32 x97 = (x95 + x69); ++ { u32 x98 = (x97 >> 0x19); ++ { u32 x99 = (x97 & 0x1ffffff); ++ out[0] = x96; ++ out[1] = x99; ++ out[2] = (x98 + x72); ++ out[3] = x75; ++ out[4] = x78; ++ out[5] = x81; ++ out[6] = x84; ++ out[7] = x87; ++ out[8] = x90; ++ out[9] = x93; ++ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ++} ++ ++static __always_inline void fe_sq_tl(fe *h, const fe_loose *f) ++{ ++ fe_sqr_impl(h->v, f->v); ++} ++ ++static __always_inline void fe_sq_tt(fe *h, const fe *f) ++{ ++ fe_sqr_impl(h->v, f->v); ++} ++ ++static __always_inline void fe_loose_invert(fe *out, const fe_loose *z) ++{ ++ fe t0; ++ fe t1; ++ fe t2; ++ fe t3; ++ int i; ++ ++ fe_sq_tl(&t0, z); ++ fe_sq_tt(&t1, &t0); ++ for (i = 1; i < 2; ++i) ++ fe_sq_tt(&t1, &t1); ++ fe_mul_tlt(&t1, z, &t1); ++ fe_mul_ttt(&t0, &t0, &t1); ++ fe_sq_tt(&t2, &t0); ++ fe_mul_ttt(&t1, &t1, &t2); ++ fe_sq_tt(&t2, &t1); ++ for (i = 1; i < 5; ++i) ++ fe_sq_tt(&t2, &t2); ++ fe_mul_ttt(&t1, &t2, &t1); ++ fe_sq_tt(&t2, &t1); ++ for (i = 1; i < 10; ++i) ++ fe_sq_tt(&t2, &t2); ++ fe_mul_ttt(&t2, &t2, &t1); ++ fe_sq_tt(&t3, &t2); ++ for (i = 1; i < 20; ++i) ++ fe_sq_tt(&t3, &t3); ++ fe_mul_ttt(&t2, &t3, &t2); ++ fe_sq_tt(&t2, &t2); ++ for (i = 1; i < 10; ++i) ++ fe_sq_tt(&t2, &t2); ++ fe_mul_ttt(&t1, &t2, &t1); ++ fe_sq_tt(&t2, &t1); ++ for (i = 1; i < 50; ++i) ++ fe_sq_tt(&t2, &t2); ++ fe_mul_ttt(&t2, &t2, &t1); ++ fe_sq_tt(&t3, &t2); ++ for (i = 1; i < 100; ++i) ++ fe_sq_tt(&t3, &t3); ++ fe_mul_ttt(&t2, &t3, &t2); ++ fe_sq_tt(&t2, &t2); ++ for (i = 1; i < 50; ++i) ++ fe_sq_tt(&t2, &t2); ++ fe_mul_ttt(&t1, &t2, &t1); ++ fe_sq_tt(&t1, &t1); ++ for (i = 1; i < 5; ++i) ++ fe_sq_tt(&t1, &t1); ++ fe_mul_ttt(out, &t1, &t0); ++} ++ ++static __always_inline void fe_invert(fe *out, const fe *z) ++{ ++ fe_loose l; ++ fe_copy_lt(&l, z); ++ fe_loose_invert(out, &l); ++} ++ ++/* Replace (f,g) with (g,f) if b == 1; ++ * replace (f,g) with (f,g) if b == 0. ++ * ++ * Preconditions: b in {0,1} ++ */ ++static __always_inline void fe_cswap(fe *f, fe *g, unsigned int b) ++{ ++ unsigned i; ++ b = 0 - b; ++ for (i = 0; i < 10; i++) { ++ u32 x = f->v[i] ^ g->v[i]; ++ x &= b; ++ f->v[i] ^= x; ++ g->v[i] ^= x; ++ } ++} ++ ++/* NOTE: based on fiat-crypto fe_mul, edited for in2=121666, 0, 0.*/ ++static __always_inline void fe_mul_121666_impl(u32 out[10], const u32 in1[10]) ++{ ++ { const u32 x20 = in1[9]; ++ { const u32 x21 = in1[8]; ++ { const u32 x19 = in1[7]; ++ { const u32 x17 = in1[6]; ++ { const u32 x15 = in1[5]; ++ { const u32 x13 = in1[4]; ++ { const u32 x11 = in1[3]; ++ { const u32 x9 = in1[2]; ++ { const u32 x7 = in1[1]; ++ { const u32 x5 = in1[0]; ++ { const u32 x38 = 0; ++ { const u32 x39 = 0; ++ { const u32 x37 = 0; ++ { const u32 x35 = 0; ++ { const u32 x33 = 0; ++ { const u32 x31 = 0; ++ { const u32 x29 = 0; ++ { const u32 x27 = 0; ++ { const u32 x25 = 0; ++ { const u32 x23 = 121666; ++ { u64 x40 = ((u64)x23 * x5); ++ { u64 x41 = (((u64)x23 * x7) + ((u64)x25 * x5)); ++ { u64 x42 = ((((u64)(0x2 * x25) * x7) + ((u64)x23 * x9)) + ((u64)x27 * x5)); ++ { u64 x43 = (((((u64)x25 * x9) + ((u64)x27 * x7)) + ((u64)x23 * x11)) + ((u64)x29 * x5)); ++ { u64 x44 = (((((u64)x27 * x9) + (0x2 * (((u64)x25 * x11) + ((u64)x29 * x7)))) + ((u64)x23 * x13)) + ((u64)x31 * x5)); ++ { u64 x45 = (((((((u64)x27 * x11) + ((u64)x29 * x9)) + ((u64)x25 * x13)) + ((u64)x31 * x7)) + ((u64)x23 * x15)) + ((u64)x33 * x5)); ++ { u64 x46 = (((((0x2 * ((((u64)x29 * x11) + ((u64)x25 * x15)) + ((u64)x33 * x7))) + ((u64)x27 * x13)) + ((u64)x31 * x9)) + ((u64)x23 * x17)) + ((u64)x35 * x5)); ++ { u64 x47 = (((((((((u64)x29 * x13) + ((u64)x31 * x11)) + ((u64)x27 * x15)) + ((u64)x33 * x9)) + ((u64)x25 * x17)) + ((u64)x35 * x7)) + ((u64)x23 * x19)) + ((u64)x37 * x5)); ++ { u64 x48 = (((((((u64)x31 * x13) + (0x2 * (((((u64)x29 * x15) + ((u64)x33 * x11)) + ((u64)x25 * x19)) + ((u64)x37 * x7)))) + ((u64)x27 * x17)) + ((u64)x35 * x9)) + ((u64)x23 * x21)) + ((u64)x39 * x5)); ++ { u64 x49 = (((((((((((u64)x31 * x15) + ((u64)x33 * x13)) + ((u64)x29 * x17)) + ((u64)x35 * x11)) + ((u64)x27 * x19)) + ((u64)x37 * x9)) + ((u64)x25 * x21)) + ((u64)x39 * x7)) + ((u64)x23 * x20)) + ((u64)x38 * x5)); ++ { u64 x50 = (((((0x2 * ((((((u64)x33 * x15) + ((u64)x29 * x19)) + ((u64)x37 * x11)) + ((u64)x25 * x20)) + ((u64)x38 * x7))) + ((u64)x31 * x17)) + ((u64)x35 * x13)) + ((u64)x27 * x21)) + ((u64)x39 * x9)); ++ { u64 x51 = (((((((((u64)x33 * x17) + ((u64)x35 * x15)) + ((u64)x31 * x19)) + ((u64)x37 * x13)) + ((u64)x29 * x21)) + ((u64)x39 * x11)) + ((u64)x27 * x20)) + ((u64)x38 * x9)); ++ { u64 x52 = (((((u64)x35 * x17) + (0x2 * (((((u64)x33 * x19) + ((u64)x37 * x15)) + ((u64)x29 * x20)) + ((u64)x38 * x11)))) + ((u64)x31 * x21)) + ((u64)x39 * x13)); ++ { u64 x53 = (((((((u64)x35 * x19) + ((u64)x37 * x17)) + ((u64)x33 * x21)) + ((u64)x39 * x15)) + ((u64)x31 * x20)) + ((u64)x38 * x13)); ++ { u64 x54 = (((0x2 * ((((u64)x37 * x19) + ((u64)x33 * x20)) + ((u64)x38 * x15))) + ((u64)x35 * x21)) + ((u64)x39 * x17)); ++ { u64 x55 = (((((u64)x37 * x21) + ((u64)x39 * x19)) + ((u64)x35 * x20)) + ((u64)x38 * x17)); ++ { u64 x56 = (((u64)x39 * x21) + (0x2 * (((u64)x37 * x20) + ((u64)x38 * x19)))); ++ { u64 x57 = (((u64)x39 * x20) + ((u64)x38 * x21)); ++ { u64 x58 = ((u64)(0x2 * x38) * x20); ++ { u64 x59 = (x48 + (x58 << 0x4)); ++ { u64 x60 = (x59 + (x58 << 0x1)); ++ { u64 x61 = (x60 + x58); ++ { u64 x62 = (x47 + (x57 << 0x4)); ++ { u64 x63 = (x62 + (x57 << 0x1)); ++ { u64 x64 = (x63 + x57); ++ { u64 x65 = (x46 + (x56 << 0x4)); ++ { u64 x66 = (x65 + (x56 << 0x1)); ++ { u64 x67 = (x66 + x56); ++ { u64 x68 = (x45 + (x55 << 0x4)); ++ { u64 x69 = (x68 + (x55 << 0x1)); ++ { u64 x70 = (x69 + x55); ++ { u64 x71 = (x44 + (x54 << 0x4)); ++ { u64 x72 = (x71 + (x54 << 0x1)); ++ { u64 x73 = (x72 + x54); ++ { u64 x74 = (x43 + (x53 << 0x4)); ++ { u64 x75 = (x74 + (x53 << 0x1)); ++ { u64 x76 = (x75 + x53); ++ { u64 x77 = (x42 + (x52 << 0x4)); ++ { u64 x78 = (x77 + (x52 << 0x1)); ++ { u64 x79 = (x78 + x52); ++ { u64 x80 = (x41 + (x51 << 0x4)); ++ { u64 x81 = (x80 + (x51 << 0x1)); ++ { u64 x82 = (x81 + x51); ++ { u64 x83 = (x40 + (x50 << 0x4)); ++ { u64 x84 = (x83 + (x50 << 0x1)); ++ { u64 x85 = (x84 + x50); ++ { u64 x86 = (x85 >> 0x1a); ++ { u32 x87 = ((u32)x85 & 0x3ffffff); ++ { u64 x88 = (x86 + x82); ++ { u64 x89 = (x88 >> 0x19); ++ { u32 x90 = ((u32)x88 & 0x1ffffff); ++ { u64 x91 = (x89 + x79); ++ { u64 x92 = (x91 >> 0x1a); ++ { u32 x93 = ((u32)x91 & 0x3ffffff); ++ { u64 x94 = (x92 + x76); ++ { u64 x95 = (x94 >> 0x19); ++ { u32 x96 = ((u32)x94 & 0x1ffffff); ++ { u64 x97 = (x95 + x73); ++ { u64 x98 = (x97 >> 0x1a); ++ { u32 x99 = ((u32)x97 & 0x3ffffff); ++ { u64 x100 = (x98 + x70); ++ { u64 x101 = (x100 >> 0x19); ++ { u32 x102 = ((u32)x100 & 0x1ffffff); ++ { u64 x103 = (x101 + x67); ++ { u64 x104 = (x103 >> 0x1a); ++ { u32 x105 = ((u32)x103 & 0x3ffffff); ++ { u64 x106 = (x104 + x64); ++ { u64 x107 = (x106 >> 0x19); ++ { u32 x108 = ((u32)x106 & 0x1ffffff); ++ { u64 x109 = (x107 + x61); ++ { u64 x110 = (x109 >> 0x1a); ++ { u32 x111 = ((u32)x109 & 0x3ffffff); ++ { u64 x112 = (x110 + x49); ++ { u64 x113 = (x112 >> 0x19); ++ { u32 x114 = ((u32)x112 & 0x1ffffff); ++ { u64 x115 = (x87 + (0x13 * x113)); ++ { u32 x116 = (u32) (x115 >> 0x1a); ++ { u32 x117 = ((u32)x115 & 0x3ffffff); ++ { u32 x118 = (x116 + x90); ++ { u32 x119 = (x118 >> 0x19); ++ { u32 x120 = (x118 & 0x1ffffff); ++ out[0] = x117; ++ out[1] = x120; ++ out[2] = (x119 + x93); ++ out[3] = x96; ++ out[4] = x99; ++ out[5] = x102; ++ out[6] = x105; ++ out[7] = x108; ++ out[8] = x111; ++ out[9] = x114; ++ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ++} ++ ++static __always_inline void fe_mul121666(fe *h, const fe_loose *f) ++{ ++ fe_mul_121666_impl(h->v, f->v); ++} ++ ++void curve25519_generic(u8 out[CURVE25519_KEY_SIZE], ++ const u8 scalar[CURVE25519_KEY_SIZE], ++ const u8 point[CURVE25519_KEY_SIZE]) ++{ ++ fe x1, x2, z2, x3, z3; ++ fe_loose x2l, z2l, x3l; ++ unsigned swap = 0; ++ int pos; ++ u8 e[32]; ++ ++ memcpy(e, scalar, 32); ++ curve25519_clamp_secret(e); ++ ++ /* The following implementation was transcribed to Coq and proven to ++ * correspond to unary scalar multiplication in affine coordinates given ++ * that x1 != 0 is the x coordinate of some point on the curve. It was ++ * also checked in Coq that doing a ladderstep with x1 = x3 = 0 gives ++ * z2' = z3' = 0, and z2 = z3 = 0 gives z2' = z3' = 0. The statement was ++ * quantified over the underlying field, so it applies to Curve25519 ++ * itself and the quadratic twist of Curve25519. It was not proven in ++ * Coq that prime-field arithmetic correctly simulates extension-field ++ * arithmetic on prime-field values. The decoding of the byte array ++ * representation of e was not considered. ++ * ++ * Specification of Montgomery curves in affine coordinates: ++ * ++ * ++ * Proof that these form a group that is isomorphic to a Weierstrass ++ * curve: ++ * ++ * ++ * Coq transcription and correctness proof of the loop ++ * (where scalarbits=255): ++ * ++ * ++ * preconditions: 0 <= e < 2^255 (not necessarily e < order), ++ * fe_invert(0) = 0 ++ */ ++ fe_frombytes(&x1, point); ++ fe_1(&x2); ++ fe_0(&z2); ++ fe_copy(&x3, &x1); ++ fe_1(&z3); ++ ++ for (pos = 254; pos >= 0; --pos) { ++ fe tmp0, tmp1; ++ fe_loose tmp0l, tmp1l; ++ /* loop invariant as of right before the test, for the case ++ * where x1 != 0: ++ * pos >= -1; if z2 = 0 then x2 is nonzero; if z3 = 0 then x3 ++ * is nonzero ++ * let r := e >> (pos+1) in the following equalities of ++ * projective points: ++ * to_xz (r*P) === if swap then (x3, z3) else (x2, z2) ++ * to_xz ((r+1)*P) === if swap then (x2, z2) else (x3, z3) ++ * x1 is the nonzero x coordinate of the nonzero ++ * point (r*P-(r+1)*P) ++ */ ++ unsigned b = 1 & (e[pos / 8] >> (pos & 7)); ++ swap ^= b; ++ fe_cswap(&x2, &x3, swap); ++ fe_cswap(&z2, &z3, swap); ++ swap = b; ++ /* Coq transcription of ladderstep formula (called from ++ * transcribed loop): ++ * ++ * ++ * x1 != 0 ++ * x1 = 0 ++ */ ++ fe_sub(&tmp0l, &x3, &z3); ++ fe_sub(&tmp1l, &x2, &z2); ++ fe_add(&x2l, &x2, &z2); ++ fe_add(&z2l, &x3, &z3); ++ fe_mul_tll(&z3, &tmp0l, &x2l); ++ fe_mul_tll(&z2, &z2l, &tmp1l); ++ fe_sq_tl(&tmp0, &tmp1l); ++ fe_sq_tl(&tmp1, &x2l); ++ fe_add(&x3l, &z3, &z2); ++ fe_sub(&z2l, &z3, &z2); ++ fe_mul_ttt(&x2, &tmp1, &tmp0); ++ fe_sub(&tmp1l, &tmp1, &tmp0); ++ fe_sq_tl(&z2, &z2l); ++ fe_mul121666(&z3, &tmp1l); ++ fe_sq_tl(&x3, &x3l); ++ fe_add(&tmp0l, &tmp0, &z3); ++ fe_mul_ttt(&z3, &x1, &z2); ++ fe_mul_tll(&z2, &tmp1l, &tmp0l); ++ } ++ /* here pos=-1, so r=e, so to_xz (e*P) === if swap then (x3, z3) ++ * else (x2, z2) ++ */ ++ fe_cswap(&x2, &x3, swap); ++ fe_cswap(&z2, &z3, swap); ++ ++ fe_invert(&z2, &z2); ++ fe_mul_ttt(&x2, &x2, &z2); ++ fe_tobytes(out, &x2); ++ ++ memzero_explicit(&x1, sizeof(x1)); ++ memzero_explicit(&x2, sizeof(x2)); ++ memzero_explicit(&z2, sizeof(z2)); ++ memzero_explicit(&x3, sizeof(x3)); ++ memzero_explicit(&z3, sizeof(z3)); ++ memzero_explicit(&x2l, sizeof(x2l)); ++ memzero_explicit(&z2l, sizeof(z2l)); ++ memzero_explicit(&x3l, sizeof(x3l)); ++ memzero_explicit(&e, sizeof(e)); ++} +--- /dev/null ++++ b/lib/crypto/curve25519-hacl64.c +@@ -0,0 +1,788 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2016-2017 INRIA and Microsoft Corporation. ++ * Copyright (C) 2018-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is a machine-generated formally verified implementation of Curve25519 ++ * ECDH from: . Though originally machine ++ * generated, it has been tweaked to be suitable for use in the kernel. It is ++ * optimized for 64-bit machines that can efficiently work with 128-bit ++ * integer types. ++ */ ++ ++#include ++#include ++#include ++ ++typedef __uint128_t u128; ++ ++static __always_inline u64 u64_eq_mask(u64 a, u64 b) ++{ ++ u64 x = a ^ b; ++ u64 minus_x = ~x + (u64)1U; ++ u64 x_or_minus_x = x | minus_x; ++ u64 xnx = x_or_minus_x >> (u32)63U; ++ u64 c = xnx - (u64)1U; ++ return c; ++} ++ ++static __always_inline u64 u64_gte_mask(u64 a, u64 b) ++{ ++ u64 x = a; ++ u64 y = b; ++ u64 x_xor_y = x ^ y; ++ u64 x_sub_y = x - y; ++ u64 x_sub_y_xor_y = x_sub_y ^ y; ++ u64 q = x_xor_y | x_sub_y_xor_y; ++ u64 x_xor_q = x ^ q; ++ u64 x_xor_q_ = x_xor_q >> (u32)63U; ++ u64 c = x_xor_q_ - (u64)1U; ++ return c; ++} ++ ++static __always_inline void modulo_carry_top(u64 *b) ++{ ++ u64 b4 = b[4]; ++ u64 b0 = b[0]; ++ u64 b4_ = b4 & 0x7ffffffffffffLLU; ++ u64 b0_ = b0 + 19 * (b4 >> 51); ++ b[4] = b4_; ++ b[0] = b0_; ++} ++ ++static __always_inline void fproduct_copy_from_wide_(u64 *output, u128 *input) ++{ ++ { ++ u128 xi = input[0]; ++ output[0] = ((u64)(xi)); ++ } ++ { ++ u128 xi = input[1]; ++ output[1] = ((u64)(xi)); ++ } ++ { ++ u128 xi = input[2]; ++ output[2] = ((u64)(xi)); ++ } ++ { ++ u128 xi = input[3]; ++ output[3] = ((u64)(xi)); ++ } ++ { ++ u128 xi = input[4]; ++ output[4] = ((u64)(xi)); ++ } ++} ++ ++static __always_inline void ++fproduct_sum_scalar_multiplication_(u128 *output, u64 *input, u64 s) ++{ ++ output[0] += (u128)input[0] * s; ++ output[1] += (u128)input[1] * s; ++ output[2] += (u128)input[2] * s; ++ output[3] += (u128)input[3] * s; ++ output[4] += (u128)input[4] * s; ++} ++ ++static __always_inline void fproduct_carry_wide_(u128 *tmp) ++{ ++ { ++ u32 ctr = 0; ++ u128 tctr = tmp[ctr]; ++ u128 tctrp1 = tmp[ctr + 1]; ++ u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU; ++ u128 c = ((tctr) >> (51)); ++ tmp[ctr] = ((u128)(r0)); ++ tmp[ctr + 1] = ((tctrp1) + (c)); ++ } ++ { ++ u32 ctr = 1; ++ u128 tctr = tmp[ctr]; ++ u128 tctrp1 = tmp[ctr + 1]; ++ u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU; ++ u128 c = ((tctr) >> (51)); ++ tmp[ctr] = ((u128)(r0)); ++ tmp[ctr + 1] = ((tctrp1) + (c)); ++ } ++ ++ { ++ u32 ctr = 2; ++ u128 tctr = tmp[ctr]; ++ u128 tctrp1 = tmp[ctr + 1]; ++ u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU; ++ u128 c = ((tctr) >> (51)); ++ tmp[ctr] = ((u128)(r0)); ++ tmp[ctr + 1] = ((tctrp1) + (c)); ++ } ++ { ++ u32 ctr = 3; ++ u128 tctr = tmp[ctr]; ++ u128 tctrp1 = tmp[ctr + 1]; ++ u64 r0 = ((u64)(tctr)) & 0x7ffffffffffffLLU; ++ u128 c = ((tctr) >> (51)); ++ tmp[ctr] = ((u128)(r0)); ++ tmp[ctr + 1] = ((tctrp1) + (c)); ++ } ++} ++ ++static __always_inline void fmul_shift_reduce(u64 *output) ++{ ++ u64 tmp = output[4]; ++ u64 b0; ++ { ++ u32 ctr = 5 - 0 - 1; ++ u64 z = output[ctr - 1]; ++ output[ctr] = z; ++ } ++ { ++ u32 ctr = 5 - 1 - 1; ++ u64 z = output[ctr - 1]; ++ output[ctr] = z; ++ } ++ { ++ u32 ctr = 5 - 2 - 1; ++ u64 z = output[ctr - 1]; ++ output[ctr] = z; ++ } ++ { ++ u32 ctr = 5 - 3 - 1; ++ u64 z = output[ctr - 1]; ++ output[ctr] = z; ++ } ++ output[0] = tmp; ++ b0 = output[0]; ++ output[0] = 19 * b0; ++} ++ ++static __always_inline void fmul_mul_shift_reduce_(u128 *output, u64 *input, ++ u64 *input21) ++{ ++ u32 i; ++ u64 input2i; ++ { ++ u64 input2i = input21[0]; ++ fproduct_sum_scalar_multiplication_(output, input, input2i); ++ fmul_shift_reduce(input); ++ } ++ { ++ u64 input2i = input21[1]; ++ fproduct_sum_scalar_multiplication_(output, input, input2i); ++ fmul_shift_reduce(input); ++ } ++ { ++ u64 input2i = input21[2]; ++ fproduct_sum_scalar_multiplication_(output, input, input2i); ++ fmul_shift_reduce(input); ++ } ++ { ++ u64 input2i = input21[3]; ++ fproduct_sum_scalar_multiplication_(output, input, input2i); ++ fmul_shift_reduce(input); ++ } ++ i = 4; ++ input2i = input21[i]; ++ fproduct_sum_scalar_multiplication_(output, input, input2i); ++} ++ ++static __always_inline void fmul_fmul(u64 *output, u64 *input, u64 *input21) ++{ ++ u64 tmp[5] = { input[0], input[1], input[2], input[3], input[4] }; ++ { ++ u128 b4; ++ u128 b0; ++ u128 b4_; ++ u128 b0_; ++ u64 i0; ++ u64 i1; ++ u64 i0_; ++ u64 i1_; ++ u128 t[5] = { 0 }; ++ fmul_mul_shift_reduce_(t, tmp, input21); ++ fproduct_carry_wide_(t); ++ b4 = t[4]; ++ b0 = t[0]; ++ b4_ = ((b4) & (((u128)(0x7ffffffffffffLLU)))); ++ b0_ = ((b0) + (((u128)(19) * (((u64)(((b4) >> (51)))))))); ++ t[4] = b4_; ++ t[0] = b0_; ++ fproduct_copy_from_wide_(output, t); ++ i0 = output[0]; ++ i1 = output[1]; ++ i0_ = i0 & 0x7ffffffffffffLLU; ++ i1_ = i1 + (i0 >> 51); ++ output[0] = i0_; ++ output[1] = i1_; ++ } ++} ++ ++static __always_inline void fsquare_fsquare__(u128 *tmp, u64 *output) ++{ ++ u64 r0 = output[0]; ++ u64 r1 = output[1]; ++ u64 r2 = output[2]; ++ u64 r3 = output[3]; ++ u64 r4 = output[4]; ++ u64 d0 = r0 * 2; ++ u64 d1 = r1 * 2; ++ u64 d2 = r2 * 2 * 19; ++ u64 d419 = r4 * 19; ++ u64 d4 = d419 * 2; ++ u128 s0 = ((((((u128)(r0) * (r0))) + (((u128)(d4) * (r1))))) + ++ (((u128)(d2) * (r3)))); ++ u128 s1 = ((((((u128)(d0) * (r1))) + (((u128)(d4) * (r2))))) + ++ (((u128)(r3 * 19) * (r3)))); ++ u128 s2 = ((((((u128)(d0) * (r2))) + (((u128)(r1) * (r1))))) + ++ (((u128)(d4) * (r3)))); ++ u128 s3 = ((((((u128)(d0) * (r3))) + (((u128)(d1) * (r2))))) + ++ (((u128)(r4) * (d419)))); ++ u128 s4 = ((((((u128)(d0) * (r4))) + (((u128)(d1) * (r3))))) + ++ (((u128)(r2) * (r2)))); ++ tmp[0] = s0; ++ tmp[1] = s1; ++ tmp[2] = s2; ++ tmp[3] = s3; ++ tmp[4] = s4; ++} ++ ++static __always_inline void fsquare_fsquare_(u128 *tmp, u64 *output) ++{ ++ u128 b4; ++ u128 b0; ++ u128 b4_; ++ u128 b0_; ++ u64 i0; ++ u64 i1; ++ u64 i0_; ++ u64 i1_; ++ fsquare_fsquare__(tmp, output); ++ fproduct_carry_wide_(tmp); ++ b4 = tmp[4]; ++ b0 = tmp[0]; ++ b4_ = ((b4) & (((u128)(0x7ffffffffffffLLU)))); ++ b0_ = ((b0) + (((u128)(19) * (((u64)(((b4) >> (51)))))))); ++ tmp[4] = b4_; ++ tmp[0] = b0_; ++ fproduct_copy_from_wide_(output, tmp); ++ i0 = output[0]; ++ i1 = output[1]; ++ i0_ = i0 & 0x7ffffffffffffLLU; ++ i1_ = i1 + (i0 >> 51); ++ output[0] = i0_; ++ output[1] = i1_; ++} ++ ++static __always_inline void fsquare_fsquare_times_(u64 *output, u128 *tmp, ++ u32 count1) ++{ ++ u32 i; ++ fsquare_fsquare_(tmp, output); ++ for (i = 1; i < count1; ++i) ++ fsquare_fsquare_(tmp, output); ++} ++ ++static __always_inline void fsquare_fsquare_times(u64 *output, u64 *input, ++ u32 count1) ++{ ++ u128 t[5]; ++ memcpy(output, input, 5 * sizeof(*input)); ++ fsquare_fsquare_times_(output, t, count1); ++} ++ ++static __always_inline void fsquare_fsquare_times_inplace(u64 *output, ++ u32 count1) ++{ ++ u128 t[5]; ++ fsquare_fsquare_times_(output, t, count1); ++} ++ ++static __always_inline void crecip_crecip(u64 *out, u64 *z) ++{ ++ u64 buf[20] = { 0 }; ++ u64 *a0 = buf; ++ u64 *t00 = buf + 5; ++ u64 *b0 = buf + 10; ++ u64 *t01; ++ u64 *b1; ++ u64 *c0; ++ u64 *a; ++ u64 *t0; ++ u64 *b; ++ u64 *c; ++ fsquare_fsquare_times(a0, z, 1); ++ fsquare_fsquare_times(t00, a0, 2); ++ fmul_fmul(b0, t00, z); ++ fmul_fmul(a0, b0, a0); ++ fsquare_fsquare_times(t00, a0, 1); ++ fmul_fmul(b0, t00, b0); ++ fsquare_fsquare_times(t00, b0, 5); ++ t01 = buf + 5; ++ b1 = buf + 10; ++ c0 = buf + 15; ++ fmul_fmul(b1, t01, b1); ++ fsquare_fsquare_times(t01, b1, 10); ++ fmul_fmul(c0, t01, b1); ++ fsquare_fsquare_times(t01, c0, 20); ++ fmul_fmul(t01, t01, c0); ++ fsquare_fsquare_times_inplace(t01, 10); ++ fmul_fmul(b1, t01, b1); ++ fsquare_fsquare_times(t01, b1, 50); ++ a = buf; ++ t0 = buf + 5; ++ b = buf + 10; ++ c = buf + 15; ++ fmul_fmul(c, t0, b); ++ fsquare_fsquare_times(t0, c, 100); ++ fmul_fmul(t0, t0, c); ++ fsquare_fsquare_times_inplace(t0, 50); ++ fmul_fmul(t0, t0, b); ++ fsquare_fsquare_times_inplace(t0, 5); ++ fmul_fmul(out, t0, a); ++} ++ ++static __always_inline void fsum(u64 *a, u64 *b) ++{ ++ a[0] += b[0]; ++ a[1] += b[1]; ++ a[2] += b[2]; ++ a[3] += b[3]; ++ a[4] += b[4]; ++} ++ ++static __always_inline void fdifference(u64 *a, u64 *b) ++{ ++ u64 tmp[5] = { 0 }; ++ u64 b0; ++ u64 b1; ++ u64 b2; ++ u64 b3; ++ u64 b4; ++ memcpy(tmp, b, 5 * sizeof(*b)); ++ b0 = tmp[0]; ++ b1 = tmp[1]; ++ b2 = tmp[2]; ++ b3 = tmp[3]; ++ b4 = tmp[4]; ++ tmp[0] = b0 + 0x3fffffffffff68LLU; ++ tmp[1] = b1 + 0x3ffffffffffff8LLU; ++ tmp[2] = b2 + 0x3ffffffffffff8LLU; ++ tmp[3] = b3 + 0x3ffffffffffff8LLU; ++ tmp[4] = b4 + 0x3ffffffffffff8LLU; ++ { ++ u64 xi = a[0]; ++ u64 yi = tmp[0]; ++ a[0] = yi - xi; ++ } ++ { ++ u64 xi = a[1]; ++ u64 yi = tmp[1]; ++ a[1] = yi - xi; ++ } ++ { ++ u64 xi = a[2]; ++ u64 yi = tmp[2]; ++ a[2] = yi - xi; ++ } ++ { ++ u64 xi = a[3]; ++ u64 yi = tmp[3]; ++ a[3] = yi - xi; ++ } ++ { ++ u64 xi = a[4]; ++ u64 yi = tmp[4]; ++ a[4] = yi - xi; ++ } ++} ++ ++static __always_inline void fscalar(u64 *output, u64 *b, u64 s) ++{ ++ u128 tmp[5]; ++ u128 b4; ++ u128 b0; ++ u128 b4_; ++ u128 b0_; ++ { ++ u64 xi = b[0]; ++ tmp[0] = ((u128)(xi) * (s)); ++ } ++ { ++ u64 xi = b[1]; ++ tmp[1] = ((u128)(xi) * (s)); ++ } ++ { ++ u64 xi = b[2]; ++ tmp[2] = ((u128)(xi) * (s)); ++ } ++ { ++ u64 xi = b[3]; ++ tmp[3] = ((u128)(xi) * (s)); ++ } ++ { ++ u64 xi = b[4]; ++ tmp[4] = ((u128)(xi) * (s)); ++ } ++ fproduct_carry_wide_(tmp); ++ b4 = tmp[4]; ++ b0 = tmp[0]; ++ b4_ = ((b4) & (((u128)(0x7ffffffffffffLLU)))); ++ b0_ = ((b0) + (((u128)(19) * (((u64)(((b4) >> (51)))))))); ++ tmp[4] = b4_; ++ tmp[0] = b0_; ++ fproduct_copy_from_wide_(output, tmp); ++} ++ ++static __always_inline void fmul(u64 *output, u64 *a, u64 *b) ++{ ++ fmul_fmul(output, a, b); ++} ++ ++static __always_inline void crecip(u64 *output, u64 *input) ++{ ++ crecip_crecip(output, input); ++} ++ ++static __always_inline void point_swap_conditional_step(u64 *a, u64 *b, ++ u64 swap1, u32 ctr) ++{ ++ u32 i = ctr - 1; ++ u64 ai = a[i]; ++ u64 bi = b[i]; ++ u64 x = swap1 & (ai ^ bi); ++ u64 ai1 = ai ^ x; ++ u64 bi1 = bi ^ x; ++ a[i] = ai1; ++ b[i] = bi1; ++} ++ ++static __always_inline void point_swap_conditional5(u64 *a, u64 *b, u64 swap1) ++{ ++ point_swap_conditional_step(a, b, swap1, 5); ++ point_swap_conditional_step(a, b, swap1, 4); ++ point_swap_conditional_step(a, b, swap1, 3); ++ point_swap_conditional_step(a, b, swap1, 2); ++ point_swap_conditional_step(a, b, swap1, 1); ++} ++ ++static __always_inline void point_swap_conditional(u64 *a, u64 *b, u64 iswap) ++{ ++ u64 swap1 = 0 - iswap; ++ point_swap_conditional5(a, b, swap1); ++ point_swap_conditional5(a + 5, b + 5, swap1); ++} ++ ++static __always_inline void point_copy(u64 *output, u64 *input) ++{ ++ memcpy(output, input, 5 * sizeof(*input)); ++ memcpy(output + 5, input + 5, 5 * sizeof(*input)); ++} ++ ++static __always_inline void addanddouble_fmonty(u64 *pp, u64 *ppq, u64 *p, ++ u64 *pq, u64 *qmqp) ++{ ++ u64 *qx = qmqp; ++ u64 *x2 = pp; ++ u64 *z2 = pp + 5; ++ u64 *x3 = ppq; ++ u64 *z3 = ppq + 5; ++ u64 *x = p; ++ u64 *z = p + 5; ++ u64 *xprime = pq; ++ u64 *zprime = pq + 5; ++ u64 buf[40] = { 0 }; ++ u64 *origx = buf; ++ u64 *origxprime0 = buf + 5; ++ u64 *xxprime0; ++ u64 *zzprime0; ++ u64 *origxprime; ++ xxprime0 = buf + 25; ++ zzprime0 = buf + 30; ++ memcpy(origx, x, 5 * sizeof(*x)); ++ fsum(x, z); ++ fdifference(z, origx); ++ memcpy(origxprime0, xprime, 5 * sizeof(*xprime)); ++ fsum(xprime, zprime); ++ fdifference(zprime, origxprime0); ++ fmul(xxprime0, xprime, z); ++ fmul(zzprime0, x, zprime); ++ origxprime = buf + 5; ++ { ++ u64 *xx0; ++ u64 *zz0; ++ u64 *xxprime; ++ u64 *zzprime; ++ u64 *zzzprime; ++ xx0 = buf + 15; ++ zz0 = buf + 20; ++ xxprime = buf + 25; ++ zzprime = buf + 30; ++ zzzprime = buf + 35; ++ memcpy(origxprime, xxprime, 5 * sizeof(*xxprime)); ++ fsum(xxprime, zzprime); ++ fdifference(zzprime, origxprime); ++ fsquare_fsquare_times(x3, xxprime, 1); ++ fsquare_fsquare_times(zzzprime, zzprime, 1); ++ fmul(z3, zzzprime, qx); ++ fsquare_fsquare_times(xx0, x, 1); ++ fsquare_fsquare_times(zz0, z, 1); ++ { ++ u64 *zzz; ++ u64 *xx; ++ u64 *zz; ++ u64 scalar; ++ zzz = buf + 10; ++ xx = buf + 15; ++ zz = buf + 20; ++ fmul(x2, xx, zz); ++ fdifference(zz, xx); ++ scalar = 121665; ++ fscalar(zzz, zz, scalar); ++ fsum(zzz, xx); ++ fmul(z2, zzz, zz); ++ } ++ } ++} ++ ++static __always_inline void ++ladder_smallloop_cmult_small_loop_step(u64 *nq, u64 *nqpq, u64 *nq2, u64 *nqpq2, ++ u64 *q, u8 byt) ++{ ++ u64 bit0 = (u64)(byt >> 7); ++ u64 bit; ++ point_swap_conditional(nq, nqpq, bit0); ++ addanddouble_fmonty(nq2, nqpq2, nq, nqpq, q); ++ bit = (u64)(byt >> 7); ++ point_swap_conditional(nq2, nqpq2, bit); ++} ++ ++static __always_inline void ++ladder_smallloop_cmult_small_loop_double_step(u64 *nq, u64 *nqpq, u64 *nq2, ++ u64 *nqpq2, u64 *q, u8 byt) ++{ ++ u8 byt1; ++ ladder_smallloop_cmult_small_loop_step(nq, nqpq, nq2, nqpq2, q, byt); ++ byt1 = byt << 1; ++ ladder_smallloop_cmult_small_loop_step(nq2, nqpq2, nq, nqpq, q, byt1); ++} ++ ++static __always_inline void ++ladder_smallloop_cmult_small_loop(u64 *nq, u64 *nqpq, u64 *nq2, u64 *nqpq2, ++ u64 *q, u8 byt, u32 i) ++{ ++ while (i--) { ++ ladder_smallloop_cmult_small_loop_double_step(nq, nqpq, nq2, ++ nqpq2, q, byt); ++ byt <<= 2; ++ } ++} ++ ++static __always_inline void ladder_bigloop_cmult_big_loop(u8 *n1, u64 *nq, ++ u64 *nqpq, u64 *nq2, ++ u64 *nqpq2, u64 *q, ++ u32 i) ++{ ++ while (i--) { ++ u8 byte = n1[i]; ++ ladder_smallloop_cmult_small_loop(nq, nqpq, nq2, nqpq2, q, ++ byte, 4); ++ } ++} ++ ++static void ladder_cmult(u64 *result, u8 *n1, u64 *q) ++{ ++ u64 point_buf[40] = { 0 }; ++ u64 *nq = point_buf; ++ u64 *nqpq = point_buf + 10; ++ u64 *nq2 = point_buf + 20; ++ u64 *nqpq2 = point_buf + 30; ++ point_copy(nqpq, q); ++ nq[0] = 1; ++ ladder_bigloop_cmult_big_loop(n1, nq, nqpq, nq2, nqpq2, q, 32); ++ point_copy(result, nq); ++} ++ ++static __always_inline void format_fexpand(u64 *output, const u8 *input) ++{ ++ const u8 *x00 = input + 6; ++ const u8 *x01 = input + 12; ++ const u8 *x02 = input + 19; ++ const u8 *x0 = input + 24; ++ u64 i0, i1, i2, i3, i4, output0, output1, output2, output3, output4; ++ i0 = get_unaligned_le64(input); ++ i1 = get_unaligned_le64(x00); ++ i2 = get_unaligned_le64(x01); ++ i3 = get_unaligned_le64(x02); ++ i4 = get_unaligned_le64(x0); ++ output0 = i0 & 0x7ffffffffffffLLU; ++ output1 = i1 >> 3 & 0x7ffffffffffffLLU; ++ output2 = i2 >> 6 & 0x7ffffffffffffLLU; ++ output3 = i3 >> 1 & 0x7ffffffffffffLLU; ++ output4 = i4 >> 12 & 0x7ffffffffffffLLU; ++ output[0] = output0; ++ output[1] = output1; ++ output[2] = output2; ++ output[3] = output3; ++ output[4] = output4; ++} ++ ++static __always_inline void format_fcontract_first_carry_pass(u64 *input) ++{ ++ u64 t0 = input[0]; ++ u64 t1 = input[1]; ++ u64 t2 = input[2]; ++ u64 t3 = input[3]; ++ u64 t4 = input[4]; ++ u64 t1_ = t1 + (t0 >> 51); ++ u64 t0_ = t0 & 0x7ffffffffffffLLU; ++ u64 t2_ = t2 + (t1_ >> 51); ++ u64 t1__ = t1_ & 0x7ffffffffffffLLU; ++ u64 t3_ = t3 + (t2_ >> 51); ++ u64 t2__ = t2_ & 0x7ffffffffffffLLU; ++ u64 t4_ = t4 + (t3_ >> 51); ++ u64 t3__ = t3_ & 0x7ffffffffffffLLU; ++ input[0] = t0_; ++ input[1] = t1__; ++ input[2] = t2__; ++ input[3] = t3__; ++ input[4] = t4_; ++} ++ ++static __always_inline void format_fcontract_first_carry_full(u64 *input) ++{ ++ format_fcontract_first_carry_pass(input); ++ modulo_carry_top(input); ++} ++ ++static __always_inline void format_fcontract_second_carry_pass(u64 *input) ++{ ++ u64 t0 = input[0]; ++ u64 t1 = input[1]; ++ u64 t2 = input[2]; ++ u64 t3 = input[3]; ++ u64 t4 = input[4]; ++ u64 t1_ = t1 + (t0 >> 51); ++ u64 t0_ = t0 & 0x7ffffffffffffLLU; ++ u64 t2_ = t2 + (t1_ >> 51); ++ u64 t1__ = t1_ & 0x7ffffffffffffLLU; ++ u64 t3_ = t3 + (t2_ >> 51); ++ u64 t2__ = t2_ & 0x7ffffffffffffLLU; ++ u64 t4_ = t4 + (t3_ >> 51); ++ u64 t3__ = t3_ & 0x7ffffffffffffLLU; ++ input[0] = t0_; ++ input[1] = t1__; ++ input[2] = t2__; ++ input[3] = t3__; ++ input[4] = t4_; ++} ++ ++static __always_inline void format_fcontract_second_carry_full(u64 *input) ++{ ++ u64 i0; ++ u64 i1; ++ u64 i0_; ++ u64 i1_; ++ format_fcontract_second_carry_pass(input); ++ modulo_carry_top(input); ++ i0 = input[0]; ++ i1 = input[1]; ++ i0_ = i0 & 0x7ffffffffffffLLU; ++ i1_ = i1 + (i0 >> 51); ++ input[0] = i0_; ++ input[1] = i1_; ++} ++ ++static __always_inline void format_fcontract_trim(u64 *input) ++{ ++ u64 a0 = input[0]; ++ u64 a1 = input[1]; ++ u64 a2 = input[2]; ++ u64 a3 = input[3]; ++ u64 a4 = input[4]; ++ u64 mask0 = u64_gte_mask(a0, 0x7ffffffffffedLLU); ++ u64 mask1 = u64_eq_mask(a1, 0x7ffffffffffffLLU); ++ u64 mask2 = u64_eq_mask(a2, 0x7ffffffffffffLLU); ++ u64 mask3 = u64_eq_mask(a3, 0x7ffffffffffffLLU); ++ u64 mask4 = u64_eq_mask(a4, 0x7ffffffffffffLLU); ++ u64 mask = (((mask0 & mask1) & mask2) & mask3) & mask4; ++ u64 a0_ = a0 - (0x7ffffffffffedLLU & mask); ++ u64 a1_ = a1 - (0x7ffffffffffffLLU & mask); ++ u64 a2_ = a2 - (0x7ffffffffffffLLU & mask); ++ u64 a3_ = a3 - (0x7ffffffffffffLLU & mask); ++ u64 a4_ = a4 - (0x7ffffffffffffLLU & mask); ++ input[0] = a0_; ++ input[1] = a1_; ++ input[2] = a2_; ++ input[3] = a3_; ++ input[4] = a4_; ++} ++ ++static __always_inline void format_fcontract_store(u8 *output, u64 *input) ++{ ++ u64 t0 = input[0]; ++ u64 t1 = input[1]; ++ u64 t2 = input[2]; ++ u64 t3 = input[3]; ++ u64 t4 = input[4]; ++ u64 o0 = t1 << 51 | t0; ++ u64 o1 = t2 << 38 | t1 >> 13; ++ u64 o2 = t3 << 25 | t2 >> 26; ++ u64 o3 = t4 << 12 | t3 >> 39; ++ u8 *b0 = output; ++ u8 *b1 = output + 8; ++ u8 *b2 = output + 16; ++ u8 *b3 = output + 24; ++ put_unaligned_le64(o0, b0); ++ put_unaligned_le64(o1, b1); ++ put_unaligned_le64(o2, b2); ++ put_unaligned_le64(o3, b3); ++} ++ ++static __always_inline void format_fcontract(u8 *output, u64 *input) ++{ ++ format_fcontract_first_carry_full(input); ++ format_fcontract_second_carry_full(input); ++ format_fcontract_trim(input); ++ format_fcontract_store(output, input); ++} ++ ++static __always_inline void format_scalar_of_point(u8 *scalar, u64 *point) ++{ ++ u64 *x = point; ++ u64 *z = point + 5; ++ u64 buf[10] __aligned(32) = { 0 }; ++ u64 *zmone = buf; ++ u64 *sc = buf + 5; ++ crecip(zmone, z); ++ fmul(sc, x, zmone); ++ format_fcontract(scalar, sc); ++} ++ ++void curve25519_generic(u8 mypublic[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE], ++ const u8 basepoint[CURVE25519_KEY_SIZE]) ++{ ++ u64 buf0[10] __aligned(32) = { 0 }; ++ u64 *x0 = buf0; ++ u64 *z = buf0 + 5; ++ u64 *q; ++ format_fexpand(x0, basepoint); ++ z[0] = 1; ++ q = buf0; ++ { ++ u8 e[32] __aligned(32) = { 0 }; ++ u8 *scalar; ++ memcpy(e, secret, 32); ++ curve25519_clamp_secret(e); ++ scalar = e; ++ { ++ u64 buf[15] = { 0 }; ++ u64 *nq = buf; ++ u64 *x = nq; ++ x[0] = 1; ++ ladder_cmult(nq, scalar, q); ++ format_scalar_of_point(mypublic, nq); ++ memzero_explicit(buf, sizeof(buf)); ++ } ++ memzero_explicit(e, sizeof(e)); ++ } ++ memzero_explicit(buf0, sizeof(buf0)); ++} +--- /dev/null ++++ b/lib/crypto/curve25519.c +@@ -0,0 +1,25 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is an implementation of the Curve25519 ECDH algorithm, using either ++ * a 32-bit implementation or a 64-bit implementation with 128-bit integers, ++ * depending on what is supported by the target compiler. ++ * ++ * Information: https://cr.yp.to/ecdh.html ++ */ ++ ++#include ++#include ++#include ++ ++const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 }; ++const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 }; ++ ++EXPORT_SYMBOL(curve25519_null_point); ++EXPORT_SYMBOL(curve25519_base_point); ++EXPORT_SYMBOL(curve25519_generic); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Curve25519 scalar multiplication"); ++MODULE_AUTHOR("Jason A. Donenfeld "); diff --git a/ipq806x/backport-5.4/080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch b/ipq806x/backport-5.4/080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch new file mode 100644 index 0000000..b2813ae --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0026-crypto-curve25519-add-kpp-selftest.patch @@ -0,0 +1,1268 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:33 +0100 +Subject: [PATCH] crypto: curve25519 - add kpp selftest + +commit f613457a7af085728297bef71233c37faf3c01b1 upstream. + +In preparation of introducing KPP implementations of Curve25519, import +the set of test cases proposed by the Zinc patch set, but converted to +the KPP format. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/testmgr.c | 6 + + crypto/testmgr.h | 1225 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 1231 insertions(+) + +--- a/crypto/testmgr.c ++++ b/crypto/testmgr.c +@@ -4296,6 +4296,12 @@ static const struct alg_test_desc alg_te + .test = alg_test_null, + .fips_allowed = 1, + }, { ++ .alg = "curve25519", ++ .test = alg_test_kpp, ++ .suite = { ++ .kpp = __VECS(curve25519_tv_template) ++ } ++ }, { + .alg = "deflate", + .test = alg_test_comp, + .fips_allowed = 1, +--- a/crypto/testmgr.h ++++ b/crypto/testmgr.h +@@ -1030,6 +1030,1231 @@ static const struct kpp_testvec dh_tv_te + } + }; + ++static const struct kpp_testvec curve25519_tv_template[] = { ++{ ++ .secret = (u8[32]){ 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, ++ 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, ++ 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, ++ 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a }, ++ .b_public = (u8[32]){ 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, ++ 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, ++ 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, ++ 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f }, ++ .expected_ss = (u8[32]){ 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, ++ 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, ++ 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, ++ 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++{ ++ .secret = (u8[32]){ 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, ++ 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, ++ 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, ++ 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb }, ++ .b_public = (u8[32]){ 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, ++ 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, ++ 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, ++ 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a }, ++ .expected_ss = (u8[32]){ 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, ++ 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, ++ 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, ++ 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++{ ++ .secret = (u8[32]){ 1 }, ++ .b_public = (u8[32]){ 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .expected_ss = (u8[32]){ 0x3c, 0x77, 0x77, 0xca, 0xf9, 0x97, 0xb2, 0x64, ++ 0x41, 0x60, 0x77, 0x66, 0x5b, 0x4e, 0x22, 0x9d, ++ 0x0b, 0x95, 0x48, 0xdc, 0x0c, 0xd8, 0x19, 0x98, ++ 0xdd, 0xcd, 0xc5, 0xc8, 0x53, 0x3c, 0x79, 0x7f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++{ ++ .secret = (u8[32]){ 1 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0xb3, 0x2d, 0x13, 0x62, 0xc2, 0x48, 0xd6, 0x2f, ++ 0xe6, 0x26, 0x19, 0xcf, 0xf0, 0x4d, 0xd4, 0x3d, ++ 0xb7, 0x3f, 0xfc, 0x1b, 0x63, 0x08, 0xed, 0xe3, ++ 0x0b, 0x78, 0xd8, 0x73, 0x80, 0xf1, 0xe8, 0x34 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++{ ++ .secret = (u8[32]){ 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, ++ 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, ++ 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, ++ 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 }, ++ .b_public = (u8[32]){ 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, ++ 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, ++ 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, ++ 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c }, ++ .expected_ss = (u8[32]){ 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, ++ 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, ++ 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, ++ 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++{ ++ .secret = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0xfb, 0x9f }, ++ .expected_ss = (u8[32]){ 0x77, 0x52, 0xb6, 0x18, 0xc1, 0x2d, 0x48, 0xd2, ++ 0xc6, 0x93, 0x46, 0x83, 0x81, 0x7c, 0xc6, 0x57, ++ 0xf3, 0x31, 0x03, 0x19, 0x49, 0x48, 0x20, 0x05, ++ 0x42, 0x2b, 0x4e, 0xae, 0x8d, 0x1d, 0x43, 0x23 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++{ ++ .secret = (u8[32]){ 0x8e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .b_public = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x06 }, ++ .expected_ss = (u8[32]){ 0x5a, 0xdf, 0xaa, 0x25, 0x86, 0x8e, 0x32, 0x3d, ++ 0xae, 0x49, 0x62, 0xc1, 0x01, 0x5c, 0xb3, 0x12, ++ 0xe1, 0xc5, 0xc7, 0x9e, 0x95, 0x3f, 0x03, 0x99, ++ 0xb0, 0xba, 0x16, 0x22, 0xf3, 0xb6, 0xf7, 0x0c }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - normal case */ ++{ ++ .secret = (u8[32]){ 0x48, 0x52, 0x83, 0x4d, 0x9d, 0x6b, 0x77, 0xda, ++ 0xde, 0xab, 0xaa, 0xf2, 0xe1, 0x1d, 0xca, 0x66, ++ 0xd1, 0x9f, 0xe7, 0x49, 0x93, 0xa7, 0xbe, 0xc3, ++ 0x6c, 0x6e, 0x16, 0xa0, 0x98, 0x3f, 0xea, 0xba }, ++ .b_public = (u8[32]){ 0x9c, 0x64, 0x7d, 0x9a, 0xe5, 0x89, 0xb9, 0xf5, ++ 0x8f, 0xdc, 0x3c, 0xa4, 0x94, 0x7e, 0xfb, 0xc9, ++ 0x15, 0xc4, 0xb2, 0xe0, 0x8e, 0x74, 0x4a, 0x0e, ++ 0xdf, 0x46, 0x9d, 0xac, 0x59, 0xc8, 0xf8, 0x5a }, ++ .expected_ss = (u8[32]){ 0x87, 0xb7, 0xf2, 0x12, 0xb6, 0x27, 0xf7, 0xa5, ++ 0x4c, 0xa5, 0xe0, 0xbc, 0xda, 0xdd, 0xd5, 0x38, ++ 0x9d, 0x9d, 0xe6, 0x15, 0x6c, 0xdb, 0xcf, 0x8e, ++ 0xbe, 0x14, 0xff, 0xbc, 0xfb, 0x43, 0x65, 0x51 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key on twist */ ++{ ++ .secret = (u8[32]){ 0x58, 0x8c, 0x06, 0x1a, 0x50, 0x80, 0x4a, 0xc4, ++ 0x88, 0xad, 0x77, 0x4a, 0xc7, 0x16, 0xc3, 0xf5, ++ 0xba, 0x71, 0x4b, 0x27, 0x12, 0xe0, 0x48, 0x49, ++ 0x13, 0x79, 0xa5, 0x00, 0x21, 0x19, 0x98, 0xa8 }, ++ .b_public = (u8[32]){ 0x63, 0xaa, 0x40, 0xc6, 0xe3, 0x83, 0x46, 0xc5, ++ 0xca, 0xf2, 0x3a, 0x6d, 0xf0, 0xa5, 0xe6, 0xc8, ++ 0x08, 0x89, 0xa0, 0x86, 0x47, 0xe5, 0x51, 0xb3, ++ 0x56, 0x34, 0x49, 0xbe, 0xfc, 0xfc, 0x97, 0x33 }, ++ .expected_ss = (u8[32]){ 0xb1, 0xa7, 0x07, 0x51, 0x94, 0x95, 0xff, 0xff, ++ 0xb2, 0x98, 0xff, 0x94, 0x17, 0x16, 0xb0, 0x6d, ++ 0xfa, 0xb8, 0x7c, 0xf8, 0xd9, 0x11, 0x23, 0xfe, ++ 0x2b, 0xe9, 0xa2, 0x33, 0xdd, 0xa2, 0x22, 0x12 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key on twist */ ++{ ++ .secret = (u8[32]){ 0xb0, 0x5b, 0xfd, 0x32, 0xe5, 0x53, 0x25, 0xd9, ++ 0xfd, 0x64, 0x8c, 0xb3, 0x02, 0x84, 0x80, 0x39, ++ 0x00, 0x0b, 0x39, 0x0e, 0x44, 0xd5, 0x21, 0xe5, ++ 0x8a, 0xab, 0x3b, 0x29, 0xa6, 0x96, 0x0b, 0xa8 }, ++ .b_public = (u8[32]){ 0x0f, 0x83, 0xc3, 0x6f, 0xde, 0xd9, 0xd3, 0x2f, ++ 0xad, 0xf4, 0xef, 0xa3, 0xae, 0x93, 0xa9, 0x0b, ++ 0xb5, 0xcf, 0xa6, 0x68, 0x93, 0xbc, 0x41, 0x2c, ++ 0x43, 0xfa, 0x72, 0x87, 0xdb, 0xb9, 0x97, 0x79 }, ++ .expected_ss = (u8[32]){ 0x67, 0xdd, 0x4a, 0x6e, 0x16, 0x55, 0x33, 0x53, ++ 0x4c, 0x0e, 0x3f, 0x17, 0x2e, 0x4a, 0xb8, 0x57, ++ 0x6b, 0xca, 0x92, 0x3a, 0x5f, 0x07, 0xb2, 0xc0, ++ 0x69, 0xb4, 0xc3, 0x10, 0xff, 0x2e, 0x93, 0x5b }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key on twist */ ++{ ++ .secret = (u8[32]){ 0x70, 0xe3, 0x4b, 0xcb, 0xe1, 0xf4, 0x7f, 0xbc, ++ 0x0f, 0xdd, 0xfd, 0x7c, 0x1e, 0x1a, 0xa5, 0x3d, ++ 0x57, 0xbf, 0xe0, 0xf6, 0x6d, 0x24, 0x30, 0x67, ++ 0xb4, 0x24, 0xbb, 0x62, 0x10, 0xbe, 0xd1, 0x9c }, ++ .b_public = (u8[32]){ 0x0b, 0x82, 0x11, 0xa2, 0xb6, 0x04, 0x90, 0x97, ++ 0xf6, 0x87, 0x1c, 0x6c, 0x05, 0x2d, 0x3c, 0x5f, ++ 0xc1, 0xba, 0x17, 0xda, 0x9e, 0x32, 0xae, 0x45, ++ 0x84, 0x03, 0xb0, 0x5b, 0xb2, 0x83, 0x09, 0x2a }, ++ .expected_ss = (u8[32]){ 0x4a, 0x06, 0x38, 0xcf, 0xaa, 0x9e, 0xf1, 0x93, ++ 0x3b, 0x47, 0xf8, 0x93, 0x92, 0x96, 0xa6, 0xb2, ++ 0x5b, 0xe5, 0x41, 0xef, 0x7f, 0x70, 0xe8, 0x44, ++ 0xc0, 0xbc, 0xc0, 0x0b, 0x13, 0x4d, 0xe6, 0x4a }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key on twist */ ++{ ++ .secret = (u8[32]){ 0x68, 0xc1, 0xf3, 0xa6, 0x53, 0xa4, 0xcd, 0xb1, ++ 0xd3, 0x7b, 0xba, 0x94, 0x73, 0x8f, 0x8b, 0x95, ++ 0x7a, 0x57, 0xbe, 0xb2, 0x4d, 0x64, 0x6e, 0x99, ++ 0x4d, 0xc2, 0x9a, 0x27, 0x6a, 0xad, 0x45, 0x8d }, ++ .b_public = (u8[32]){ 0x34, 0x3a, 0xc2, 0x0a, 0x3b, 0x9c, 0x6a, 0x27, ++ 0xb1, 0x00, 0x81, 0x76, 0x50, 0x9a, 0xd3, 0x07, ++ 0x35, 0x85, 0x6e, 0xc1, 0xc8, 0xd8, 0xfc, 0xae, ++ 0x13, 0x91, 0x2d, 0x08, 0xd1, 0x52, 0xf4, 0x6c }, ++ .expected_ss = (u8[32]){ 0x39, 0x94, 0x91, 0xfc, 0xe8, 0xdf, 0xab, 0x73, ++ 0xb4, 0xf9, 0xf6, 0x11, 0xde, 0x8e, 0xa0, 0xb2, ++ 0x7b, 0x28, 0xf8, 0x59, 0x94, 0x25, 0x0b, 0x0f, ++ 0x47, 0x5d, 0x58, 0x5d, 0x04, 0x2a, 0xc2, 0x07 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key on twist */ ++{ ++ .secret = (u8[32]){ 0xd8, 0x77, 0xb2, 0x6d, 0x06, 0xdf, 0xf9, 0xd9, ++ 0xf7, 0xfd, 0x4c, 0x5b, 0x37, 0x69, 0xf8, 0xcd, ++ 0xd5, 0xb3, 0x05, 0x16, 0xa5, 0xab, 0x80, 0x6b, ++ 0xe3, 0x24, 0xff, 0x3e, 0xb6, 0x9e, 0xa0, 0xb2 }, ++ .b_public = (u8[32]){ 0xfa, 0x69, 0x5f, 0xc7, 0xbe, 0x8d, 0x1b, 0xe5, ++ 0xbf, 0x70, 0x48, 0x98, 0xf3, 0x88, 0xc4, 0x52, ++ 0xba, 0xfd, 0xd3, 0xb8, 0xea, 0xe8, 0x05, 0xf8, ++ 0x68, 0x1a, 0x8d, 0x15, 0xc2, 0xd4, 0xe1, 0x42 }, ++ .expected_ss = (u8[32]){ 0x2c, 0x4f, 0xe1, 0x1d, 0x49, 0x0a, 0x53, 0x86, ++ 0x17, 0x76, 0xb1, 0x3b, 0x43, 0x54, 0xab, 0xd4, ++ 0xcf, 0x5a, 0x97, 0x69, 0x9d, 0xb6, 0xe6, 0xc6, ++ 0x8c, 0x16, 0x26, 0xd0, 0x76, 0x62, 0xf7, 0x58 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case on twist */ ++{ ++ .secret = (u8[32]){ 0x38, 0xdd, 0xe9, 0xf3, 0xe7, 0xb7, 0x99, 0x04, ++ 0x5f, 0x9a, 0xc3, 0x79, 0x3d, 0x4a, 0x92, 0x77, ++ 0xda, 0xde, 0xad, 0xc4, 0x1b, 0xec, 0x02, 0x90, ++ 0xf8, 0x1f, 0x74, 0x4f, 0x73, 0x77, 0x5f, 0x84 }, ++ .b_public = (u8[32]){ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .expected_ss = (u8[32]){ 0x9a, 0x2c, 0xfe, 0x84, 0xff, 0x9c, 0x4a, 0x97, ++ 0x39, 0x62, 0x5c, 0xae, 0x4a, 0x3b, 0x82, 0xa9, ++ 0x06, 0x87, 0x7a, 0x44, 0x19, 0x46, 0xf8, 0xd7, ++ 0xb3, 0xd7, 0x95, 0xfe, 0x8f, 0x5d, 0x16, 0x39 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case on twist */ ++{ ++ .secret = (u8[32]){ 0x98, 0x57, 0xa9, 0x14, 0xe3, 0xc2, 0x90, 0x36, ++ 0xfd, 0x9a, 0x44, 0x2b, 0xa5, 0x26, 0xb5, 0xcd, ++ 0xcd, 0xf2, 0x82, 0x16, 0x15, 0x3e, 0x63, 0x6c, ++ 0x10, 0x67, 0x7a, 0xca, 0xb6, 0xbd, 0x6a, 0xa5 }, ++ .b_public = (u8[32]){ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .expected_ss = (u8[32]){ 0x4d, 0xa4, 0xe0, 0xaa, 0x07, 0x2c, 0x23, 0x2e, ++ 0xe2, 0xf0, 0xfa, 0x4e, 0x51, 0x9a, 0xe5, 0x0b, ++ 0x52, 0xc1, 0xed, 0xd0, 0x8a, 0x53, 0x4d, 0x4e, ++ 0xf3, 0x46, 0xc2, 0xe1, 0x06, 0xd2, 0x1d, 0x60 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case on twist */ ++{ ++ .secret = (u8[32]){ 0x48, 0xe2, 0x13, 0x0d, 0x72, 0x33, 0x05, 0xed, ++ 0x05, 0xe6, 0xe5, 0x89, 0x4d, 0x39, 0x8a, 0x5e, ++ 0x33, 0x36, 0x7a, 0x8c, 0x6a, 0xac, 0x8f, 0xcd, ++ 0xf0, 0xa8, 0x8e, 0x4b, 0x42, 0x82, 0x0d, 0xb7 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0xf8, 0xff, ++ 0xff, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00, ++ 0x00, 0xf0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00 }, ++ .expected_ss = (u8[32]){ 0x9e, 0xd1, 0x0c, 0x53, 0x74, 0x7f, 0x64, 0x7f, ++ 0x82, 0xf4, 0x51, 0x25, 0xd3, 0xde, 0x15, 0xa1, ++ 0xe6, 0xb8, 0x24, 0x49, 0x6a, 0xb4, 0x04, 0x10, ++ 0xff, 0xcc, 0x3c, 0xfe, 0x95, 0x76, 0x0f, 0x3b }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case on twist */ ++{ ++ .secret = (u8[32]){ 0x28, 0xf4, 0x10, 0x11, 0x69, 0x18, 0x51, 0xb3, ++ 0xa6, 0x2b, 0x64, 0x15, 0x53, 0xb3, 0x0d, 0x0d, ++ 0xfd, 0xdc, 0xb8, 0xff, 0xfc, 0xf5, 0x37, 0x00, ++ 0xa7, 0xbe, 0x2f, 0x6a, 0x87, 0x2e, 0x9f, 0xb0 }, ++ .b_public = (u8[32]){ 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x07, 0x00, ++ 0x00, 0xe0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8, 0xff, ++ 0xff, 0x0f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0xcf, 0x72, 0xb4, 0xaa, 0x6a, 0xa1, 0xc9, 0xf8, ++ 0x94, 0xf4, 0x16, 0x5b, 0x86, 0x10, 0x9a, 0xa4, ++ 0x68, 0x51, 0x76, 0x48, 0xe1, 0xf0, 0xcc, 0x70, ++ 0xe1, 0xab, 0x08, 0x46, 0x01, 0x76, 0x50, 0x6b }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case on twist */ ++{ ++ .secret = (u8[32]){ 0x18, 0xa9, 0x3b, 0x64, 0x99, 0xb9, 0xf6, 0xb3, ++ 0x22, 0x5c, 0xa0, 0x2f, 0xef, 0x41, 0x0e, 0x0a, ++ 0xde, 0xc2, 0x35, 0x32, 0x32, 0x1d, 0x2d, 0x8e, ++ 0xf1, 0xa6, 0xd6, 0x02, 0xa8, 0xc6, 0x5b, 0x83 }, ++ .b_public = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0x5d, 0x50, 0xb6, 0x28, 0x36, 0xbb, 0x69, 0x57, ++ 0x94, 0x10, 0x38, 0x6c, 0xf7, 0xbb, 0x81, 0x1c, ++ 0x14, 0xbf, 0x85, 0xb1, 0xc7, 0xb1, 0x7e, 0x59, ++ 0x24, 0xc7, 0xff, 0xea, 0x91, 0xef, 0x9e, 0x12 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case on twist */ ++{ ++ .secret = (u8[32]){ 0xc0, 0x1d, 0x13, 0x05, 0xa1, 0x33, 0x8a, 0x1f, ++ 0xca, 0xc2, 0xba, 0x7e, 0x2e, 0x03, 0x2b, 0x42, ++ 0x7e, 0x0b, 0x04, 0x90, 0x31, 0x65, 0xac, 0xa9, ++ 0x57, 0xd8, 0xd0, 0x55, 0x3d, 0x87, 0x17, 0xb0 }, ++ .b_public = (u8[32]){ 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0x19, 0x23, 0x0e, 0xb1, 0x48, 0xd5, 0xd6, 0x7c, ++ 0x3c, 0x22, 0xab, 0x1d, 0xae, 0xff, 0x80, 0xa5, ++ 0x7e, 0xae, 0x42, 0x65, 0xce, 0x28, 0x72, 0x65, ++ 0x7b, 0x2c, 0x80, 0x99, 0xfc, 0x69, 0x8e, 0x50 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for public key */ ++{ ++ .secret = (u8[32]){ 0x38, 0x6f, 0x7f, 0x16, 0xc5, 0x07, 0x31, 0xd6, ++ 0x4f, 0x82, 0xe6, 0xa1, 0x70, 0xb1, 0x42, 0xa4, ++ 0xe3, 0x4f, 0x31, 0xfd, 0x77, 0x68, 0xfc, 0xb8, ++ 0x90, 0x29, 0x25, 0xe7, 0xd1, 0xe2, 0x1a, 0xbe }, ++ .b_public = (u8[32]){ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .expected_ss = (u8[32]){ 0x0f, 0xca, 0xb5, 0xd8, 0x42, 0xa0, 0x78, 0xd7, ++ 0xa7, 0x1f, 0xc5, 0x9b, 0x57, 0xbf, 0xb4, 0xca, ++ 0x0b, 0xe6, 0x87, 0x3b, 0x49, 0xdc, 0xdb, 0x9f, ++ 0x44, 0xe1, 0x4a, 0xe8, 0xfb, 0xdf, 0xa5, 0x42 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for public key */ ++{ ++ .secret = (u8[32]){ 0xe0, 0x23, 0xa2, 0x89, 0xbd, 0x5e, 0x90, 0xfa, ++ 0x28, 0x04, 0xdd, 0xc0, 0x19, 0xa0, 0x5e, 0xf3, ++ 0xe7, 0x9d, 0x43, 0x4b, 0xb6, 0xea, 0x2f, 0x52, ++ 0x2e, 0xcb, 0x64, 0x3a, 0x75, 0x29, 0x6e, 0x95 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, ++ .expected_ss = (u8[32]){ 0x54, 0xce, 0x8f, 0x22, 0x75, 0xc0, 0x77, 0xe3, ++ 0xb1, 0x30, 0x6a, 0x39, 0x39, 0xc5, 0xe0, 0x3e, ++ 0xef, 0x6b, 0xbb, 0x88, 0x06, 0x05, 0x44, 0x75, ++ 0x8d, 0x9f, 0xef, 0x59, 0xb0, 0xbc, 0x3e, 0x4f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for public key */ ++{ ++ .secret = (u8[32]){ 0x68, 0xf0, 0x10, 0xd6, 0x2e, 0xe8, 0xd9, 0x26, ++ 0x05, 0x3a, 0x36, 0x1c, 0x3a, 0x75, 0xc6, 0xea, ++ 0x4e, 0xbd, 0xc8, 0x60, 0x6a, 0xb2, 0x85, 0x00, ++ 0x3a, 0x6f, 0x8f, 0x40, 0x76, 0xb0, 0x1e, 0x83 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 }, ++ .expected_ss = (u8[32]){ 0xf1, 0x36, 0x77, 0x5c, 0x5b, 0xeb, 0x0a, 0xf8, ++ 0x11, 0x0a, 0xf1, 0x0b, 0x20, 0x37, 0x23, 0x32, ++ 0x04, 0x3c, 0xab, 0x75, 0x24, 0x19, 0x67, 0x87, ++ 0x75, 0xa2, 0x23, 0xdf, 0x57, 0xc9, 0xd3, 0x0d }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for public key */ ++{ ++ .secret = (u8[32]){ 0x58, 0xeb, 0xcb, 0x35, 0xb0, 0xf8, 0x84, 0x5c, ++ 0xaf, 0x1e, 0xc6, 0x30, 0xf9, 0x65, 0x76, 0xb6, ++ 0x2c, 0x4b, 0x7b, 0x6c, 0x36, 0xb2, 0x9d, 0xeb, ++ 0x2c, 0xb0, 0x08, 0x46, 0x51, 0x75, 0x5c, 0x96 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xfb, 0xff, ++ 0xff, 0xdf, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, ++ 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xf7, 0xff, ++ 0xff, 0xf7, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x3f }, ++ .expected_ss = (u8[32]){ 0xbf, 0x9a, 0xff, 0xd0, 0x6b, 0x84, 0x40, 0x85, ++ 0x58, 0x64, 0x60, 0x96, 0x2e, 0xf2, 0x14, 0x6f, ++ 0xf3, 0xd4, 0x53, 0x3d, 0x94, 0x44, 0xaa, 0xb0, ++ 0x06, 0xeb, 0x88, 0xcc, 0x30, 0x54, 0x40, 0x7d }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for public key */ ++{ ++ .secret = (u8[32]){ 0x18, 0x8c, 0x4b, 0xc5, 0xb9, 0xc4, 0x4b, 0x38, ++ 0xbb, 0x65, 0x8b, 0x9b, 0x2a, 0xe8, 0x2d, 0x5b, ++ 0x01, 0x01, 0x5e, 0x09, 0x31, 0x84, 0xb1, 0x7c, ++ 0xb7, 0x86, 0x35, 0x03, 0xa7, 0x83, 0xe1, 0xbb }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .expected_ss = (u8[32]){ 0xd4, 0x80, 0xde, 0x04, 0xf6, 0x99, 0xcb, 0x3b, ++ 0xe0, 0x68, 0x4a, 0x9c, 0xc2, 0xe3, 0x12, 0x81, ++ 0xea, 0x0b, 0xc5, 0xa9, 0xdc, 0xc1, 0x57, 0xd3, ++ 0xd2, 0x01, 0x58, 0xd4, 0x6c, 0xa5, 0x24, 0x6d }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for public key */ ++{ ++ .secret = (u8[32]){ 0xe0, 0x6c, 0x11, 0xbb, 0x2e, 0x13, 0xce, 0x3d, ++ 0xc7, 0x67, 0x3f, 0x67, 0xf5, 0x48, 0x22, 0x42, ++ 0x90, 0x94, 0x23, 0xa9, 0xae, 0x95, 0xee, 0x98, ++ 0x6a, 0x98, 0x8d, 0x98, 0xfa, 0xee, 0x23, 0xa2 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0x4c, 0x44, 0x01, 0xcc, 0xe6, 0xb5, 0x1e, 0x4c, ++ 0xb1, 0x8f, 0x27, 0x90, 0x24, 0x6c, 0x9b, 0xf9, ++ 0x14, 0xdb, 0x66, 0x77, 0x50, 0xa1, 0xcb, 0x89, ++ 0x06, 0x90, 0x92, 0xaf, 0x07, 0x29, 0x22, 0x76 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for public key */ ++{ ++ .secret = (u8[32]){ 0xc0, 0x65, 0x8c, 0x46, 0xdd, 0xe1, 0x81, 0x29, ++ 0x29, 0x38, 0x77, 0x53, 0x5b, 0x11, 0x62, 0xb6, ++ 0xf9, 0xf5, 0x41, 0x4a, 0x23, 0xcf, 0x4d, 0x2c, ++ 0xbc, 0x14, 0x0a, 0x4d, 0x99, 0xda, 0x2b, 0x8f }, ++ .b_public = (u8[32]){ 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0x57, 0x8b, 0xa8, 0xcc, 0x2d, 0xbd, 0xc5, 0x75, ++ 0xaf, 0xcf, 0x9d, 0xf2, 0xb3, 0xee, 0x61, 0x89, ++ 0xf5, 0x33, 0x7d, 0x68, 0x54, 0xc7, 0x9b, 0x4c, ++ 0xe1, 0x65, 0xea, 0x12, 0x29, 0x3b, 0x3a, 0x0f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0xf0, 0x1e, 0x48, 0xda, 0xfa, 0xc9, 0xd7, 0xbc, ++ 0xf5, 0x89, 0xcb, 0xc3, 0x82, 0xc8, 0x78, 0xd1, ++ 0x8b, 0xda, 0x35, 0x50, 0x58, 0x9f, 0xfb, 0x5d, ++ 0x50, 0xb5, 0x23, 0xbe, 0xbe, 0x32, 0x9d, 0xae }, ++ .b_public = (u8[32]){ 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0xbd, 0x36, 0xa0, 0x79, 0x0e, 0xb8, 0x83, 0x09, ++ 0x8c, 0x98, 0x8b, 0x21, 0x78, 0x67, 0x73, 0xde, ++ 0x0b, 0x3a, 0x4d, 0xf1, 0x62, 0x28, 0x2c, 0xf1, ++ 0x10, 0xde, 0x18, 0xdd, 0x48, 0x4c, 0xe7, 0x4b }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x28, 0x87, 0x96, 0xbc, 0x5a, 0xff, 0x4b, 0x81, ++ 0xa3, 0x75, 0x01, 0x75, 0x7b, 0xc0, 0x75, 0x3a, ++ 0x3c, 0x21, 0x96, 0x47, 0x90, 0xd3, 0x86, 0x99, ++ 0x30, 0x8d, 0xeb, 0xc1, 0x7a, 0x6e, 0xaf, 0x8d }, ++ .b_public = (u8[32]){ 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0xb4, 0xe0, 0xdd, 0x76, 0xda, 0x7b, 0x07, 0x17, ++ 0x28, 0xb6, 0x1f, 0x85, 0x67, 0x71, 0xaa, 0x35, ++ 0x6e, 0x57, 0xed, 0xa7, 0x8a, 0x5b, 0x16, 0x55, ++ 0xcc, 0x38, 0x20, 0xfb, 0x5f, 0x85, 0x4c, 0x5c }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x98, 0xdf, 0x84, 0x5f, 0x66, 0x51, 0xbf, 0x11, ++ 0x38, 0x22, 0x1f, 0x11, 0x90, 0x41, 0xf7, 0x2b, ++ 0x6d, 0xbc, 0x3c, 0x4a, 0xce, 0x71, 0x43, 0xd9, ++ 0x9f, 0xd5, 0x5a, 0xd8, 0x67, 0x48, 0x0d, 0xa8 }, ++ .b_public = (u8[32]){ 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0x6f, 0xdf, 0x6c, 0x37, 0x61, 0x1d, 0xbd, 0x53, ++ 0x04, 0xdc, 0x0f, 0x2e, 0xb7, 0xc9, 0x51, 0x7e, ++ 0xb3, 0xc5, 0x0e, 0x12, 0xfd, 0x05, 0x0a, 0xc6, ++ 0xde, 0xc2, 0x70, 0x71, 0xd4, 0xbf, 0xc0, 0x34 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0xf0, 0x94, 0x98, 0xe4, 0x6f, 0x02, 0xf8, 0x78, ++ 0x82, 0x9e, 0x78, 0xb8, 0x03, 0xd3, 0x16, 0xa2, ++ 0xed, 0x69, 0x5d, 0x04, 0x98, 0xa0, 0x8a, 0xbd, ++ 0xf8, 0x27, 0x69, 0x30, 0xe2, 0x4e, 0xdc, 0xb0 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .expected_ss = (u8[32]){ 0x4c, 0x8f, 0xc4, 0xb1, 0xc6, 0xab, 0x88, 0xfb, ++ 0x21, 0xf1, 0x8f, 0x6d, 0x4c, 0x81, 0x02, 0x40, ++ 0xd4, 0xe9, 0x46, 0x51, 0xba, 0x44, 0xf7, 0xa2, ++ 0xc8, 0x63, 0xce, 0xc7, 0xdc, 0x56, 0x60, 0x2d }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x18, 0x13, 0xc1, 0x0a, 0x5c, 0x7f, 0x21, 0xf9, ++ 0x6e, 0x17, 0xf2, 0x88, 0xc0, 0xcc, 0x37, 0x60, ++ 0x7c, 0x04, 0xc5, 0xf5, 0xae, 0xa2, 0xdb, 0x13, ++ 0x4f, 0x9e, 0x2f, 0xfc, 0x66, 0xbd, 0x9d, 0xb8 }, ++ .b_public = (u8[32]){ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .expected_ss = (u8[32]){ 0x1c, 0xd0, 0xb2, 0x82, 0x67, 0xdc, 0x54, 0x1c, ++ 0x64, 0x2d, 0x6d, 0x7d, 0xca, 0x44, 0xa8, 0xb3, ++ 0x8a, 0x63, 0x73, 0x6e, 0xef, 0x5c, 0x4e, 0x65, ++ 0x01, 0xff, 0xbb, 0xb1, 0x78, 0x0c, 0x03, 0x3c }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x78, 0x57, 0xfb, 0x80, 0x86, 0x53, 0x64, 0x5a, ++ 0x0b, 0xeb, 0x13, 0x8a, 0x64, 0xf5, 0xf4, 0xd7, ++ 0x33, 0xa4, 0x5e, 0xa8, 0x4c, 0x3c, 0xda, 0x11, ++ 0xa9, 0xc0, 0x6f, 0x7e, 0x71, 0x39, 0x14, 0x9e }, ++ .b_public = (u8[32]){ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .expected_ss = (u8[32]){ 0x87, 0x55, 0xbe, 0x01, 0xc6, 0x0a, 0x7e, 0x82, ++ 0x5c, 0xff, 0x3e, 0x0e, 0x78, 0xcb, 0x3a, 0xa4, ++ 0x33, 0x38, 0x61, 0x51, 0x6a, 0xa5, 0x9b, 0x1c, ++ 0x51, 0xa8, 0xb2, 0xa5, 0x43, 0xdf, 0xa8, 0x22 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0xe0, 0x3a, 0xa8, 0x42, 0xe2, 0xab, 0xc5, 0x6e, ++ 0x81, 0xe8, 0x7b, 0x8b, 0x9f, 0x41, 0x7b, 0x2a, ++ 0x1e, 0x59, 0x13, 0xc7, 0x23, 0xee, 0xd2, 0x8d, ++ 0x75, 0x2f, 0x8d, 0x47, 0xa5, 0x9f, 0x49, 0x8f }, ++ .b_public = (u8[32]){ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .expected_ss = (u8[32]){ 0x54, 0xc9, 0xa1, 0xed, 0x95, 0xe5, 0x46, 0xd2, ++ 0x78, 0x22, 0xa3, 0x60, 0x93, 0x1d, 0xda, 0x60, ++ 0xa1, 0xdf, 0x04, 0x9d, 0xa6, 0xf9, 0x04, 0x25, ++ 0x3c, 0x06, 0x12, 0xbb, 0xdc, 0x08, 0x74, 0x76 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0xf8, 0xf7, 0x07, 0xb7, 0x99, 0x9b, 0x18, 0xcb, ++ 0x0d, 0x6b, 0x96, 0x12, 0x4f, 0x20, 0x45, 0x97, ++ 0x2c, 0xa2, 0x74, 0xbf, 0xc1, 0x54, 0xad, 0x0c, ++ 0x87, 0x03, 0x8c, 0x24, 0xc6, 0xd0, 0xd4, 0xb2 }, ++ .b_public = (u8[32]){ 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0xcc, 0x1f, 0x40, 0xd7, 0x43, 0xcd, 0xc2, 0x23, ++ 0x0e, 0x10, 0x43, 0xda, 0xba, 0x8b, 0x75, 0xe8, ++ 0x10, 0xf1, 0xfb, 0xab, 0x7f, 0x25, 0x52, 0x69, ++ 0xbd, 0x9e, 0xbb, 0x29, 0xe6, 0xbf, 0x49, 0x4f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0xa0, 0x34, 0xf6, 0x84, 0xfa, 0x63, 0x1e, 0x1a, ++ 0x34, 0x81, 0x18, 0xc1, 0xce, 0x4c, 0x98, 0x23, ++ 0x1f, 0x2d, 0x9e, 0xec, 0x9b, 0xa5, 0x36, 0x5b, ++ 0x4a, 0x05, 0xd6, 0x9a, 0x78, 0x5b, 0x07, 0x96 }, ++ .b_public = (u8[32]){ 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0x54, 0x99, 0x8e, 0xe4, 0x3a, 0x5b, 0x00, 0x7b, ++ 0xf4, 0x99, 0xf0, 0x78, 0xe7, 0x36, 0x52, 0x44, ++ 0x00, 0xa8, 0xb5, 0xc7, 0xe9, 0xb9, 0xb4, 0x37, ++ 0x71, 0x74, 0x8c, 0x7c, 0xdf, 0x88, 0x04, 0x12 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x30, 0xb6, 0xc6, 0xa0, 0xf2, 0xff, 0xa6, 0x80, ++ 0x76, 0x8f, 0x99, 0x2b, 0xa8, 0x9e, 0x15, 0x2d, ++ 0x5b, 0xc9, 0x89, 0x3d, 0x38, 0xc9, 0x11, 0x9b, ++ 0xe4, 0xf7, 0x67, 0xbf, 0xab, 0x6e, 0x0c, 0xa5 }, ++ .b_public = (u8[32]){ 0xdc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0xea, 0xd9, 0xb3, 0x8e, 0xfd, 0xd7, 0x23, 0x63, ++ 0x79, 0x34, 0xe5, 0x5a, 0xb7, 0x17, 0xa7, 0xae, ++ 0x09, 0xeb, 0x86, 0xa2, 0x1d, 0xc3, 0x6a, 0x3f, ++ 0xee, 0xb8, 0x8b, 0x75, 0x9e, 0x39, 0x1e, 0x09 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x90, 0x1b, 0x9d, 0xcf, 0x88, 0x1e, 0x01, 0xe0, ++ 0x27, 0x57, 0x50, 0x35, 0xd4, 0x0b, 0x43, 0xbd, ++ 0xc1, 0xc5, 0x24, 0x2e, 0x03, 0x08, 0x47, 0x49, ++ 0x5b, 0x0c, 0x72, 0x86, 0x46, 0x9b, 0x65, 0x91 }, ++ .b_public = (u8[32]){ 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0x60, 0x2f, 0xf4, 0x07, 0x89, 0xb5, 0x4b, 0x41, ++ 0x80, 0x59, 0x15, 0xfe, 0x2a, 0x62, 0x21, 0xf0, ++ 0x7a, 0x50, 0xff, 0xc2, 0xc3, 0xfc, 0x94, 0xcf, ++ 0x61, 0xf1, 0x3d, 0x79, 0x04, 0xe8, 0x8e, 0x0e }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x80, 0x46, 0x67, 0x7c, 0x28, 0xfd, 0x82, 0xc9, ++ 0xa1, 0xbd, 0xb7, 0x1a, 0x1a, 0x1a, 0x34, 0xfa, ++ 0xba, 0x12, 0x25, 0xe2, 0x50, 0x7f, 0xe3, 0xf5, ++ 0x4d, 0x10, 0xbd, 0x5b, 0x0d, 0x86, 0x5f, 0x8e }, ++ .b_public = (u8[32]){ 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0xe0, 0x0a, 0xe8, 0xb1, 0x43, 0x47, 0x12, 0x47, ++ 0xba, 0x24, 0xf1, 0x2c, 0x88, 0x55, 0x36, 0xc3, ++ 0xcb, 0x98, 0x1b, 0x58, 0xe1, 0xe5, 0x6b, 0x2b, ++ 0xaf, 0x35, 0xc1, 0x2a, 0xe1, 0xf7, 0x9c, 0x26 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x60, 0x2f, 0x7e, 0x2f, 0x68, 0xa8, 0x46, 0xb8, ++ 0x2c, 0xc2, 0x69, 0xb1, 0xd4, 0x8e, 0x93, 0x98, ++ 0x86, 0xae, 0x54, 0xfd, 0x63, 0x6c, 0x1f, 0xe0, ++ 0x74, 0xd7, 0x10, 0x12, 0x7d, 0x47, 0x24, 0x91 }, ++ .b_public = (u8[32]){ 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0x98, 0xcb, 0x9b, 0x50, 0xdd, 0x3f, 0xc2, 0xb0, ++ 0xd4, 0xf2, 0xd2, 0xbf, 0x7c, 0x5c, 0xfd, 0xd1, ++ 0x0c, 0x8f, 0xcd, 0x31, 0xfc, 0x40, 0xaf, 0x1a, ++ 0xd4, 0x4f, 0x47, 0xc1, 0x31, 0x37, 0x63, 0x62 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x60, 0x88, 0x7b, 0x3d, 0xc7, 0x24, 0x43, 0x02, ++ 0x6e, 0xbe, 0xdb, 0xbb, 0xb7, 0x06, 0x65, 0xf4, ++ 0x2b, 0x87, 0xad, 0xd1, 0x44, 0x0e, 0x77, 0x68, ++ 0xfb, 0xd7, 0xe8, 0xe2, 0xce, 0x5f, 0x63, 0x9d }, ++ .b_public = (u8[32]){ 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0x38, 0xd6, 0x30, 0x4c, 0x4a, 0x7e, 0x6d, 0x9f, ++ 0x79, 0x59, 0x33, 0x4f, 0xb5, 0x24, 0x5b, 0xd2, ++ 0xc7, 0x54, 0x52, 0x5d, 0x4c, 0x91, 0xdb, 0x95, ++ 0x02, 0x06, 0x92, 0x62, 0x34, 0xc1, 0xf6, 0x33 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0x78, 0xd3, 0x1d, 0xfa, 0x85, 0x44, 0x97, 0xd7, ++ 0x2d, 0x8d, 0xef, 0x8a, 0x1b, 0x7f, 0xb0, 0x06, ++ 0xce, 0xc2, 0xd8, 0xc4, 0x92, 0x46, 0x47, 0xc9, ++ 0x38, 0x14, 0xae, 0x56, 0xfa, 0xed, 0xa4, 0x95 }, ++ .b_public = (u8[32]){ 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0x78, 0x6c, 0xd5, 0x49, 0x96, 0xf0, 0x14, 0xa5, ++ 0xa0, 0x31, 0xec, 0x14, 0xdb, 0x81, 0x2e, 0xd0, ++ 0x83, 0x55, 0x06, 0x1f, 0xdb, 0x5d, 0xe6, 0x80, ++ 0xa8, 0x00, 0xac, 0x52, 0x1f, 0x31, 0x8e, 0x23 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - public key >= p */ ++{ ++ .secret = (u8[32]){ 0xc0, 0x4c, 0x5b, 0xae, 0xfa, 0x83, 0x02, 0xdd, ++ 0xde, 0xd6, 0xa4, 0xbb, 0x95, 0x77, 0x61, 0xb4, ++ 0xeb, 0x97, 0xae, 0xfa, 0x4f, 0xc3, 0xb8, 0x04, ++ 0x30, 0x85, 0xf9, 0x6a, 0x56, 0x59, 0xb3, 0xa5 }, ++ .b_public = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .expected_ss = (u8[32]){ 0x29, 0xae, 0x8b, 0xc7, 0x3e, 0x9b, 0x10, 0xa0, ++ 0x8b, 0x4f, 0x68, 0x1c, 0x43, 0xc3, 0xe0, 0xac, ++ 0x1a, 0x17, 0x1d, 0x31, 0xb3, 0x8f, 0x1a, 0x48, ++ 0xef, 0xba, 0x29, 0xae, 0x63, 0x9e, 0xa1, 0x34 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - RFC 7748 */ ++{ ++ .secret = (u8[32]){ 0xa0, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, ++ 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, ++ 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, ++ 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0x44 }, ++ .b_public = (u8[32]){ 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, ++ 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, ++ 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, ++ 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c }, ++ .expected_ss = (u8[32]){ 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, ++ 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, ++ 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, ++ 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - RFC 7748 */ ++{ ++ .secret = (u8[32]){ 0x48, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, ++ 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, ++ 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, ++ 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x4d }, ++ .b_public = (u8[32]){ 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, ++ 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, ++ 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, ++ 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x13 }, ++ .expected_ss = (u8[32]){ 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, ++ 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8, ++ 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, ++ 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x0a, 0xb4, 0xe7, 0x63, 0x80, 0xd8, 0x4d, 0xde, ++ 0x4f, 0x68, 0x33, 0xc5, 0x8f, 0x2a, 0x9f, 0xb8, ++ 0xf8, 0x3b, 0xb0, 0x16, 0x9b, 0x17, 0x2b, 0xe4, ++ 0xb6, 0xe0, 0x59, 0x28, 0x87, 0x74, 0x1a, 0x36 }, ++ .expected_ss = (u8[32]){ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x89, 0xe1, 0x0d, 0x57, 0x01, 0xb4, 0x33, 0x7d, ++ 0x2d, 0x03, 0x21, 0x81, 0x53, 0x8b, 0x10, 0x64, ++ 0xbd, 0x40, 0x84, 0x40, 0x1c, 0xec, 0xa1, 0xfd, ++ 0x12, 0x66, 0x3a, 0x19, 0x59, 0x38, 0x80, 0x00 }, ++ .expected_ss = (u8[32]){ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x2b, 0x55, 0xd3, 0xaa, 0x4a, 0x8f, 0x80, 0xc8, ++ 0xc0, 0xb2, 0xae, 0x5f, 0x93, 0x3e, 0x85, 0xaf, ++ 0x49, 0xbe, 0xac, 0x36, 0xc2, 0xfa, 0x73, 0x94, ++ 0xba, 0xb7, 0x6c, 0x89, 0x33, 0xf8, 0xf8, 0x1d }, ++ .expected_ss = (u8[32]){ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x63, 0xe5, 0xb1, 0xfe, 0x96, 0x01, 0xfe, 0x84, ++ 0x38, 0x5d, 0x88, 0x66, 0xb0, 0x42, 0x12, 0x62, ++ 0xf7, 0x8f, 0xbf, 0xa5, 0xaf, 0xf9, 0x58, 0x5e, ++ 0x62, 0x66, 0x79, 0xb1, 0x85, 0x47, 0xd9, 0x59 }, ++ .expected_ss = (u8[32]){ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0xe4, 0x28, 0xf3, 0xda, 0xc1, 0x78, 0x09, 0xf8, ++ 0x27, 0xa5, 0x22, 0xce, 0x32, 0x35, 0x50, 0x58, ++ 0xd0, 0x73, 0x69, 0x36, 0x4a, 0xa7, 0x89, 0x02, ++ 0xee, 0x10, 0x13, 0x9b, 0x9f, 0x9d, 0xd6, 0x53 }, ++ .expected_ss = (u8[32]){ 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0xb3, 0xb5, 0x0e, 0x3e, 0xd3, 0xa4, 0x07, 0xb9, ++ 0x5d, 0xe9, 0x42, 0xef, 0x74, 0x57, 0x5b, 0x5a, ++ 0xb8, 0xa1, 0x0c, 0x09, 0xee, 0x10, 0x35, 0x44, ++ 0xd6, 0x0b, 0xdf, 0xed, 0x81, 0x38, 0xab, 0x2b }, ++ .expected_ss = (u8[32]){ 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x21, 0x3f, 0xff, 0xe9, 0x3d, 0x5e, 0xa8, 0xcd, ++ 0x24, 0x2e, 0x46, 0x28, 0x44, 0x02, 0x99, 0x22, ++ 0xc4, 0x3c, 0x77, 0xc9, 0xe3, 0xe4, 0x2f, 0x56, ++ 0x2f, 0x48, 0x5d, 0x24, 0xc5, 0x01, 0xa2, 0x0b }, ++ .expected_ss = (u8[32]){ 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x91, 0xb2, 0x32, 0xa1, 0x78, 0xb3, 0xcd, 0x53, ++ 0x09, 0x32, 0x44, 0x1e, 0x61, 0x39, 0x41, 0x8f, ++ 0x72, 0x17, 0x22, 0x92, 0xf1, 0xda, 0x4c, 0x18, ++ 0x34, 0xfc, 0x5e, 0xbf, 0xef, 0xb5, 0x1e, 0x3f }, ++ .expected_ss = (u8[32]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x04, 0x5c, 0x6e, 0x11, 0xc5, 0xd3, 0x32, 0x55, ++ 0x6c, 0x78, 0x22, 0xfe, 0x94, 0xeb, 0xf8, 0x9b, ++ 0x56, 0xa3, 0x87, 0x8d, 0xc2, 0x7c, 0xa0, 0x79, ++ 0x10, 0x30, 0x58, 0x84, 0x9f, 0xab, 0xcb, 0x4f }, ++ .expected_ss = (u8[32]){ 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x1c, 0xa2, 0x19, 0x0b, 0x71, 0x16, 0x35, 0x39, ++ 0x06, 0x3c, 0x35, 0x77, 0x3b, 0xda, 0x0c, 0x9c, ++ 0x92, 0x8e, 0x91, 0x36, 0xf0, 0x62, 0x0a, 0xeb, ++ 0x09, 0x3f, 0x09, 0x91, 0x97, 0xb7, 0xf7, 0x4e }, ++ .expected_ss = (u8[32]){ 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0xf7, 0x6e, 0x90, 0x10, 0xac, 0x33, 0xc5, 0x04, ++ 0x3b, 0x2d, 0x3b, 0x76, 0xa8, 0x42, 0x17, 0x10, ++ 0x00, 0xc4, 0x91, 0x62, 0x22, 0xe9, 0xe8, 0x58, ++ 0x97, 0xa0, 0xae, 0xc7, 0xf6, 0x35, 0x0b, 0x3c }, ++ .expected_ss = (u8[32]){ 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0xbb, 0x72, 0x68, 0x8d, 0x8f, 0x8a, 0xa7, 0xa3, ++ 0x9c, 0xd6, 0x06, 0x0c, 0xd5, 0xc8, 0x09, 0x3c, ++ 0xde, 0xc6, 0xfe, 0x34, 0x19, 0x37, 0xc3, 0x88, ++ 0x6a, 0x99, 0x34, 0x6c, 0xd0, 0x7f, 0xaa, 0x55 }, ++ .expected_ss = (u8[32]){ 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x88, 0xfd, 0xde, 0xa1, 0x93, 0x39, 0x1c, 0x6a, ++ 0x59, 0x33, 0xef, 0x9b, 0x71, 0x90, 0x15, 0x49, ++ 0x44, 0x72, 0x05, 0xaa, 0xe9, 0xda, 0x92, 0x8a, ++ 0x6b, 0x91, 0xa3, 0x52, 0xba, 0x10, 0xf4, 0x1f }, ++ .expected_ss = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - edge case for shared secret */ ++{ ++ .secret = (u8[32]){ 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .b_public = (u8[32]){ 0x30, 0x3b, 0x39, 0x2f, 0x15, 0x31, 0x16, 0xca, ++ 0xd9, 0xcc, 0x68, 0x2a, 0x00, 0xcc, 0xc4, 0x4c, ++ 0x95, 0xff, 0x0d, 0x3b, 0xbe, 0x56, 0x8b, 0xeb, ++ 0x6c, 0x4e, 0x73, 0x9b, 0xaf, 0xdc, 0x2c, 0x68 }, ++ .expected_ss = (u8[32]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - checking for overflow */ ++{ ++ .secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .b_public = (u8[32]){ 0xfd, 0x30, 0x0a, 0xeb, 0x40, 0xe1, 0xfa, 0x58, ++ 0x25, 0x18, 0x41, 0x2b, 0x49, 0xb2, 0x08, 0xa7, ++ 0x84, 0x2b, 0x1e, 0x1f, 0x05, 0x6a, 0x04, 0x01, ++ 0x78, 0xea, 0x41, 0x41, 0x53, 0x4f, 0x65, 0x2d }, ++ .expected_ss = (u8[32]){ 0xb7, 0x34, 0x10, 0x5d, 0xc2, 0x57, 0x58, 0x5d, ++ 0x73, 0xb5, 0x66, 0xcc, 0xb7, 0x6f, 0x06, 0x27, ++ 0x95, 0xcc, 0xbe, 0xc8, 0x91, 0x28, 0xe5, 0x2b, ++ 0x02, 0xf3, 0xe5, 0x96, 0x39, 0xf1, 0x3c, 0x46 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - checking for overflow */ ++{ ++ .secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .b_public = (u8[32]){ 0xc8, 0xef, 0x79, 0xb5, 0x14, 0xd7, 0x68, 0x26, ++ 0x77, 0xbc, 0x79, 0x31, 0xe0, 0x6e, 0xe5, 0xc2, ++ 0x7c, 0x9b, 0x39, 0x2b, 0x4a, 0xe9, 0x48, 0x44, ++ 0x73, 0xf5, 0x54, 0xe6, 0x67, 0x8e, 0xcc, 0x2e }, ++ .expected_ss = (u8[32]){ 0x64, 0x7a, 0x46, 0xb6, 0xfc, 0x3f, 0x40, 0xd6, ++ 0x21, 0x41, 0xee, 0x3c, 0xee, 0x70, 0x6b, 0x4d, ++ 0x7a, 0x92, 0x71, 0x59, 0x3a, 0x7b, 0x14, 0x3e, ++ 0x8e, 0x2e, 0x22, 0x79, 0x88, 0x3e, 0x45, 0x50 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - checking for overflow */ ++{ ++ .secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .b_public = (u8[32]){ 0x64, 0xae, 0xac, 0x25, 0x04, 0x14, 0x48, 0x61, ++ 0x53, 0x2b, 0x7b, 0xbc, 0xb6, 0xc8, 0x7d, 0x67, ++ 0xdd, 0x4c, 0x1f, 0x07, 0xeb, 0xc2, 0xe0, 0x6e, ++ 0xff, 0xb9, 0x5a, 0xec, 0xc6, 0x17, 0x0b, 0x2c }, ++ .expected_ss = (u8[32]){ 0x4f, 0xf0, 0x3d, 0x5f, 0xb4, 0x3c, 0xd8, 0x65, ++ 0x7a, 0x3c, 0xf3, 0x7c, 0x13, 0x8c, 0xad, 0xce, ++ 0xcc, 0xe5, 0x09, 0xe4, 0xeb, 0xa0, 0x89, 0xd0, ++ 0xef, 0x40, 0xb4, 0xe4, 0xfb, 0x94, 0x61, 0x55 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - checking for overflow */ ++{ ++ .secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .b_public = (u8[32]){ 0xbf, 0x68, 0xe3, 0x5e, 0x9b, 0xdb, 0x7e, 0xee, ++ 0x1b, 0x50, 0x57, 0x02, 0x21, 0x86, 0x0f, 0x5d, ++ 0xcd, 0xad, 0x8a, 0xcb, 0xab, 0x03, 0x1b, 0x14, ++ 0x97, 0x4c, 0xc4, 0x90, 0x13, 0xc4, 0x98, 0x31 }, ++ .expected_ss = (u8[32]){ 0x21, 0xce, 0xe5, 0x2e, 0xfd, 0xbc, 0x81, 0x2e, ++ 0x1d, 0x02, 0x1a, 0x4a, 0xf1, 0xe1, 0xd8, 0xbc, ++ 0x4d, 0xb3, 0xc4, 0x00, 0xe4, 0xd2, 0xa2, 0xc5, ++ 0x6a, 0x39, 0x26, 0xdb, 0x4d, 0x99, 0xc6, 0x5b }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - checking for overflow */ ++{ ++ .secret = (u8[32]){ 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .b_public = (u8[32]){ 0x53, 0x47, 0xc4, 0x91, 0x33, 0x1a, 0x64, 0xb4, ++ 0x3d, 0xdc, 0x68, 0x30, 0x34, 0xe6, 0x77, 0xf5, ++ 0x3d, 0xc3, 0x2b, 0x52, 0xa5, 0x2a, 0x57, 0x7c, ++ 0x15, 0xa8, 0x3b, 0xf2, 0x98, 0xe9, 0x9f, 0x19 }, ++ .expected_ss = (u8[32]){ 0x18, 0xcb, 0x89, 0xe4, 0xe2, 0x0c, 0x0c, 0x2b, ++ 0xd3, 0x24, 0x30, 0x52, 0x45, 0x26, 0x6c, 0x93, ++ 0x27, 0x69, 0x0b, 0xbe, 0x79, 0xac, 0xb8, 0x8f, ++ 0x5b, 0x8f, 0xb3, 0xf7, 0x4e, 0xca, 0x3e, 0x52 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - private key == -1 (mod order) */ ++{ ++ .secret = (u8[32]){ 0xa0, 0x23, 0xcd, 0xd0, 0x83, 0xef, 0x5b, 0xb8, ++ 0x2f, 0x10, 0xd6, 0x2e, 0x59, 0xe1, 0x5a, 0x68, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50 }, ++ .b_public = (u8[32]){ 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e, ++ 0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57, ++ 0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f, ++ 0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 }, ++ .expected_ss = (u8[32]){ 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e, ++ 0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57, ++ 0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f, ++ 0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++}, ++/* wycheproof - private key == 1 (mod order) on twist */ ++{ ++ .secret = (u8[32]){ 0x58, 0x08, 0x3d, 0xd2, 0x61, 0xad, 0x91, 0xef, ++ 0xf9, 0x52, 0x32, 0x2e, 0xc8, 0x24, 0xc6, 0x82, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f }, ++ .b_public = (u8[32]){ 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f, ++ 0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6, ++ 0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64, ++ 0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 }, ++ .expected_ss = (u8[32]){ 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f, ++ 0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6, ++ 0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64, ++ 0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 }, ++ .secret_size = 32, ++ .b_public_size = 32, ++ .expected_ss_size = 32, ++ ++} ++}; ++ + static const struct kpp_testvec ecdh_tv_template[] = { + { + #ifndef CONFIG_CRYPTO_FIPS diff --git a/ipq806x/backport-5.4/080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch b/ipq806x/backport-5.4/080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch new file mode 100644 index 0000000..d909561 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0027-crypto-curve25519-implement-generic-KPP-driver.patch @@ -0,0 +1,136 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:34 +0100 +Subject: [PATCH] crypto: curve25519 - implement generic KPP driver + +commit ee772cb641135739c1530647391d5a04c39db192 upstream. + +Expose the generic Curve25519 library via the crypto API KPP interface. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/Kconfig | 5 +++ + crypto/Makefile | 1 + + crypto/curve25519-generic.c | 90 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 96 insertions(+) + create mode 100644 crypto/curve25519-generic.c + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -264,6 +264,11 @@ config CRYPTO_ECRDSA + standard algorithms (called GOST algorithms). Only signature verification + is implemented. + ++config CRYPTO_CURVE25519 ++ tristate "Curve25519 algorithm" ++ select CRYPTO_KPP ++ select CRYPTO_LIB_CURVE25519_GENERIC ++ + comment "Authenticated Encryption with Associated Data" + + config CRYPTO_CCM +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -167,6 +167,7 @@ obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o + obj-$(CONFIG_CRYPTO_OFB) += ofb.o + obj-$(CONFIG_CRYPTO_ECC) += ecc.o + obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o ++obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o + + ecdh_generic-y += ecdh.o + ecdh_generic-y += ecdh_helper.o +--- /dev/null ++++ b/crypto/curve25519-generic.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf, ++ unsigned int len) ++{ ++ u8 *secret = kpp_tfm_ctx(tfm); ++ ++ if (!len) ++ curve25519_generate_secret(secret); ++ else if (len == CURVE25519_KEY_SIZE && ++ crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE)) ++ memcpy(secret, buf, CURVE25519_KEY_SIZE); ++ else ++ return -EINVAL; ++ return 0; ++} ++ ++static int curve25519_compute_value(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ const u8 *secret = kpp_tfm_ctx(tfm); ++ u8 public_key[CURVE25519_KEY_SIZE]; ++ u8 buf[CURVE25519_KEY_SIZE]; ++ int copied, nbytes; ++ u8 const *bp; ++ ++ if (req->src) { ++ copied = sg_copy_to_buffer(req->src, ++ sg_nents_for_len(req->src, ++ CURVE25519_KEY_SIZE), ++ public_key, CURVE25519_KEY_SIZE); ++ if (copied != CURVE25519_KEY_SIZE) ++ return -EINVAL; ++ bp = public_key; ++ } else { ++ bp = curve25519_base_point; ++ } ++ ++ curve25519_generic(buf, secret, bp); ++ ++ /* might want less than we've got */ ++ nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len); ++ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, ++ nbytes), ++ buf, nbytes); ++ if (copied != nbytes) ++ return -EINVAL; ++ return 0; ++} ++ ++static unsigned int curve25519_max_size(struct crypto_kpp *tfm) ++{ ++ return CURVE25519_KEY_SIZE; ++} ++ ++static struct kpp_alg curve25519_alg = { ++ .base.cra_name = "curve25519", ++ .base.cra_driver_name = "curve25519-generic", ++ .base.cra_priority = 100, ++ .base.cra_module = THIS_MODULE, ++ .base.cra_ctxsize = CURVE25519_KEY_SIZE, ++ ++ .set_secret = curve25519_set_secret, ++ .generate_public_key = curve25519_compute_value, ++ .compute_shared_secret = curve25519_compute_value, ++ .max_size = curve25519_max_size, ++}; ++ ++static int curve25519_init(void) ++{ ++ return crypto_register_kpp(&curve25519_alg); ++} ++ ++static void curve25519_exit(void) ++{ ++ crypto_unregister_kpp(&curve25519_alg); ++} ++ ++subsys_initcall(curve25519_init); ++module_exit(curve25519_exit); ++ ++MODULE_ALIAS_CRYPTO("curve25519"); ++MODULE_ALIAS_CRYPTO("curve25519-generic"); ++MODULE_LICENSE("GPL"); diff --git a/ipq806x/backport-5.4/080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch b/ipq806x/backport-5.4/080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch new file mode 100644 index 0000000..36b59c9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0028-crypto-lib-curve25519-work-around-Clang-stack-spilli.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:35 +0100 +Subject: [PATCH] crypto: lib/curve25519 - work around Clang stack spilling + issue + +commit 660bb8e1f833ea63185fe80fde847e3e42f18e3b upstream. + +Arnd reports that the 32-bit generic library code for Curve25119 ends +up using an excessive amount of stack space when built with Clang: + + lib/crypto/curve25519-fiat32.c:756:6: error: stack frame size + of 1384 bytes in function 'curve25519_generic' + [-Werror,-Wframe-larger-than=] + +Let's give some hints to the compiler regarding which routines should +not be inlined, to prevent it from running out of registers and spilling +to the stack. The resulting code performs identically under both GCC +and Clang, and makes the warning go away. + +Suggested-by: Arnd Bergmann +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + lib/crypto/curve25519-fiat32.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/lib/crypto/curve25519-fiat32.c ++++ b/lib/crypto/curve25519-fiat32.c +@@ -223,7 +223,7 @@ static __always_inline void fe_1(fe *h) + h->v[0] = 1; + } + +-static void fe_add_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) ++static noinline void fe_add_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) + { + { const u32 x20 = in1[9]; + { const u32 x21 = in1[8]; +@@ -266,7 +266,7 @@ static __always_inline void fe_add(fe_lo + fe_add_impl(h->v, f->v, g->v); + } + +-static void fe_sub_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) ++static noinline void fe_sub_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) + { + { const u32 x20 = in1[9]; + { const u32 x21 = in1[8]; +@@ -309,7 +309,7 @@ static __always_inline void fe_sub(fe_lo + fe_sub_impl(h->v, f->v, g->v); + } + +-static void fe_mul_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) ++static noinline void fe_mul_impl(u32 out[10], const u32 in1[10], const u32 in2[10]) + { + { const u32 x20 = in1[9]; + { const u32 x21 = in1[8]; +@@ -441,7 +441,7 @@ fe_mul_tll(fe *h, const fe_loose *f, con + fe_mul_impl(h->v, f->v, g->v); + } + +-static void fe_sqr_impl(u32 out[10], const u32 in1[10]) ++static noinline void fe_sqr_impl(u32 out[10], const u32 in1[10]) + { + { const u32 x17 = in1[9]; + { const u32 x18 = in1[8]; +@@ -619,7 +619,7 @@ static __always_inline void fe_invert(fe + * + * Preconditions: b in {0,1} + */ +-static __always_inline void fe_cswap(fe *f, fe *g, unsigned int b) ++static noinline void fe_cswap(fe *f, fe *g, unsigned int b) + { + unsigned i; + b = 0 - b; diff --git a/ipq806x/backport-5.4/080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch b/ipq806x/backport-5.4/080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch new file mode 100644 index 0000000..49fd970 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0029-crypto-curve25519-x86_64-library-and-KPP-implementat.patch @@ -0,0 +1,2536 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 8 Nov 2019 13:22:36 +0100 +Subject: [PATCH] crypto: curve25519 - x86_64 library and KPP implementations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit bb611bdfd6be34d9f822c73305fcc83720499d38 upstream. + +This implementation is the fastest available x86_64 implementation, and +unlike Sandy2x, it doesn't requie use of the floating point registers at +all. Instead it makes use of BMI2 and ADX, available on recent +microarchitectures. The implementation was written by Armando +Faz-Hernández with contributions (upstream) from Samuel Neves and me, +in addition to further changes in the kernel implementation from us. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Samuel Neves +Co-developed-by: Samuel Neves +[ardb: - move to arch/x86/crypto + - wire into lib/crypto framework + - implement crypto API KPP hooks ] +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/Makefile | 1 + + arch/x86/crypto/curve25519-x86_64.c | 2475 +++++++++++++++++++++++++++ + crypto/Kconfig | 6 + + 3 files changed, 2482 insertions(+) + create mode 100644 arch/x86/crypto/curve25519-x86_64.c + +--- a/arch/x86/crypto/Makefile ++++ b/arch/x86/crypto/Makefile +@@ -39,6 +39,7 @@ obj-$(CONFIG_CRYPTO_AEGIS128_AESNI_SSE2) + + obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o + obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o ++obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o + + # These modules require assembler to support AVX. + ifeq ($(avx_supported),yes) +--- /dev/null ++++ b/arch/x86/crypto/curve25519-x86_64.c +@@ -0,0 +1,2475 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* ++ * Copyright (c) 2017 Armando Faz . All Rights Reserved. ++ * Copyright (C) 2018-2019 Jason A. Donenfeld . All Rights Reserved. ++ * Copyright (C) 2018 Samuel Neves . All Rights Reserved. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_bmi2); ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_adx); ++ ++enum { NUM_WORDS_ELTFP25519 = 4 }; ++typedef __aligned(32) u64 eltfp25519_1w[NUM_WORDS_ELTFP25519]; ++typedef __aligned(32) u64 eltfp25519_1w_buffer[2 * NUM_WORDS_ELTFP25519]; ++ ++#define mul_eltfp25519_1w_adx(c, a, b) do { \ ++ mul_256x256_integer_adx(m.buffer, a, b); \ ++ red_eltfp25519_1w_adx(c, m.buffer); \ ++} while (0) ++ ++#define mul_eltfp25519_1w_bmi2(c, a, b) do { \ ++ mul_256x256_integer_bmi2(m.buffer, a, b); \ ++ red_eltfp25519_1w_bmi2(c, m.buffer); \ ++} while (0) ++ ++#define sqr_eltfp25519_1w_adx(a) do { \ ++ sqr_256x256_integer_adx(m.buffer, a); \ ++ red_eltfp25519_1w_adx(a, m.buffer); \ ++} while (0) ++ ++#define sqr_eltfp25519_1w_bmi2(a) do { \ ++ sqr_256x256_integer_bmi2(m.buffer, a); \ ++ red_eltfp25519_1w_bmi2(a, m.buffer); \ ++} while (0) ++ ++#define mul_eltfp25519_2w_adx(c, a, b) do { \ ++ mul2_256x256_integer_adx(m.buffer, a, b); \ ++ red_eltfp25519_2w_adx(c, m.buffer); \ ++} while (0) ++ ++#define mul_eltfp25519_2w_bmi2(c, a, b) do { \ ++ mul2_256x256_integer_bmi2(m.buffer, a, b); \ ++ red_eltfp25519_2w_bmi2(c, m.buffer); \ ++} while (0) ++ ++#define sqr_eltfp25519_2w_adx(a) do { \ ++ sqr2_256x256_integer_adx(m.buffer, a); \ ++ red_eltfp25519_2w_adx(a, m.buffer); \ ++} while (0) ++ ++#define sqr_eltfp25519_2w_bmi2(a) do { \ ++ sqr2_256x256_integer_bmi2(m.buffer, a); \ ++ red_eltfp25519_2w_bmi2(a, m.buffer); \ ++} while (0) ++ ++#define sqrn_eltfp25519_1w_adx(a, times) do { \ ++ int ____counter = (times); \ ++ while (____counter-- > 0) \ ++ sqr_eltfp25519_1w_adx(a); \ ++} while (0) ++ ++#define sqrn_eltfp25519_1w_bmi2(a, times) do { \ ++ int ____counter = (times); \ ++ while (____counter-- > 0) \ ++ sqr_eltfp25519_1w_bmi2(a); \ ++} while (0) ++ ++#define copy_eltfp25519_1w(C, A) do { \ ++ (C)[0] = (A)[0]; \ ++ (C)[1] = (A)[1]; \ ++ (C)[2] = (A)[2]; \ ++ (C)[3] = (A)[3]; \ ++} while (0) ++ ++#define setzero_eltfp25519_1w(C) do { \ ++ (C)[0] = 0; \ ++ (C)[1] = 0; \ ++ (C)[2] = 0; \ ++ (C)[3] = 0; \ ++} while (0) ++ ++__aligned(32) static const u64 table_ladder_8k[252 * NUM_WORDS_ELTFP25519] = { ++ /* 1 */ 0xfffffffffffffff3UL, 0xffffffffffffffffUL, ++ 0xffffffffffffffffUL, 0x5fffffffffffffffUL, ++ /* 2 */ 0x6b8220f416aafe96UL, 0x82ebeb2b4f566a34UL, ++ 0xd5a9a5b075a5950fUL, 0x5142b2cf4b2488f4UL, ++ /* 3 */ 0x6aaebc750069680cUL, 0x89cf7820a0f99c41UL, ++ 0x2a58d9183b56d0f4UL, 0x4b5aca80e36011a4UL, ++ /* 4 */ 0x329132348c29745dUL, 0xf4a2e616e1642fd7UL, ++ 0x1e45bb03ff67bc34UL, 0x306912d0f42a9b4aUL, ++ /* 5 */ 0xff886507e6af7154UL, 0x04f50e13dfeec82fUL, ++ 0xaa512fe82abab5ceUL, 0x174e251a68d5f222UL, ++ /* 6 */ 0xcf96700d82028898UL, 0x1743e3370a2c02c5UL, ++ 0x379eec98b4e86eaaUL, 0x0c59888a51e0482eUL, ++ /* 7 */ 0xfbcbf1d699b5d189UL, 0xacaef0d58e9fdc84UL, ++ 0xc1c20d06231f7614UL, 0x2938218da274f972UL, ++ /* 8 */ 0xf6af49beff1d7f18UL, 0xcc541c22387ac9c2UL, ++ 0x96fcc9ef4015c56bUL, 0x69c1627c690913a9UL, ++ /* 9 */ 0x7a86fd2f4733db0eUL, 0xfdb8c4f29e087de9UL, ++ 0x095e4b1a8ea2a229UL, 0x1ad7a7c829b37a79UL, ++ /* 10 */ 0x342d89cad17ea0c0UL, 0x67bedda6cced2051UL, ++ 0x19ca31bf2bb42f74UL, 0x3df7b4c84980acbbUL, ++ /* 11 */ 0xa8c6444dc80ad883UL, 0xb91e440366e3ab85UL, ++ 0xc215cda00164f6d8UL, 0x3d867c6ef247e668UL, ++ /* 12 */ 0xc7dd582bcc3e658cUL, 0xfd2c4748ee0e5528UL, ++ 0xa0fd9b95cc9f4f71UL, 0x7529d871b0675ddfUL, ++ /* 13 */ 0xb8f568b42d3cbd78UL, 0x1233011b91f3da82UL, ++ 0x2dce6ccd4a7c3b62UL, 0x75e7fc8e9e498603UL, ++ /* 14 */ 0x2f4f13f1fcd0b6ecUL, 0xf1a8ca1f29ff7a45UL, ++ 0xc249c1a72981e29bUL, 0x6ebe0dbb8c83b56aUL, ++ /* 15 */ 0x7114fa8d170bb222UL, 0x65a2dcd5bf93935fUL, ++ 0xbdc41f68b59c979aUL, 0x2f0eef79a2ce9289UL, ++ /* 16 */ 0x42ecbf0c083c37ceUL, 0x2930bc09ec496322UL, ++ 0xf294b0c19cfeac0dUL, 0x3780aa4bedfabb80UL, ++ /* 17 */ 0x56c17d3e7cead929UL, 0xe7cb4beb2e5722c5UL, ++ 0x0ce931732dbfe15aUL, 0x41b883c7621052f8UL, ++ /* 18 */ 0xdbf75ca0c3d25350UL, 0x2936be086eb1e351UL, ++ 0xc936e03cb4a9b212UL, 0x1d45bf82322225aaUL, ++ /* 19 */ 0xe81ab1036a024cc5UL, 0xe212201c304c9a72UL, ++ 0xc5d73fba6832b1fcUL, 0x20ffdb5a4d839581UL, ++ /* 20 */ 0xa283d367be5d0fadUL, 0x6c2b25ca8b164475UL, ++ 0x9d4935467caaf22eUL, 0x5166408eee85ff49UL, ++ /* 21 */ 0x3c67baa2fab4e361UL, 0xb3e433c67ef35cefUL, ++ 0x5259729241159b1cUL, 0x6a621892d5b0ab33UL, ++ /* 22 */ 0x20b74a387555cdcbUL, 0x532aa10e1208923fUL, ++ 0xeaa17b7762281dd1UL, 0x61ab3443f05c44bfUL, ++ /* 23 */ 0x257a6c422324def8UL, 0x131c6c1017e3cf7fUL, ++ 0x23758739f630a257UL, 0x295a407a01a78580UL, ++ /* 24 */ 0xf8c443246d5da8d9UL, 0x19d775450c52fa5dUL, ++ 0x2afcfc92731bf83dUL, 0x7d10c8e81b2b4700UL, ++ /* 25 */ 0xc8e0271f70baa20bUL, 0x993748867ca63957UL, ++ 0x5412efb3cb7ed4bbUL, 0x3196d36173e62975UL, ++ /* 26 */ 0xde5bcad141c7dffcUL, 0x47cc8cd2b395c848UL, ++ 0xa34cd942e11af3cbUL, 0x0256dbf2d04ecec2UL, ++ /* 27 */ 0x875ab7e94b0e667fUL, 0xcad4dd83c0850d10UL, ++ 0x47f12e8f4e72c79fUL, 0x5f1a87bb8c85b19bUL, ++ /* 28 */ 0x7ae9d0b6437f51b8UL, 0x12c7ce5518879065UL, ++ 0x2ade09fe5cf77aeeUL, 0x23a05a2f7d2c5627UL, ++ /* 29 */ 0x5908e128f17c169aUL, 0xf77498dd8ad0852dUL, ++ 0x74b4c4ceab102f64UL, 0x183abadd10139845UL, ++ /* 30 */ 0xb165ba8daa92aaacUL, 0xd5c5ef9599386705UL, ++ 0xbe2f8f0cf8fc40d1UL, 0x2701e635ee204514UL, ++ /* 31 */ 0x629fa80020156514UL, 0xf223868764a8c1ceUL, ++ 0x5b894fff0b3f060eUL, 0x60d9944cf708a3faUL, ++ /* 32 */ 0xaeea001a1c7a201fUL, 0xebf16a633ee2ce63UL, ++ 0x6f7709594c7a07e1UL, 0x79b958150d0208cbUL, ++ /* 33 */ 0x24b55e5301d410e7UL, 0xe3a34edff3fdc84dUL, ++ 0xd88768e4904032d8UL, 0x131384427b3aaeecUL, ++ /* 34 */ 0x8405e51286234f14UL, 0x14dc4739adb4c529UL, ++ 0xb8a2b5b250634ffdUL, 0x2fe2a94ad8a7ff93UL, ++ /* 35 */ 0xec5c57efe843faddUL, 0x2843ce40f0bb9918UL, ++ 0xa4b561d6cf3d6305UL, 0x743629bde8fb777eUL, ++ /* 36 */ 0x343edd46bbaf738fUL, 0xed981828b101a651UL, ++ 0xa401760b882c797aUL, 0x1fc223e28dc88730UL, ++ /* 37 */ 0x48604e91fc0fba0eUL, 0xb637f78f052c6fa4UL, ++ 0x91ccac3d09e9239cUL, 0x23f7eed4437a687cUL, ++ /* 38 */ 0x5173b1118d9bd800UL, 0x29d641b63189d4a7UL, ++ 0xfdbf177988bbc586UL, 0x2959894fcad81df5UL, ++ /* 39 */ 0xaebc8ef3b4bbc899UL, 0x4148995ab26992b9UL, ++ 0x24e20b0134f92cfbUL, 0x40d158894a05dee8UL, ++ /* 40 */ 0x46b00b1185af76f6UL, 0x26bac77873187a79UL, ++ 0x3dc0bf95ab8fff5fUL, 0x2a608bd8945524d7UL, ++ /* 41 */ 0x26449588bd446302UL, 0x7c4bc21c0388439cUL, ++ 0x8e98a4f383bd11b2UL, 0x26218d7bc9d876b9UL, ++ /* 42 */ 0xe3081542997c178aUL, 0x3c2d29a86fb6606fUL, ++ 0x5c217736fa279374UL, 0x7dde05734afeb1faUL, ++ /* 43 */ 0x3bf10e3906d42babUL, 0xe4f7803e1980649cUL, ++ 0xe6053bf89595bf7aUL, 0x394faf38da245530UL, ++ /* 44 */ 0x7a8efb58896928f4UL, 0xfbc778e9cc6a113cUL, ++ 0x72670ce330af596fUL, 0x48f222a81d3d6cf7UL, ++ /* 45 */ 0xf01fce410d72caa7UL, 0x5a20ecc7213b5595UL, ++ 0x7bc21165c1fa1483UL, 0x07f89ae31da8a741UL, ++ /* 46 */ 0x05d2c2b4c6830ff9UL, 0xd43e330fc6316293UL, ++ 0xa5a5590a96d3a904UL, 0x705edb91a65333b6UL, ++ /* 47 */ 0x048ee15e0bb9a5f7UL, 0x3240cfca9e0aaf5dUL, ++ 0x8f4b71ceedc4a40bUL, 0x621c0da3de544a6dUL, ++ /* 48 */ 0x92872836a08c4091UL, 0xce8375b010c91445UL, ++ 0x8a72eb524f276394UL, 0x2667fcfa7ec83635UL, ++ /* 49 */ 0x7f4c173345e8752aUL, 0x061b47feee7079a5UL, ++ 0x25dd9afa9f86ff34UL, 0x3780cef5425dc89cUL, ++ /* 50 */ 0x1a46035a513bb4e9UL, 0x3e1ef379ac575adaUL, ++ 0xc78c5f1c5fa24b50UL, 0x321a967634fd9f22UL, ++ /* 51 */ 0x946707b8826e27faUL, 0x3dca84d64c506fd0UL, ++ 0xc189218075e91436UL, 0x6d9284169b3b8484UL, ++ /* 52 */ 0x3a67e840383f2ddfUL, 0x33eec9a30c4f9b75UL, ++ 0x3ec7c86fa783ef47UL, 0x26ec449fbac9fbc4UL, ++ /* 53 */ 0x5c0f38cba09b9e7dUL, 0x81168cc762a3478cUL, ++ 0x3e23b0d306fc121cUL, 0x5a238aa0a5efdcddUL, ++ /* 54 */ 0x1ba26121c4ea43ffUL, 0x36f8c77f7c8832b5UL, ++ 0x88fbea0b0adcf99aUL, 0x5ca9938ec25bebf9UL, ++ /* 55 */ 0xd5436a5e51fccda0UL, 0x1dbc4797c2cd893bUL, ++ 0x19346a65d3224a08UL, 0x0f5034e49b9af466UL, ++ /* 56 */ 0xf23c3967a1e0b96eUL, 0xe58b08fa867a4d88UL, ++ 0xfb2fabc6a7341679UL, 0x2a75381eb6026946UL, ++ /* 57 */ 0xc80a3be4c19420acUL, 0x66b1f6c681f2b6dcUL, ++ 0x7cf7036761e93388UL, 0x25abbbd8a660a4c4UL, ++ /* 58 */ 0x91ea12ba14fd5198UL, 0x684950fc4a3cffa9UL, ++ 0xf826842130f5ad28UL, 0x3ea988f75301a441UL, ++ /* 59 */ 0xc978109a695f8c6fUL, 0x1746eb4a0530c3f3UL, ++ 0x444d6d77b4459995UL, 0x75952b8c054e5cc7UL, ++ /* 60 */ 0xa3703f7915f4d6aaUL, 0x66c346202f2647d8UL, ++ 0xd01469df811d644bUL, 0x77fea47d81a5d71fUL, ++ /* 61 */ 0xc5e9529ef57ca381UL, 0x6eeeb4b9ce2f881aUL, ++ 0xb6e91a28e8009bd6UL, 0x4b80be3e9afc3fecUL, ++ /* 62 */ 0x7e3773c526aed2c5UL, 0x1b4afcb453c9a49dUL, ++ 0xa920bdd7baffb24dUL, 0x7c54699f122d400eUL, ++ /* 63 */ 0xef46c8e14fa94bc8UL, 0xe0b074ce2952ed5eUL, ++ 0xbea450e1dbd885d5UL, 0x61b68649320f712cUL, ++ /* 64 */ 0x8a485f7309ccbdd1UL, 0xbd06320d7d4d1a2dUL, ++ 0x25232973322dbef4UL, 0x445dc4758c17f770UL, ++ /* 65 */ 0xdb0434177cc8933cUL, 0xed6fe82175ea059fUL, ++ 0x1efebefdc053db34UL, 0x4adbe867c65daf99UL, ++ /* 66 */ 0x3acd71a2a90609dfUL, 0xe5e991856dd04050UL, ++ 0x1ec69b688157c23cUL, 0x697427f6885cfe4dUL, ++ /* 67 */ 0xd7be7b9b65e1a851UL, 0xa03d28d522c536ddUL, ++ 0x28399d658fd2b645UL, 0x49e5b7e17c2641e1UL, ++ /* 68 */ 0x6f8c3a98700457a4UL, 0x5078f0a25ebb6778UL, ++ 0xd13c3ccbc382960fUL, 0x2e003258a7df84b1UL, ++ /* 69 */ 0x8ad1f39be6296a1cUL, 0xc1eeaa652a5fbfb2UL, ++ 0x33ee0673fd26f3cbUL, 0x59256173a69d2cccUL, ++ /* 70 */ 0x41ea07aa4e18fc41UL, 0xd9fc19527c87a51eUL, ++ 0xbdaacb805831ca6fUL, 0x445b652dc916694fUL, ++ /* 71 */ 0xce92a3a7f2172315UL, 0x1edc282de11b9964UL, ++ 0xa1823aafe04c314aUL, 0x790a2d94437cf586UL, ++ /* 72 */ 0x71c447fb93f6e009UL, 0x8922a56722845276UL, ++ 0xbf70903b204f5169UL, 0x2f7a89891ba319feUL, ++ /* 73 */ 0x02a08eb577e2140cUL, 0xed9a4ed4427bdcf4UL, ++ 0x5253ec44e4323cd1UL, 0x3e88363c14e9355bUL, ++ /* 74 */ 0xaa66c14277110b8cUL, 0x1ae0391610a23390UL, ++ 0x2030bd12c93fc2a2UL, 0x3ee141579555c7abUL, ++ /* 75 */ 0x9214de3a6d6e7d41UL, 0x3ccdd88607f17efeUL, ++ 0x674f1288f8e11217UL, 0x5682250f329f93d0UL, ++ /* 76 */ 0x6cf00b136d2e396eUL, 0x6e4cf86f1014debfUL, ++ 0x5930b1b5bfcc4e83UL, 0x047069b48aba16b6UL, ++ /* 77 */ 0x0d4ce4ab69b20793UL, 0xb24db91a97d0fb9eUL, ++ 0xcdfa50f54e00d01dUL, 0x221b1085368bddb5UL, ++ /* 78 */ 0xe7e59468b1e3d8d2UL, 0x53c56563bd122f93UL, ++ 0xeee8a903e0663f09UL, 0x61efa662cbbe3d42UL, ++ /* 79 */ 0x2cf8ddddde6eab2aUL, 0x9bf80ad51435f231UL, ++ 0x5deadacec9f04973UL, 0x29275b5d41d29b27UL, ++ /* 80 */ 0xcfde0f0895ebf14fUL, 0xb9aab96b054905a7UL, ++ 0xcae80dd9a1c420fdUL, 0x0a63bf2f1673bbc7UL, ++ /* 81 */ 0x092f6e11958fbc8cUL, 0x672a81e804822fadUL, ++ 0xcac8351560d52517UL, 0x6f3f7722c8f192f8UL, ++ /* 82 */ 0xf8ba90ccc2e894b7UL, 0x2c7557a438ff9f0dUL, ++ 0x894d1d855ae52359UL, 0x68e122157b743d69UL, ++ /* 83 */ 0xd87e5570cfb919f3UL, 0x3f2cdecd95798db9UL, ++ 0x2121154710c0a2ceUL, 0x3c66a115246dc5b2UL, ++ /* 84 */ 0xcbedc562294ecb72UL, 0xba7143c36a280b16UL, ++ 0x9610c2efd4078b67UL, 0x6144735d946a4b1eUL, ++ /* 85 */ 0x536f111ed75b3350UL, 0x0211db8c2041d81bUL, ++ 0xf93cb1000e10413cUL, 0x149dfd3c039e8876UL, ++ /* 86 */ 0xd479dde46b63155bUL, 0xb66e15e93c837976UL, ++ 0xdafde43b1f13e038UL, 0x5fafda1a2e4b0b35UL, ++ /* 87 */ 0x3600bbdf17197581UL, 0x3972050bbe3cd2c2UL, ++ 0x5938906dbdd5be86UL, 0x34fce5e43f9b860fUL, ++ /* 88 */ 0x75a8a4cd42d14d02UL, 0x828dabc53441df65UL, ++ 0x33dcabedd2e131d3UL, 0x3ebad76fb814d25fUL, ++ /* 89 */ 0xd4906f566f70e10fUL, 0x5d12f7aa51690f5aUL, ++ 0x45adb16e76cefcf2UL, 0x01f768aead232999UL, ++ /* 90 */ 0x2b6cc77b6248febdUL, 0x3cd30628ec3aaffdUL, ++ 0xce1c0b80d4ef486aUL, 0x4c3bff2ea6f66c23UL, ++ /* 91 */ 0x3f2ec4094aeaeb5fUL, 0x61b19b286e372ca7UL, ++ 0x5eefa966de2a701dUL, 0x23b20565de55e3efUL, ++ /* 92 */ 0xe301ca5279d58557UL, 0x07b2d4ce27c2874fUL, ++ 0xa532cd8a9dcf1d67UL, 0x2a52fee23f2bff56UL, ++ /* 93 */ 0x8624efb37cd8663dUL, 0xbbc7ac20ffbd7594UL, ++ 0x57b85e9c82d37445UL, 0x7b3052cb86a6ec66UL, ++ /* 94 */ 0x3482f0ad2525e91eUL, 0x2cb68043d28edca0UL, ++ 0xaf4f6d052e1b003aUL, 0x185f8c2529781b0aUL, ++ /* 95 */ 0xaa41de5bd80ce0d6UL, 0x9407b2416853e9d6UL, ++ 0x563ec36e357f4c3aUL, 0x4cc4b8dd0e297bceUL, ++ /* 96 */ 0xa2fc1a52ffb8730eUL, 0x1811f16e67058e37UL, ++ 0x10f9a366cddf4ee1UL, 0x72f4a0c4a0b9f099UL, ++ /* 97 */ 0x8c16c06f663f4ea7UL, 0x693b3af74e970fbaUL, ++ 0x2102e7f1d69ec345UL, 0x0ba53cbc968a8089UL, ++ /* 98 */ 0xca3d9dc7fea15537UL, 0x4c6824bb51536493UL, ++ 0xb9886314844006b1UL, 0x40d2a72ab454cc60UL, ++ /* 99 */ 0x5936a1b712570975UL, 0x91b9d648debda657UL, ++ 0x3344094bb64330eaUL, 0x006ba10d12ee51d0UL, ++ /* 100 */ 0x19228468f5de5d58UL, 0x0eb12f4c38cc05b0UL, ++ 0xa1039f9dd5601990UL, 0x4502d4ce4fff0e0bUL, ++ /* 101 */ 0xeb2054106837c189UL, 0xd0f6544c6dd3b93cUL, ++ 0x40727064c416d74fUL, 0x6e15c6114b502ef0UL, ++ /* 102 */ 0x4df2a398cfb1a76bUL, 0x11256c7419f2f6b1UL, ++ 0x4a497962066e6043UL, 0x705b3aab41355b44UL, ++ /* 103 */ 0x365ef536d797b1d8UL, 0x00076bd622ddf0dbUL, ++ 0x3bbf33b0e0575a88UL, 0x3777aa05c8e4ca4dUL, ++ /* 104 */ 0x392745c85578db5fUL, 0x6fda4149dbae5ae2UL, ++ 0xb1f0b00b8adc9867UL, 0x09963437d36f1da3UL, ++ /* 105 */ 0x7e824e90a5dc3853UL, 0xccb5f6641f135cbdUL, ++ 0x6736d86c87ce8fccUL, 0x625f3ce26604249fUL, ++ /* 106 */ 0xaf8ac8059502f63fUL, 0x0c05e70a2e351469UL, ++ 0x35292e9c764b6305UL, 0x1a394360c7e23ac3UL, ++ /* 107 */ 0xd5c6d53251183264UL, 0x62065abd43c2b74fUL, ++ 0xb5fbf5d03b973f9bUL, 0x13a3da3661206e5eUL, ++ /* 108 */ 0xc6bd5837725d94e5UL, 0x18e30912205016c5UL, ++ 0x2088ce1570033c68UL, 0x7fba1f495c837987UL, ++ /* 109 */ 0x5a8c7423f2f9079dUL, 0x1735157b34023fc5UL, ++ 0xe4f9b49ad2fab351UL, 0x6691ff72c878e33cUL, ++ /* 110 */ 0x122c2adedc5eff3eUL, 0xf8dd4bf1d8956cf4UL, ++ 0xeb86205d9e9e5bdaUL, 0x049b92b9d975c743UL, ++ /* 111 */ 0xa5379730b0f6c05aUL, 0x72a0ffacc6f3a553UL, ++ 0xb0032c34b20dcd6dUL, 0x470e9dbc88d5164aUL, ++ /* 112 */ 0xb19cf10ca237c047UL, 0xb65466711f6c81a2UL, ++ 0xb3321bd16dd80b43UL, 0x48c14f600c5fbe8eUL, ++ /* 113 */ 0x66451c264aa6c803UL, 0xb66e3904a4fa7da6UL, ++ 0xd45f19b0b3128395UL, 0x31602627c3c9bc10UL, ++ /* 114 */ 0x3120dc4832e4e10dUL, 0xeb20c46756c717f7UL, ++ 0x00f52e3f67280294UL, 0x566d4fc14730c509UL, ++ /* 115 */ 0x7e3a5d40fd837206UL, 0xc1e926dc7159547aUL, ++ 0x216730fba68d6095UL, 0x22e8c3843f69cea7UL, ++ /* 116 */ 0x33d074e8930e4b2bUL, 0xb6e4350e84d15816UL, ++ 0x5534c26ad6ba2365UL, 0x7773c12f89f1f3f3UL, ++ /* 117 */ 0x8cba404da57962aaUL, 0x5b9897a81999ce56UL, ++ 0x508e862f121692fcUL, 0x3a81907fa093c291UL, ++ /* 118 */ 0x0dded0ff4725a510UL, 0x10d8cc10673fc503UL, ++ 0x5b9d151c9f1f4e89UL, 0x32a5c1d5cb09a44cUL, ++ /* 119 */ 0x1e0aa442b90541fbUL, 0x5f85eb7cc1b485dbUL, ++ 0xbee595ce8a9df2e5UL, 0x25e496c722422236UL, ++ /* 120 */ 0x5edf3c46cd0fe5b9UL, 0x34e75a7ed2a43388UL, ++ 0xe488de11d761e352UL, 0x0e878a01a085545cUL, ++ /* 121 */ 0xba493c77e021bb04UL, 0x2b4d1843c7df899aUL, ++ 0x9ea37a487ae80d67UL, 0x67a9958011e41794UL, ++ /* 122 */ 0x4b58051a6697b065UL, 0x47e33f7d8d6ba6d4UL, ++ 0xbb4da8d483ca46c1UL, 0x68becaa181c2db0dUL, ++ /* 123 */ 0x8d8980e90b989aa5UL, 0xf95eb14a2c93c99bUL, ++ 0x51c6c7c4796e73a2UL, 0x6e228363b5efb569UL, ++ /* 124 */ 0xc6bbc0b02dd624c8UL, 0x777eb47dec8170eeUL, ++ 0x3cde15a004cfafa9UL, 0x1dc6bc087160bf9bUL, ++ /* 125 */ 0x2e07e043eec34002UL, 0x18e9fc677a68dc7fUL, ++ 0xd8da03188bd15b9aUL, 0x48fbc3bb00568253UL, ++ /* 126 */ 0x57547d4cfb654ce1UL, 0xd3565b82a058e2adUL, ++ 0xf63eaf0bbf154478UL, 0x47531ef114dfbb18UL, ++ /* 127 */ 0xe1ec630a4278c587UL, 0x5507d546ca8e83f3UL, ++ 0x85e135c63adc0c2bUL, 0x0aa7efa85682844eUL, ++ /* 128 */ 0x72691ba8b3e1f615UL, 0x32b4e9701fbe3ffaUL, ++ 0x97b6d92e39bb7868UL, 0x2cfe53dea02e39e8UL, ++ /* 129 */ 0x687392cd85cd52b0UL, 0x27ff66c910e29831UL, ++ 0x97134556a9832d06UL, 0x269bb0360a84f8a0UL, ++ /* 130 */ 0x706e55457643f85cUL, 0x3734a48c9b597d1bUL, ++ 0x7aee91e8c6efa472UL, 0x5cd6abc198a9d9e0UL, ++ /* 131 */ 0x0e04de06cb3ce41aUL, 0xd8c6eb893402e138UL, ++ 0x904659bb686e3772UL, 0x7215c371746ba8c8UL, ++ /* 132 */ 0xfd12a97eeae4a2d9UL, 0x9514b7516394f2c5UL, ++ 0x266fd5809208f294UL, 0x5c847085619a26b9UL, ++ /* 133 */ 0x52985410fed694eaUL, 0x3c905b934a2ed254UL, ++ 0x10bb47692d3be467UL, 0x063b3d2d69e5e9e1UL, ++ /* 134 */ 0x472726eedda57debUL, 0xefb6c4ae10f41891UL, ++ 0x2b1641917b307614UL, 0x117c554fc4f45b7cUL, ++ /* 135 */ 0xc07cf3118f9d8812UL, 0x01dbd82050017939UL, ++ 0xd7e803f4171b2827UL, 0x1015e87487d225eaUL, ++ /* 136 */ 0xc58de3fed23acc4dUL, 0x50db91c294a7be2dUL, ++ 0x0b94d43d1c9cf457UL, 0x6b1640fa6e37524aUL, ++ /* 137 */ 0x692f346c5fda0d09UL, 0x200b1c59fa4d3151UL, ++ 0xb8c46f760777a296UL, 0x4b38395f3ffdfbcfUL, ++ /* 138 */ 0x18d25e00be54d671UL, 0x60d50582bec8aba6UL, ++ 0x87ad8f263b78b982UL, 0x50fdf64e9cda0432UL, ++ /* 139 */ 0x90f567aac578dcf0UL, 0xef1e9b0ef2a3133bUL, ++ 0x0eebba9242d9de71UL, 0x15473c9bf03101c7UL, ++ /* 140 */ 0x7c77e8ae56b78095UL, 0xb678e7666e6f078eUL, ++ 0x2da0b9615348ba1fUL, 0x7cf931c1ff733f0bUL, ++ /* 141 */ 0x26b357f50a0a366cUL, 0xe9708cf42b87d732UL, ++ 0xc13aeea5f91cb2c0UL, 0x35d90c991143bb4cUL, ++ /* 142 */ 0x47c1c404a9a0d9dcUL, 0x659e58451972d251UL, ++ 0x3875a8c473b38c31UL, 0x1fbd9ed379561f24UL, ++ /* 143 */ 0x11fabc6fd41ec28dUL, 0x7ef8dfe3cd2a2dcaUL, ++ 0x72e73b5d8c404595UL, 0x6135fa4954b72f27UL, ++ /* 144 */ 0xccfc32a2de24b69cUL, 0x3f55698c1f095d88UL, ++ 0xbe3350ed5ac3f929UL, 0x5e9bf806ca477eebUL, ++ /* 145 */ 0xe9ce8fb63c309f68UL, 0x5376f63565e1f9f4UL, ++ 0xd1afcfb35a6393f1UL, 0x6632a1ede5623506UL, ++ /* 146 */ 0x0b7d6c390c2ded4cUL, 0x56cb3281df04cb1fUL, ++ 0x66305a1249ecc3c7UL, 0x5d588b60a38ca72aUL, ++ /* 147 */ 0xa6ecbf78e8e5f42dUL, 0x86eeb44b3c8a3eecUL, ++ 0xec219c48fbd21604UL, 0x1aaf1af517c36731UL, ++ /* 148 */ 0xc306a2836769bde7UL, 0x208280622b1e2adbUL, ++ 0x8027f51ffbff94a6UL, 0x76cfa1ce1124f26bUL, ++ /* 149 */ 0x18eb00562422abb6UL, 0xf377c4d58f8c29c3UL, ++ 0x4dbbc207f531561aUL, 0x0253b7f082128a27UL, ++ /* 150 */ 0x3d1f091cb62c17e0UL, 0x4860e1abd64628a9UL, ++ 0x52d17436309d4253UL, 0x356f97e13efae576UL, ++ /* 151 */ 0xd351e11aa150535bUL, 0x3e6b45bb1dd878ccUL, ++ 0x0c776128bed92c98UL, 0x1d34ae93032885b8UL, ++ /* 152 */ 0x4ba0488ca85ba4c3UL, 0x985348c33c9ce6ceUL, ++ 0x66124c6f97bda770UL, 0x0f81a0290654124aUL, ++ /* 153 */ 0x9ed09ca6569b86fdUL, 0x811009fd18af9a2dUL, ++ 0xff08d03f93d8c20aUL, 0x52a148199faef26bUL, ++ /* 154 */ 0x3e03f9dc2d8d1b73UL, 0x4205801873961a70UL, ++ 0xc0d987f041a35970UL, 0x07aa1f15a1c0d549UL, ++ /* 155 */ 0xdfd46ce08cd27224UL, 0x6d0a024f934e4239UL, ++ 0x808a7a6399897b59UL, 0x0a4556e9e13d95a2UL, ++ /* 156 */ 0xd21a991fe9c13045UL, 0x9b0e8548fe7751b8UL, ++ 0x5da643cb4bf30035UL, 0x77db28d63940f721UL, ++ /* 157 */ 0xfc5eeb614adc9011UL, 0x5229419ae8c411ebUL, ++ 0x9ec3e7787d1dcf74UL, 0x340d053e216e4cb5UL, ++ /* 158 */ 0xcac7af39b48df2b4UL, 0xc0faec2871a10a94UL, ++ 0x140a69245ca575edUL, 0x0cf1c37134273a4cUL, ++ /* 159 */ 0xc8ee306ac224b8a5UL, 0x57eaee7ccb4930b0UL, ++ 0xa1e806bdaacbe74fUL, 0x7d9a62742eeb657dUL, ++ /* 160 */ 0x9eb6b6ef546c4830UL, 0x885cca1fddb36e2eUL, ++ 0xe6b9f383ef0d7105UL, 0x58654fef9d2e0412UL, ++ /* 161 */ 0xa905c4ffbe0e8e26UL, 0x942de5df9b31816eUL, ++ 0x497d723f802e88e1UL, 0x30684dea602f408dUL, ++ /* 162 */ 0x21e5a278a3e6cb34UL, 0xaefb6e6f5b151dc4UL, ++ 0xb30b8e049d77ca15UL, 0x28c3c9cf53b98981UL, ++ /* 163 */ 0x287fb721556cdd2aUL, 0x0d317ca897022274UL, ++ 0x7468c7423a543258UL, 0x4a7f11464eb5642fUL, ++ /* 164 */ 0xa237a4774d193aa6UL, 0xd865986ea92129a1UL, ++ 0x24c515ecf87c1a88UL, 0x604003575f39f5ebUL, ++ /* 165 */ 0x47b9f189570a9b27UL, 0x2b98cede465e4b78UL, ++ 0x026df551dbb85c20UL, 0x74fcd91047e21901UL, ++ /* 166 */ 0x13e2a90a23c1bfa3UL, 0x0cb0074e478519f6UL, ++ 0x5ff1cbbe3af6cf44UL, 0x67fe5438be812dbeUL, ++ /* 167 */ 0xd13cf64fa40f05b0UL, 0x054dfb2f32283787UL, ++ 0x4173915b7f0d2aeaUL, 0x482f144f1f610d4eUL, ++ /* 168 */ 0xf6210201b47f8234UL, 0x5d0ae1929e70b990UL, ++ 0xdcd7f455b049567cUL, 0x7e93d0f1f0916f01UL, ++ /* 169 */ 0xdd79cbf18a7db4faUL, 0xbe8391bf6f74c62fUL, ++ 0x027145d14b8291bdUL, 0x585a73ea2cbf1705UL, ++ /* 170 */ 0x485ca03e928a0db2UL, 0x10fc01a5742857e7UL, ++ 0x2f482edbd6d551a7UL, 0x0f0433b5048fdb8aUL, ++ /* 171 */ 0x60da2e8dd7dc6247UL, 0x88b4c9d38cd4819aUL, ++ 0x13033ac001f66697UL, 0x273b24fe3b367d75UL, ++ /* 172 */ 0xc6e8f66a31b3b9d4UL, 0x281514a494df49d5UL, ++ 0xd1726fdfc8b23da7UL, 0x4b3ae7d103dee548UL, ++ /* 173 */ 0xc6256e19ce4b9d7eUL, 0xff5c5cf186e3c61cUL, ++ 0xacc63ca34b8ec145UL, 0x74621888fee66574UL, ++ /* 174 */ 0x956f409645290a1eUL, 0xef0bf8e3263a962eUL, ++ 0xed6a50eb5ec2647bUL, 0x0694283a9dca7502UL, ++ /* 175 */ 0x769b963643a2dcd1UL, 0x42b7c8ea09fc5353UL, ++ 0x4f002aee13397eabUL, 0x63005e2c19b7d63aUL, ++ /* 176 */ 0xca6736da63023beaUL, 0x966c7f6db12a99b7UL, ++ 0xace09390c537c5e1UL, 0x0b696063a1aa89eeUL, ++ /* 177 */ 0xebb03e97288c56e5UL, 0x432a9f9f938c8be8UL, ++ 0xa6a5a93d5b717f71UL, 0x1a5fb4c3e18f9d97UL, ++ /* 178 */ 0x1c94e7ad1c60cdceUL, 0xee202a43fc02c4a0UL, ++ 0x8dafe4d867c46a20UL, 0x0a10263c8ac27b58UL, ++ /* 179 */ 0xd0dea9dfe4432a4aUL, 0x856af87bbe9277c5UL, ++ 0xce8472acc212c71aUL, 0x6f151b6d9bbb1e91UL, ++ /* 180 */ 0x26776c527ceed56aUL, 0x7d211cb7fbf8faecUL, ++ 0x37ae66a6fd4609ccUL, 0x1f81b702d2770c42UL, ++ /* 181 */ 0x2fb0b057eac58392UL, 0xe1dd89fe29744e9dUL, ++ 0xc964f8eb17beb4f8UL, 0x29571073c9a2d41eUL, ++ /* 182 */ 0xa948a18981c0e254UL, 0x2df6369b65b22830UL, ++ 0xa33eb2d75fcfd3c6UL, 0x078cd6ec4199a01fUL, ++ /* 183 */ 0x4a584a41ad900d2fUL, 0x32142b78e2c74c52UL, ++ 0x68c4e8338431c978UL, 0x7f69ea9008689fc2UL, ++ /* 184 */ 0x52f2c81e46a38265UL, 0xfd78072d04a832fdUL, ++ 0x8cd7d5fa25359e94UL, 0x4de71b7454cc29d2UL, ++ /* 185 */ 0x42eb60ad1eda6ac9UL, 0x0aad37dfdbc09c3aUL, ++ 0x81004b71e33cc191UL, 0x44e6be345122803cUL, ++ /* 186 */ 0x03fe8388ba1920dbUL, 0xf5d57c32150db008UL, ++ 0x49c8c4281af60c29UL, 0x21edb518de701aeeUL, ++ /* 187 */ 0x7fb63e418f06dc99UL, 0xa4460d99c166d7b8UL, ++ 0x24dd5248ce520a83UL, 0x5ec3ad712b928358UL, ++ /* 188 */ 0x15022a5fbd17930fUL, 0xa4f64a77d82570e3UL, ++ 0x12bc8d6915783712UL, 0x498194c0fc620abbUL, ++ /* 189 */ 0x38a2d9d255686c82UL, 0x785c6bd9193e21f0UL, ++ 0xe4d5c81ab24a5484UL, 0x56307860b2e20989UL, ++ /* 190 */ 0x429d55f78b4d74c4UL, 0x22f1834643350131UL, ++ 0x1e60c24598c71fffUL, 0x59f2f014979983efUL, ++ /* 191 */ 0x46a47d56eb494a44UL, 0x3e22a854d636a18eUL, ++ 0xb346e15274491c3bUL, 0x2ceafd4e5390cde7UL, ++ /* 192 */ 0xba8a8538be0d6675UL, 0x4b9074bb50818e23UL, ++ 0xcbdab89085d304c3UL, 0x61a24fe0e56192c4UL, ++ /* 193 */ 0xcb7615e6db525bcbUL, 0xdd7d8c35a567e4caUL, ++ 0xe6b4153acafcdd69UL, 0x2d668e097f3c9766UL, ++ /* 194 */ 0xa57e7e265ce55ef0UL, 0x5d9f4e527cd4b967UL, ++ 0xfbc83606492fd1e5UL, 0x090d52beb7c3f7aeUL, ++ /* 195 */ 0x09b9515a1e7b4d7cUL, 0x1f266a2599da44c0UL, ++ 0xa1c49548e2c55504UL, 0x7ef04287126f15ccUL, ++ /* 196 */ 0xfed1659dbd30ef15UL, 0x8b4ab9eec4e0277bUL, ++ 0x884d6236a5df3291UL, 0x1fd96ea6bf5cf788UL, ++ /* 197 */ 0x42a161981f190d9aUL, 0x61d849507e6052c1UL, ++ 0x9fe113bf285a2cd5UL, 0x7c22d676dbad85d8UL, ++ /* 198 */ 0x82e770ed2bfbd27dUL, 0x4c05b2ece996f5a5UL, ++ 0xcd40a9c2b0900150UL, 0x5895319213d9bf64UL, ++ /* 199 */ 0xe7cc5d703fea2e08UL, 0xb50c491258e2188cUL, ++ 0xcce30baa48205bf0UL, 0x537c659ccfa32d62UL, ++ /* 200 */ 0x37b6623a98cfc088UL, 0xfe9bed1fa4d6aca4UL, ++ 0x04d29b8e56a8d1b0UL, 0x725f71c40b519575UL, ++ /* 201 */ 0x28c7f89cd0339ce6UL, 0x8367b14469ddc18bUL, ++ 0x883ada83a6a1652cUL, 0x585f1974034d6c17UL, ++ /* 202 */ 0x89cfb266f1b19188UL, 0xe63b4863e7c35217UL, ++ 0xd88c9da6b4c0526aUL, 0x3e035c9df0954635UL, ++ /* 203 */ 0xdd9d5412fb45de9dUL, 0xdd684532e4cff40dUL, ++ 0x4b5c999b151d671cUL, 0x2d8c2cc811e7f690UL, ++ /* 204 */ 0x7f54be1d90055d40UL, 0xa464c5df464aaf40UL, ++ 0x33979624f0e917beUL, 0x2c018dc527356b30UL, ++ /* 205 */ 0xa5415024e330b3d4UL, 0x73ff3d96691652d3UL, ++ 0x94ec42c4ef9b59f1UL, 0x0747201618d08e5aUL, ++ /* 206 */ 0x4d6ca48aca411c53UL, 0x66415f2fcfa66119UL, ++ 0x9c4dd40051e227ffUL, 0x59810bc09a02f7ebUL, ++ /* 207 */ 0x2a7eb171b3dc101dUL, 0x441c5ab99ffef68eUL, ++ 0x32025c9b93b359eaUL, 0x5e8ce0a71e9d112fUL, ++ /* 208 */ 0xbfcccb92429503fdUL, 0xd271ba752f095d55UL, ++ 0x345ead5e972d091eUL, 0x18c8df11a83103baUL, ++ /* 209 */ 0x90cd949a9aed0f4cUL, 0xc5d1f4cb6660e37eUL, ++ 0xb8cac52d56c52e0bUL, 0x6e42e400c5808e0dUL, ++ /* 210 */ 0xa3b46966eeaefd23UL, 0x0c4f1f0be39ecdcaUL, ++ 0x189dc8c9d683a51dUL, 0x51f27f054c09351bUL, ++ /* 211 */ 0x4c487ccd2a320682UL, 0x587ea95bb3df1c96UL, ++ 0xc8ccf79e555cb8e8UL, 0x547dc829a206d73dUL, ++ /* 212 */ 0xb822a6cd80c39b06UL, 0xe96d54732000d4c6UL, ++ 0x28535b6f91463b4dUL, 0x228f4660e2486e1dUL, ++ /* 213 */ 0x98799538de8d3abfUL, 0x8cd8330045ebca6eUL, ++ 0x79952a008221e738UL, 0x4322e1a7535cd2bbUL, ++ /* 214 */ 0xb114c11819d1801cUL, 0x2016e4d84f3f5ec7UL, ++ 0xdd0e2df409260f4cUL, 0x5ec362c0ae5f7266UL, ++ /* 215 */ 0xc0462b18b8b2b4eeUL, 0x7cc8d950274d1afbUL, ++ 0xf25f7105436b02d2UL, 0x43bbf8dcbff9ccd3UL, ++ /* 216 */ 0xb6ad1767a039e9dfUL, 0xb0714da8f69d3583UL, ++ 0x5e55fa18b42931f5UL, 0x4ed5558f33c60961UL, ++ /* 217 */ 0x1fe37901c647a5ddUL, 0x593ddf1f8081d357UL, ++ 0x0249a4fd813fd7a6UL, 0x69acca274e9caf61UL, ++ /* 218 */ 0x047ba3ea330721c9UL, 0x83423fc20e7e1ea0UL, ++ 0x1df4c0af01314a60UL, 0x09a62dab89289527UL, ++ /* 219 */ 0xa5b325a49cc6cb00UL, 0xe94b5dc654b56cb6UL, ++ 0x3be28779adc994a0UL, 0x4296e8f8ba3a4aadUL, ++ /* 220 */ 0x328689761e451eabUL, 0x2e4d598bff59594aUL, ++ 0x49b96853d7a7084aUL, 0x4980a319601420a8UL, ++ /* 221 */ 0x9565b9e12f552c42UL, 0x8a5318db7100fe96UL, ++ 0x05c90b4d43add0d7UL, 0x538b4cd66a5d4edaUL, ++ /* 222 */ 0xf4e94fc3e89f039fUL, 0x592c9af26f618045UL, ++ 0x08a36eb5fd4b9550UL, 0x25fffaf6c2ed1419UL, ++ /* 223 */ 0x34434459cc79d354UL, 0xeeecbfb4b1d5476bUL, ++ 0xddeb34a061615d99UL, 0x5129cecceb64b773UL, ++ /* 224 */ 0xee43215894993520UL, 0x772f9c7cf14c0b3bUL, ++ 0xd2e2fce306bedad5UL, 0x715f42b546f06a97UL, ++ /* 225 */ 0x434ecdceda5b5f1aUL, 0x0da17115a49741a9UL, ++ 0x680bd77c73edad2eUL, 0x487c02354edd9041UL, ++ /* 226 */ 0xb8efeff3a70ed9c4UL, 0x56a32aa3e857e302UL, ++ 0xdf3a68bd48a2a5a0UL, 0x07f650b73176c444UL, ++ /* 227 */ 0xe38b9b1626e0ccb1UL, 0x79e053c18b09fb36UL, ++ 0x56d90319c9f94964UL, 0x1ca941e7ac9ff5c4UL, ++ /* 228 */ 0x49c4df29162fa0bbUL, 0x8488cf3282b33305UL, ++ 0x95dfda14cabb437dUL, 0x3391f78264d5ad86UL, ++ /* 229 */ 0x729ae06ae2b5095dUL, 0xd58a58d73259a946UL, ++ 0xe9834262d13921edUL, 0x27fedafaa54bb592UL, ++ /* 230 */ 0xa99dc5b829ad48bbUL, 0x5f025742499ee260UL, ++ 0x802c8ecd5d7513fdUL, 0x78ceb3ef3f6dd938UL, ++ /* 231 */ 0xc342f44f8a135d94UL, 0x7b9edb44828cdda3UL, ++ 0x9436d11a0537cfe7UL, 0x5064b164ec1ab4c8UL, ++ /* 232 */ 0x7020eccfd37eb2fcUL, 0x1f31ea3ed90d25fcUL, ++ 0x1b930d7bdfa1bb34UL, 0x5344467a48113044UL, ++ /* 233 */ 0x70073170f25e6dfbUL, 0xe385dc1a50114cc8UL, ++ 0x2348698ac8fc4f00UL, 0x2a77a55284dd40d8UL, ++ /* 234 */ 0xfe06afe0c98c6ce4UL, 0xc235df96dddfd6e4UL, ++ 0x1428d01e33bf1ed3UL, 0x785768ec9300bdafUL, ++ /* 235 */ 0x9702e57a91deb63bUL, 0x61bdb8bfe5ce8b80UL, ++ 0x645b426f3d1d58acUL, 0x4804a82227a557bcUL, ++ /* 236 */ 0x8e57048ab44d2601UL, 0x68d6501a4b3a6935UL, ++ 0xc39c9ec3f9e1c293UL, 0x4172f257d4de63e2UL, ++ /* 237 */ 0xd368b450330c6401UL, 0x040d3017418f2391UL, ++ 0x2c34bb6090b7d90dUL, 0x16f649228fdfd51fUL, ++ /* 238 */ 0xbea6818e2b928ef5UL, 0xe28ccf91cdc11e72UL, ++ 0x594aaa68e77a36cdUL, 0x313034806c7ffd0fUL, ++ /* 239 */ 0x8a9d27ac2249bd65UL, 0x19a3b464018e9512UL, ++ 0xc26ccff352b37ec7UL, 0x056f68341d797b21UL, ++ /* 240 */ 0x5e79d6757efd2327UL, 0xfabdbcb6553afe15UL, ++ 0xd3e7222c6eaf5a60UL, 0x7046c76d4dae743bUL, ++ /* 241 */ 0x660be872b18d4a55UL, 0x19992518574e1496UL, ++ 0xc103053a302bdcbbUL, 0x3ed8e9800b218e8eUL, ++ /* 242 */ 0x7b0b9239fa75e03eUL, 0xefe9fb684633c083UL, ++ 0x98a35fbe391a7793UL, 0x6065510fe2d0fe34UL, ++ /* 243 */ 0x55cb668548abad0cUL, 0xb4584548da87e527UL, ++ 0x2c43ecea0107c1ddUL, 0x526028809372de35UL, ++ /* 244 */ 0x3415c56af9213b1fUL, 0x5bee1a4d017e98dbUL, ++ 0x13f6b105b5cf709bUL, 0x5ff20e3482b29ab6UL, ++ /* 245 */ 0x0aa29c75cc2e6c90UL, 0xfc7d73ca3a70e206UL, ++ 0x899fc38fc4b5c515UL, 0x250386b124ffc207UL, ++ /* 246 */ 0x54ea28d5ae3d2b56UL, 0x9913149dd6de60ceUL, ++ 0x16694fc58f06d6c1UL, 0x46b23975eb018fc7UL, ++ /* 247 */ 0x470a6a0fb4b7b4e2UL, 0x5d92475a8f7253deUL, ++ 0xabeee5b52fbd3adbUL, 0x7fa20801a0806968UL, ++ /* 248 */ 0x76f3faf19f7714d2UL, 0xb3e840c12f4660c3UL, ++ 0x0fb4cd8df212744eUL, 0x4b065a251d3a2dd2UL, ++ /* 249 */ 0x5cebde383d77cd4aUL, 0x6adf39df882c9cb1UL, ++ 0xa2dd242eb09af759UL, 0x3147c0e50e5f6422UL, ++ /* 250 */ 0x164ca5101d1350dbUL, 0xf8d13479c33fc962UL, ++ 0xe640ce4d13e5da08UL, 0x4bdee0c45061f8baUL, ++ /* 251 */ 0xd7c46dc1a4edb1c9UL, 0x5514d7b6437fd98aUL, ++ 0x58942f6bb2a1c00bUL, 0x2dffb2ab1d70710eUL, ++ /* 252 */ 0xccdfcf2fc18b6d68UL, 0xa8ebcba8b7806167UL, ++ 0x980697f95e2937e3UL, 0x02fbba1cd0126e8cUL ++}; ++ ++/* c is two 512-bit products: c0[0:7]=a0[0:3]*b0[0:3] and c1[8:15]=a1[4:7]*b1[4:7] ++ * a is two 256-bit integers: a0[0:3] and a1[4:7] ++ * b is two 256-bit integers: b0[0:3] and b1[4:7] ++ */ ++static void mul2_256x256_integer_adx(u64 *const c, const u64 *const a, ++ const u64 *const b) ++{ ++ asm volatile( ++ "xorl %%r14d, %%r14d ;" ++ "movq (%1), %%rdx; " /* A[0] */ ++ "mulx (%2), %%r8, %%r15; " /* A[0]*B[0] */ ++ "xorl %%r10d, %%r10d ;" ++ "movq %%r8, (%0) ;" ++ "mulx 8(%2), %%r10, %%rax; " /* A[0]*B[1] */ ++ "adox %%r10, %%r15 ;" ++ "mulx 16(%2), %%r8, %%rbx; " /* A[0]*B[2] */ ++ "adox %%r8, %%rax ;" ++ "mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */ ++ "adox %%r10, %%rbx ;" ++ /******************************************/ ++ "adox %%r14, %%rcx ;" ++ ++ "movq 8(%1), %%rdx; " /* A[1] */ ++ "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ ++ "adox %%r15, %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ ++ "adox %%r10, %%r9 ;" ++ "adcx %%r9, %%rax ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[1]*B[2] */ ++ "adox %%r8, %%r11 ;" ++ "adcx %%r11, %%rbx ;" ++ "mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */ ++ "adox %%r10, %%r13 ;" ++ "adcx %%r13, %%rcx ;" ++ /******************************************/ ++ "adox %%r14, %%r15 ;" ++ "adcx %%r14, %%r15 ;" ++ ++ "movq 16(%1), %%rdx; " /* A[2] */ ++ "xorl %%r10d, %%r10d ;" ++ "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ ++ "adox %%rax, %%r8 ;" ++ "movq %%r8, 16(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ ++ "adox %%r10, %%r9 ;" ++ "adcx %%r9, %%rbx ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[2]*B[2] */ ++ "adox %%r8, %%r11 ;" ++ "adcx %%r11, %%rcx ;" ++ "mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */ ++ "adox %%r10, %%r13 ;" ++ "adcx %%r13, %%r15 ;" ++ /******************************************/ ++ "adox %%r14, %%rax ;" ++ "adcx %%r14, %%rax ;" ++ ++ "movq 24(%1), %%rdx; " /* A[3] */ ++ "xorl %%r10d, %%r10d ;" ++ "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ ++ "adox %%rbx, %%r8 ;" ++ "movq %%r8, 24(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ ++ "adox %%r10, %%r9 ;" ++ "adcx %%r9, %%rcx ;" ++ "movq %%rcx, 32(%0) ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[3]*B[2] */ ++ "adox %%r8, %%r11 ;" ++ "adcx %%r11, %%r15 ;" ++ "movq %%r15, 40(%0) ;" ++ "mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */ ++ "adox %%r10, %%r13 ;" ++ "adcx %%r13, %%rax ;" ++ "movq %%rax, 48(%0) ;" ++ /******************************************/ ++ "adox %%r14, %%rbx ;" ++ "adcx %%r14, %%rbx ;" ++ "movq %%rbx, 56(%0) ;" ++ ++ "movq 32(%1), %%rdx; " /* C[0] */ ++ "mulx 32(%2), %%r8, %%r15; " /* C[0]*D[0] */ ++ "xorl %%r10d, %%r10d ;" ++ "movq %%r8, 64(%0);" ++ "mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */ ++ "adox %%r10, %%r15 ;" ++ "mulx 48(%2), %%r8, %%rbx; " /* C[0]*D[2] */ ++ "adox %%r8, %%rax ;" ++ "mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */ ++ "adox %%r10, %%rbx ;" ++ /******************************************/ ++ "adox %%r14, %%rcx ;" ++ ++ "movq 40(%1), %%rdx; " /* C[1] */ ++ "xorl %%r10d, %%r10d ;" ++ "mulx 32(%2), %%r8, %%r9; " /* C[1]*D[0] */ ++ "adox %%r15, %%r8 ;" ++ "movq %%r8, 72(%0);" ++ "mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */ ++ "adox %%r10, %%r9 ;" ++ "adcx %%r9, %%rax ;" ++ "mulx 48(%2), %%r8, %%r13; " /* C[1]*D[2] */ ++ "adox %%r8, %%r11 ;" ++ "adcx %%r11, %%rbx ;" ++ "mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */ ++ "adox %%r10, %%r13 ;" ++ "adcx %%r13, %%rcx ;" ++ /******************************************/ ++ "adox %%r14, %%r15 ;" ++ "adcx %%r14, %%r15 ;" ++ ++ "movq 48(%1), %%rdx; " /* C[2] */ ++ "xorl %%r10d, %%r10d ;" ++ "mulx 32(%2), %%r8, %%r9; " /* C[2]*D[0] */ ++ "adox %%rax, %%r8 ;" ++ "movq %%r8, 80(%0);" ++ "mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */ ++ "adox %%r10, %%r9 ;" ++ "adcx %%r9, %%rbx ;" ++ "mulx 48(%2), %%r8, %%r13; " /* C[2]*D[2] */ ++ "adox %%r8, %%r11 ;" ++ "adcx %%r11, %%rcx ;" ++ "mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */ ++ "adox %%r10, %%r13 ;" ++ "adcx %%r13, %%r15 ;" ++ /******************************************/ ++ "adox %%r14, %%rax ;" ++ "adcx %%r14, %%rax ;" ++ ++ "movq 56(%1), %%rdx; " /* C[3] */ ++ "xorl %%r10d, %%r10d ;" ++ "mulx 32(%2), %%r8, %%r9; " /* C[3]*D[0] */ ++ "adox %%rbx, %%r8 ;" ++ "movq %%r8, 88(%0);" ++ "mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */ ++ "adox %%r10, %%r9 ;" ++ "adcx %%r9, %%rcx ;" ++ "movq %%rcx, 96(%0) ;" ++ "mulx 48(%2), %%r8, %%r13; " /* C[3]*D[2] */ ++ "adox %%r8, %%r11 ;" ++ "adcx %%r11, %%r15 ;" ++ "movq %%r15, 104(%0) ;" ++ "mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */ ++ "adox %%r10, %%r13 ;" ++ "adcx %%r13, %%rax ;" ++ "movq %%rax, 112(%0) ;" ++ /******************************************/ ++ "adox %%r14, %%rbx ;" ++ "adcx %%r14, %%rbx ;" ++ "movq %%rbx, 120(%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(b) ++ : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", ++ "%r10", "%r11", "%r13", "%r14", "%r15"); ++} ++ ++static void mul2_256x256_integer_bmi2(u64 *const c, const u64 *const a, ++ const u64 *const b) ++{ ++ asm volatile( ++ "movq (%1), %%rdx; " /* A[0] */ ++ "mulx (%2), %%r8, %%r15; " /* A[0]*B[0] */ ++ "movq %%r8, (%0) ;" ++ "mulx 8(%2), %%r10, %%rax; " /* A[0]*B[1] */ ++ "addq %%r10, %%r15 ;" ++ "mulx 16(%2), %%r8, %%rbx; " /* A[0]*B[2] */ ++ "adcq %%r8, %%rax ;" ++ "mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */ ++ "adcq %%r10, %%rbx ;" ++ /******************************************/ ++ "adcq $0, %%rcx ;" ++ ++ "movq 8(%1), %%rdx; " /* A[1] */ ++ "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ ++ "addq %%r15, %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[1]*B[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%r15 ;" ++ ++ "addq %%r9, %%rax ;" ++ "adcq %%r11, %%rbx ;" ++ "adcq %%r13, %%rcx ;" ++ "adcq $0, %%r15 ;" ++ ++ "movq 16(%1), %%rdx; " /* A[2] */ ++ "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ ++ "addq %%rax, %%r8 ;" ++ "movq %%r8, 16(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[2]*B[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%rax ;" ++ ++ "addq %%r9, %%rbx ;" ++ "adcq %%r11, %%rcx ;" ++ "adcq %%r13, %%r15 ;" ++ "adcq $0, %%rax ;" ++ ++ "movq 24(%1), %%rdx; " /* A[3] */ ++ "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ ++ "addq %%rbx, %%r8 ;" ++ "movq %%r8, 24(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[3]*B[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%rbx ;" ++ ++ "addq %%r9, %%rcx ;" ++ "movq %%rcx, 32(%0) ;" ++ "adcq %%r11, %%r15 ;" ++ "movq %%r15, 40(%0) ;" ++ "adcq %%r13, %%rax ;" ++ "movq %%rax, 48(%0) ;" ++ "adcq $0, %%rbx ;" ++ "movq %%rbx, 56(%0) ;" ++ ++ "movq 32(%1), %%rdx; " /* C[0] */ ++ "mulx 32(%2), %%r8, %%r15; " /* C[0]*D[0] */ ++ "movq %%r8, 64(%0) ;" ++ "mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */ ++ "addq %%r10, %%r15 ;" ++ "mulx 48(%2), %%r8, %%rbx; " /* C[0]*D[2] */ ++ "adcq %%r8, %%rax ;" ++ "mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */ ++ "adcq %%r10, %%rbx ;" ++ /******************************************/ ++ "adcq $0, %%rcx ;" ++ ++ "movq 40(%1), %%rdx; " /* C[1] */ ++ "mulx 32(%2), %%r8, %%r9; " /* C[1]*D[0] */ ++ "addq %%r15, %%r8 ;" ++ "movq %%r8, 72(%0) ;" ++ "mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 48(%2), %%r8, %%r13; " /* C[1]*D[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%r15 ;" ++ ++ "addq %%r9, %%rax ;" ++ "adcq %%r11, %%rbx ;" ++ "adcq %%r13, %%rcx ;" ++ "adcq $0, %%r15 ;" ++ ++ "movq 48(%1), %%rdx; " /* C[2] */ ++ "mulx 32(%2), %%r8, %%r9; " /* C[2]*D[0] */ ++ "addq %%rax, %%r8 ;" ++ "movq %%r8, 80(%0) ;" ++ "mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 48(%2), %%r8, %%r13; " /* C[2]*D[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%rax ;" ++ ++ "addq %%r9, %%rbx ;" ++ "adcq %%r11, %%rcx ;" ++ "adcq %%r13, %%r15 ;" ++ "adcq $0, %%rax ;" ++ ++ "movq 56(%1), %%rdx; " /* C[3] */ ++ "mulx 32(%2), %%r8, %%r9; " /* C[3]*D[0] */ ++ "addq %%rbx, %%r8 ;" ++ "movq %%r8, 88(%0) ;" ++ "mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 48(%2), %%r8, %%r13; " /* C[3]*D[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%rbx ;" ++ ++ "addq %%r9, %%rcx ;" ++ "movq %%rcx, 96(%0) ;" ++ "adcq %%r11, %%r15 ;" ++ "movq %%r15, 104(%0) ;" ++ "adcq %%r13, %%rax ;" ++ "movq %%rax, 112(%0) ;" ++ "adcq $0, %%rbx ;" ++ "movq %%rbx, 120(%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(b) ++ : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", ++ "%r10", "%r11", "%r13", "%r15"); ++} ++ ++static void sqr2_256x256_integer_adx(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movq (%1), %%rdx ;" /* A[0] */ ++ "mulx 8(%1), %%r8, %%r14 ;" /* A[1]*A[0] */ ++ "xorl %%r15d, %%r15d;" ++ "mulx 16(%1), %%r9, %%r10 ;" /* A[2]*A[0] */ ++ "adcx %%r14, %%r9 ;" ++ "mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */ ++ "adcx %%rax, %%r10 ;" ++ "movq 24(%1), %%rdx ;" /* A[3] */ ++ "mulx 8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */ ++ "adcx %%rcx, %%r11 ;" ++ "mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */ ++ "adcx %%rax, %%rbx ;" ++ "movq 8(%1), %%rdx ;" /* A[1] */ ++ "adcx %%r15, %%r13 ;" ++ "mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */ ++ "movq $0, %%r14 ;" ++ /******************************************/ ++ "adcx %%r15, %%r14 ;" ++ ++ "xorl %%r15d, %%r15d;" ++ "adox %%rax, %%r10 ;" ++ "adcx %%r8, %%r8 ;" ++ "adox %%rcx, %%r11 ;" ++ "adcx %%r9, %%r9 ;" ++ "adox %%r15, %%rbx ;" ++ "adcx %%r10, %%r10 ;" ++ "adox %%r15, %%r13 ;" ++ "adcx %%r11, %%r11 ;" ++ "adox %%r15, %%r14 ;" ++ "adcx %%rbx, %%rbx ;" ++ "adcx %%r13, %%r13 ;" ++ "adcx %%r14, %%r14 ;" ++ ++ "movq (%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */ ++ /*******************/ ++ "movq %%rax, 0(%0) ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "movq 8(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */ ++ "adcq %%rax, %%r9 ;" ++ "movq %%r9, 16(%0) ;" ++ "adcq %%rcx, %%r10 ;" ++ "movq %%r10, 24(%0) ;" ++ "movq 16(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */ ++ "adcq %%rax, %%r11 ;" ++ "movq %%r11, 32(%0) ;" ++ "adcq %%rcx, %%rbx ;" ++ "movq %%rbx, 40(%0) ;" ++ "movq 24(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */ ++ "adcq %%rax, %%r13 ;" ++ "movq %%r13, 48(%0) ;" ++ "adcq %%rcx, %%r14 ;" ++ "movq %%r14, 56(%0) ;" ++ ++ ++ "movq 32(%1), %%rdx ;" /* B[0] */ ++ "mulx 40(%1), %%r8, %%r14 ;" /* B[1]*B[0] */ ++ "xorl %%r15d, %%r15d;" ++ "mulx 48(%1), %%r9, %%r10 ;" /* B[2]*B[0] */ ++ "adcx %%r14, %%r9 ;" ++ "mulx 56(%1), %%rax, %%rcx ;" /* B[3]*B[0] */ ++ "adcx %%rax, %%r10 ;" ++ "movq 56(%1), %%rdx ;" /* B[3] */ ++ "mulx 40(%1), %%r11, %%rbx ;" /* B[1]*B[3] */ ++ "adcx %%rcx, %%r11 ;" ++ "mulx 48(%1), %%rax, %%r13 ;" /* B[2]*B[3] */ ++ "adcx %%rax, %%rbx ;" ++ "movq 40(%1), %%rdx ;" /* B[1] */ ++ "adcx %%r15, %%r13 ;" ++ "mulx 48(%1), %%rax, %%rcx ;" /* B[2]*B[1] */ ++ "movq $0, %%r14 ;" ++ /******************************************/ ++ "adcx %%r15, %%r14 ;" ++ ++ "xorl %%r15d, %%r15d;" ++ "adox %%rax, %%r10 ;" ++ "adcx %%r8, %%r8 ;" ++ "adox %%rcx, %%r11 ;" ++ "adcx %%r9, %%r9 ;" ++ "adox %%r15, %%rbx ;" ++ "adcx %%r10, %%r10 ;" ++ "adox %%r15, %%r13 ;" ++ "adcx %%r11, %%r11 ;" ++ "adox %%r15, %%r14 ;" ++ "adcx %%rbx, %%rbx ;" ++ "adcx %%r13, %%r13 ;" ++ "adcx %%r14, %%r14 ;" ++ ++ "movq 32(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* B[0]^2 */ ++ /*******************/ ++ "movq %%rax, 64(%0) ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 72(%0) ;" ++ "movq 40(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* B[1]^2 */ ++ "adcq %%rax, %%r9 ;" ++ "movq %%r9, 80(%0) ;" ++ "adcq %%rcx, %%r10 ;" ++ "movq %%r10, 88(%0) ;" ++ "movq 48(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* B[2]^2 */ ++ "adcq %%rax, %%r11 ;" ++ "movq %%r11, 96(%0) ;" ++ "adcq %%rcx, %%rbx ;" ++ "movq %%rbx, 104(%0) ;" ++ "movq 56(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* B[3]^2 */ ++ "adcq %%rax, %%r13 ;" ++ "movq %%r13, 112(%0) ;" ++ "adcq %%rcx, %%r14 ;" ++ "movq %%r14, 120(%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", ++ "%r10", "%r11", "%r13", "%r14", "%r15"); ++} ++ ++static void sqr2_256x256_integer_bmi2(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movq 8(%1), %%rdx ;" /* A[1] */ ++ "mulx (%1), %%r8, %%r9 ;" /* A[0]*A[1] */ ++ "mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */ ++ "mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */ ++ ++ "movq 16(%1), %%rdx ;" /* A[2] */ ++ "mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */ ++ "mulx (%1), %%rax, %%rdx ;" /* A[0]*A[2] */ ++ ++ "addq %%rax, %%r9 ;" ++ "adcq %%rdx, %%r10 ;" ++ "adcq %%rcx, %%r11 ;" ++ "adcq %%r14, %%r15 ;" ++ "adcq $0, %%r13 ;" ++ "movq $0, %%r14 ;" ++ "adcq $0, %%r14 ;" ++ ++ "movq (%1), %%rdx ;" /* A[0] */ ++ "mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */ ++ ++ "addq %%rax, %%r10 ;" ++ "adcq %%rcx, %%r11 ;" ++ "adcq $0, %%r15 ;" ++ "adcq $0, %%r13 ;" ++ "adcq $0, %%r14 ;" ++ ++ "shldq $1, %%r13, %%r14 ;" ++ "shldq $1, %%r15, %%r13 ;" ++ "shldq $1, %%r11, %%r15 ;" ++ "shldq $1, %%r10, %%r11 ;" ++ "shldq $1, %%r9, %%r10 ;" ++ "shldq $1, %%r8, %%r9 ;" ++ "shlq $1, %%r8 ;" ++ ++ /*******************/ ++ "mulx %%rdx, %%rax, %%rcx ; " /* A[0]^2 */ ++ /*******************/ ++ "movq %%rax, 0(%0) ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "movq 8(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ; " /* A[1]^2 */ ++ "adcq %%rax, %%r9 ;" ++ "movq %%r9, 16(%0) ;" ++ "adcq %%rcx, %%r10 ;" ++ "movq %%r10, 24(%0) ;" ++ "movq 16(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ; " /* A[2]^2 */ ++ "adcq %%rax, %%r11 ;" ++ "movq %%r11, 32(%0) ;" ++ "adcq %%rcx, %%r15 ;" ++ "movq %%r15, 40(%0) ;" ++ "movq 24(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ; " /* A[3]^2 */ ++ "adcq %%rax, %%r13 ;" ++ "movq %%r13, 48(%0) ;" ++ "adcq %%rcx, %%r14 ;" ++ "movq %%r14, 56(%0) ;" ++ ++ "movq 40(%1), %%rdx ;" /* B[1] */ ++ "mulx 32(%1), %%r8, %%r9 ;" /* B[0]*B[1] */ ++ "mulx 48(%1), %%r10, %%r11 ;" /* B[2]*B[1] */ ++ "mulx 56(%1), %%rcx, %%r14 ;" /* B[3]*B[1] */ ++ ++ "movq 48(%1), %%rdx ;" /* B[2] */ ++ "mulx 56(%1), %%r15, %%r13 ;" /* B[3]*B[2] */ ++ "mulx 32(%1), %%rax, %%rdx ;" /* B[0]*B[2] */ ++ ++ "addq %%rax, %%r9 ;" ++ "adcq %%rdx, %%r10 ;" ++ "adcq %%rcx, %%r11 ;" ++ "adcq %%r14, %%r15 ;" ++ "adcq $0, %%r13 ;" ++ "movq $0, %%r14 ;" ++ "adcq $0, %%r14 ;" ++ ++ "movq 32(%1), %%rdx ;" /* B[0] */ ++ "mulx 56(%1), %%rax, %%rcx ;" /* B[0]*B[3] */ ++ ++ "addq %%rax, %%r10 ;" ++ "adcq %%rcx, %%r11 ;" ++ "adcq $0, %%r15 ;" ++ "adcq $0, %%r13 ;" ++ "adcq $0, %%r14 ;" ++ ++ "shldq $1, %%r13, %%r14 ;" ++ "shldq $1, %%r15, %%r13 ;" ++ "shldq $1, %%r11, %%r15 ;" ++ "shldq $1, %%r10, %%r11 ;" ++ "shldq $1, %%r9, %%r10 ;" ++ "shldq $1, %%r8, %%r9 ;" ++ "shlq $1, %%r8 ;" ++ ++ /*******************/ ++ "mulx %%rdx, %%rax, %%rcx ; " /* B[0]^2 */ ++ /*******************/ ++ "movq %%rax, 64(%0) ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 72(%0) ;" ++ "movq 40(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ; " /* B[1]^2 */ ++ "adcq %%rax, %%r9 ;" ++ "movq %%r9, 80(%0) ;" ++ "adcq %%rcx, %%r10 ;" ++ "movq %%r10, 88(%0) ;" ++ "movq 48(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ; " /* B[2]^2 */ ++ "adcq %%rax, %%r11 ;" ++ "movq %%r11, 96(%0) ;" ++ "adcq %%rcx, %%r15 ;" ++ "movq %%r15, 104(%0) ;" ++ "movq 56(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ; " /* B[3]^2 */ ++ "adcq %%rax, %%r13 ;" ++ "movq %%r13, 112(%0) ;" ++ "adcq %%rcx, %%r14 ;" ++ "movq %%r14, 120(%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", ++ "%r11", "%r13", "%r14", "%r15"); ++} ++ ++static void red_eltfp25519_2w_adx(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movl $38, %%edx; " /* 2*c = 38 = 2^256 */ ++ "mulx 32(%1), %%r8, %%r10; " /* c*C[4] */ ++ "xorl %%ebx, %%ebx ;" ++ "adox (%1), %%r8 ;" ++ "mulx 40(%1), %%r9, %%r11; " /* c*C[5] */ ++ "adcx %%r10, %%r9 ;" ++ "adox 8(%1), %%r9 ;" ++ "mulx 48(%1), %%r10, %%rax; " /* c*C[6] */ ++ "adcx %%r11, %%r10 ;" ++ "adox 16(%1), %%r10 ;" ++ "mulx 56(%1), %%r11, %%rcx; " /* c*C[7] */ ++ "adcx %%rax, %%r11 ;" ++ "adox 24(%1), %%r11 ;" ++ /***************************************/ ++ "adcx %%rbx, %%rcx ;" ++ "adox %%rbx, %%rcx ;" ++ "imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */ ++ "adcx %%rcx, %%r8 ;" ++ "adcx %%rbx, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "adcx %%rbx, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "adcx %%rbx, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%edx, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ ++ "mulx 96(%1), %%r8, %%r10; " /* c*C[4] */ ++ "xorl %%ebx, %%ebx ;" ++ "adox 64(%1), %%r8 ;" ++ "mulx 104(%1), %%r9, %%r11; " /* c*C[5] */ ++ "adcx %%r10, %%r9 ;" ++ "adox 72(%1), %%r9 ;" ++ "mulx 112(%1), %%r10, %%rax; " /* c*C[6] */ ++ "adcx %%r11, %%r10 ;" ++ "adox 80(%1), %%r10 ;" ++ "mulx 120(%1), %%r11, %%rcx; " /* c*C[7] */ ++ "adcx %%rax, %%r11 ;" ++ "adox 88(%1), %%r11 ;" ++ /****************************************/ ++ "adcx %%rbx, %%rcx ;" ++ "adox %%rbx, %%rcx ;" ++ "imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */ ++ "adcx %%rcx, %%r8 ;" ++ "adcx %%rbx, %%r9 ;" ++ "movq %%r9, 40(%0) ;" ++ "adcx %%rbx, %%r10 ;" ++ "movq %%r10, 48(%0) ;" ++ "adcx %%rbx, %%r11 ;" ++ "movq %%r11, 56(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%edx, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 32(%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", ++ "%r10", "%r11"); ++} ++ ++static void red_eltfp25519_2w_bmi2(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movl $38, %%edx ; " /* 2*c = 38 = 2^256 */ ++ "mulx 32(%1), %%r8, %%r10 ;" /* c*C[4] */ ++ "mulx 40(%1), %%r9, %%r11 ;" /* c*C[5] */ ++ "addq %%r10, %%r9 ;" ++ "mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */ ++ "adcq %%r11, %%r10 ;" ++ "mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */ ++ "adcq %%rax, %%r11 ;" ++ /***************************************/ ++ "adcq $0, %%rcx ;" ++ "addq (%1), %%r8 ;" ++ "adcq 8(%1), %%r9 ;" ++ "adcq 16(%1), %%r10 ;" ++ "adcq 24(%1), %%r11 ;" ++ "adcq $0, %%rcx ;" ++ "imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */ ++ "addq %%rcx, %%r8 ;" ++ "adcq $0, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "adcq $0, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "adcq $0, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%edx, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ ++ "mulx 96(%1), %%r8, %%r10 ;" /* c*C[4] */ ++ "mulx 104(%1), %%r9, %%r11 ;" /* c*C[5] */ ++ "addq %%r10, %%r9 ;" ++ "mulx 112(%1), %%r10, %%rax ;" /* c*C[6] */ ++ "adcq %%r11, %%r10 ;" ++ "mulx 120(%1), %%r11, %%rcx ;" /* c*C[7] */ ++ "adcq %%rax, %%r11 ;" ++ /****************************************/ ++ "adcq $0, %%rcx ;" ++ "addq 64(%1), %%r8 ;" ++ "adcq 72(%1), %%r9 ;" ++ "adcq 80(%1), %%r10 ;" ++ "adcq 88(%1), %%r11 ;" ++ "adcq $0, %%rcx ;" ++ "imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */ ++ "addq %%rcx, %%r8 ;" ++ "adcq $0, %%r9 ;" ++ "movq %%r9, 40(%0) ;" ++ "adcq $0, %%r10 ;" ++ "movq %%r10, 48(%0) ;" ++ "adcq $0, %%r11 ;" ++ "movq %%r11, 56(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%edx, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 32(%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", ++ "%r11"); ++} ++ ++static void mul_256x256_integer_adx(u64 *const c, const u64 *const a, ++ const u64 *const b) ++{ ++ asm volatile( ++ "movq (%1), %%rdx; " /* A[0] */ ++ "mulx (%2), %%r8, %%r9; " /* A[0]*B[0] */ ++ "xorl %%r10d, %%r10d ;" ++ "movq %%r8, (%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[0]*B[1] */ ++ "adox %%r9, %%r10 ;" ++ "movq %%r10, 8(%0) ;" ++ "mulx 16(%2), %%r15, %%r13; " /* A[0]*B[2] */ ++ "adox %%r11, %%r15 ;" ++ "mulx 24(%2), %%r14, %%rdx; " /* A[0]*B[3] */ ++ "adox %%r13, %%r14 ;" ++ "movq $0, %%rax ;" ++ /******************************************/ ++ "adox %%rdx, %%rax ;" ++ ++ "movq 8(%1), %%rdx; " /* A[1] */ ++ "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ ++ "xorl %%r10d, %%r10d ;" ++ "adcx 8(%0), %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ ++ "adox %%r9, %%r10 ;" ++ "adcx %%r15, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "mulx 16(%2), %%r15, %%r13; " /* A[1]*B[2] */ ++ "adox %%r11, %%r15 ;" ++ "adcx %%r14, %%r15 ;" ++ "movq $0, %%r8 ;" ++ "mulx 24(%2), %%r14, %%rdx; " /* A[1]*B[3] */ ++ "adox %%r13, %%r14 ;" ++ "adcx %%rax, %%r14 ;" ++ "movq $0, %%rax ;" ++ /******************************************/ ++ "adox %%rdx, %%rax ;" ++ "adcx %%r8, %%rax ;" ++ ++ "movq 16(%1), %%rdx; " /* A[2] */ ++ "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ ++ "xorl %%r10d, %%r10d ;" ++ "adcx 16(%0), %%r8 ;" ++ "movq %%r8, 16(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ ++ "adox %%r9, %%r10 ;" ++ "adcx %%r15, %%r10 ;" ++ "movq %%r10, 24(%0) ;" ++ "mulx 16(%2), %%r15, %%r13; " /* A[2]*B[2] */ ++ "adox %%r11, %%r15 ;" ++ "adcx %%r14, %%r15 ;" ++ "movq $0, %%r8 ;" ++ "mulx 24(%2), %%r14, %%rdx; " /* A[2]*B[3] */ ++ "adox %%r13, %%r14 ;" ++ "adcx %%rax, %%r14 ;" ++ "movq $0, %%rax ;" ++ /******************************************/ ++ "adox %%rdx, %%rax ;" ++ "adcx %%r8, %%rax ;" ++ ++ "movq 24(%1), %%rdx; " /* A[3] */ ++ "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ ++ "xorl %%r10d, %%r10d ;" ++ "adcx 24(%0), %%r8 ;" ++ "movq %%r8, 24(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ ++ "adox %%r9, %%r10 ;" ++ "adcx %%r15, %%r10 ;" ++ "movq %%r10, 32(%0) ;" ++ "mulx 16(%2), %%r15, %%r13; " /* A[3]*B[2] */ ++ "adox %%r11, %%r15 ;" ++ "adcx %%r14, %%r15 ;" ++ "movq %%r15, 40(%0) ;" ++ "movq $0, %%r8 ;" ++ "mulx 24(%2), %%r14, %%rdx; " /* A[3]*B[3] */ ++ "adox %%r13, %%r14 ;" ++ "adcx %%rax, %%r14 ;" ++ "movq %%r14, 48(%0) ;" ++ "movq $0, %%rax ;" ++ /******************************************/ ++ "adox %%rdx, %%rax ;" ++ "adcx %%r8, %%rax ;" ++ "movq %%rax, 56(%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(b) ++ : "memory", "cc", "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", ++ "%r13", "%r14", "%r15"); ++} ++ ++static void mul_256x256_integer_bmi2(u64 *const c, const u64 *const a, ++ const u64 *const b) ++{ ++ asm volatile( ++ "movq (%1), %%rdx; " /* A[0] */ ++ "mulx (%2), %%r8, %%r15; " /* A[0]*B[0] */ ++ "movq %%r8, (%0) ;" ++ "mulx 8(%2), %%r10, %%rax; " /* A[0]*B[1] */ ++ "addq %%r10, %%r15 ;" ++ "mulx 16(%2), %%r8, %%rbx; " /* A[0]*B[2] */ ++ "adcq %%r8, %%rax ;" ++ "mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */ ++ "adcq %%r10, %%rbx ;" ++ /******************************************/ ++ "adcq $0, %%rcx ;" ++ ++ "movq 8(%1), %%rdx; " /* A[1] */ ++ "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ ++ "addq %%r15, %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[1]*B[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%r15 ;" ++ ++ "addq %%r9, %%rax ;" ++ "adcq %%r11, %%rbx ;" ++ "adcq %%r13, %%rcx ;" ++ "adcq $0, %%r15 ;" ++ ++ "movq 16(%1), %%rdx; " /* A[2] */ ++ "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ ++ "addq %%rax, %%r8 ;" ++ "movq %%r8, 16(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[2]*B[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%rax ;" ++ ++ "addq %%r9, %%rbx ;" ++ "adcq %%r11, %%rcx ;" ++ "adcq %%r13, %%r15 ;" ++ "adcq $0, %%rax ;" ++ ++ "movq 24(%1), %%rdx; " /* A[3] */ ++ "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ ++ "addq %%rbx, %%r8 ;" ++ "movq %%r8, 24(%0) ;" ++ "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ ++ "adcq %%r10, %%r9 ;" ++ "mulx 16(%2), %%r8, %%r13; " /* A[3]*B[2] */ ++ "adcq %%r8, %%r11 ;" ++ "mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */ ++ "adcq %%r10, %%r13 ;" ++ /******************************************/ ++ "adcq $0, %%rbx ;" ++ ++ "addq %%r9, %%rcx ;" ++ "movq %%rcx, 32(%0) ;" ++ "adcq %%r11, %%r15 ;" ++ "movq %%r15, 40(%0) ;" ++ "adcq %%r13, %%rax ;" ++ "movq %%rax, 48(%0) ;" ++ "adcq $0, %%rbx ;" ++ "movq %%rbx, 56(%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(b) ++ : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", ++ "%r10", "%r11", "%r13", "%r15"); ++} ++ ++static void sqr_256x256_integer_adx(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movq (%1), %%rdx ;" /* A[0] */ ++ "mulx 8(%1), %%r8, %%r14 ;" /* A[1]*A[0] */ ++ "xorl %%r15d, %%r15d;" ++ "mulx 16(%1), %%r9, %%r10 ;" /* A[2]*A[0] */ ++ "adcx %%r14, %%r9 ;" ++ "mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */ ++ "adcx %%rax, %%r10 ;" ++ "movq 24(%1), %%rdx ;" /* A[3] */ ++ "mulx 8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */ ++ "adcx %%rcx, %%r11 ;" ++ "mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */ ++ "adcx %%rax, %%rbx ;" ++ "movq 8(%1), %%rdx ;" /* A[1] */ ++ "adcx %%r15, %%r13 ;" ++ "mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */ ++ "movq $0, %%r14 ;" ++ /******************************************/ ++ "adcx %%r15, %%r14 ;" ++ ++ "xorl %%r15d, %%r15d;" ++ "adox %%rax, %%r10 ;" ++ "adcx %%r8, %%r8 ;" ++ "adox %%rcx, %%r11 ;" ++ "adcx %%r9, %%r9 ;" ++ "adox %%r15, %%rbx ;" ++ "adcx %%r10, %%r10 ;" ++ "adox %%r15, %%r13 ;" ++ "adcx %%r11, %%r11 ;" ++ "adox %%r15, %%r14 ;" ++ "adcx %%rbx, %%rbx ;" ++ "adcx %%r13, %%r13 ;" ++ "adcx %%r14, %%r14 ;" ++ ++ "movq (%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */ ++ /*******************/ ++ "movq %%rax, 0(%0) ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "movq 8(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */ ++ "adcq %%rax, %%r9 ;" ++ "movq %%r9, 16(%0) ;" ++ "adcq %%rcx, %%r10 ;" ++ "movq %%r10, 24(%0) ;" ++ "movq 16(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */ ++ "adcq %%rax, %%r11 ;" ++ "movq %%r11, 32(%0) ;" ++ "adcq %%rcx, %%rbx ;" ++ "movq %%rbx, 40(%0) ;" ++ "movq 24(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */ ++ "adcq %%rax, %%r13 ;" ++ "movq %%r13, 48(%0) ;" ++ "adcq %%rcx, %%r14 ;" ++ "movq %%r14, 56(%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", ++ "%r10", "%r11", "%r13", "%r14", "%r15"); ++} ++ ++static void sqr_256x256_integer_bmi2(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movq 8(%1), %%rdx ;" /* A[1] */ ++ "mulx (%1), %%r8, %%r9 ;" /* A[0]*A[1] */ ++ "mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */ ++ "mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */ ++ ++ "movq 16(%1), %%rdx ;" /* A[2] */ ++ "mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */ ++ "mulx (%1), %%rax, %%rdx ;" /* A[0]*A[2] */ ++ ++ "addq %%rax, %%r9 ;" ++ "adcq %%rdx, %%r10 ;" ++ "adcq %%rcx, %%r11 ;" ++ "adcq %%r14, %%r15 ;" ++ "adcq $0, %%r13 ;" ++ "movq $0, %%r14 ;" ++ "adcq $0, %%r14 ;" ++ ++ "movq (%1), %%rdx ;" /* A[0] */ ++ "mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */ ++ ++ "addq %%rax, %%r10 ;" ++ "adcq %%rcx, %%r11 ;" ++ "adcq $0, %%r15 ;" ++ "adcq $0, %%r13 ;" ++ "adcq $0, %%r14 ;" ++ ++ "shldq $1, %%r13, %%r14 ;" ++ "shldq $1, %%r15, %%r13 ;" ++ "shldq $1, %%r11, %%r15 ;" ++ "shldq $1, %%r10, %%r11 ;" ++ "shldq $1, %%r9, %%r10 ;" ++ "shldq $1, %%r8, %%r9 ;" ++ "shlq $1, %%r8 ;" ++ ++ /*******************/ ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */ ++ /*******************/ ++ "movq %%rax, 0(%0) ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, 8(%0) ;" ++ "movq 8(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */ ++ "adcq %%rax, %%r9 ;" ++ "movq %%r9, 16(%0) ;" ++ "adcq %%rcx, %%r10 ;" ++ "movq %%r10, 24(%0) ;" ++ "movq 16(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */ ++ "adcq %%rax, %%r11 ;" ++ "movq %%r11, 32(%0) ;" ++ "adcq %%rcx, %%r15 ;" ++ "movq %%r15, 40(%0) ;" ++ "movq 24(%1), %%rdx ;" ++ "mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */ ++ "adcq %%rax, %%r13 ;" ++ "movq %%r13, 48(%0) ;" ++ "adcq %%rcx, %%r14 ;" ++ "movq %%r14, 56(%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", ++ "%r11", "%r13", "%r14", "%r15"); ++} ++ ++static void red_eltfp25519_1w_adx(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movl $38, %%edx ;" /* 2*c = 38 = 2^256 */ ++ "mulx 32(%1), %%r8, %%r10 ;" /* c*C[4] */ ++ "xorl %%ebx, %%ebx ;" ++ "adox (%1), %%r8 ;" ++ "mulx 40(%1), %%r9, %%r11 ;" /* c*C[5] */ ++ "adcx %%r10, %%r9 ;" ++ "adox 8(%1), %%r9 ;" ++ "mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */ ++ "adcx %%r11, %%r10 ;" ++ "adox 16(%1), %%r10 ;" ++ "mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */ ++ "adcx %%rax, %%r11 ;" ++ "adox 24(%1), %%r11 ;" ++ /***************************************/ ++ "adcx %%rbx, %%rcx ;" ++ "adox %%rbx, %%rcx ;" ++ "imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */ ++ "adcx %%rcx, %%r8 ;" ++ "adcx %%rbx, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "adcx %%rbx, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "adcx %%rbx, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%edx, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", ++ "%r10", "%r11"); ++} ++ ++static void red_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a) ++{ ++ asm volatile( ++ "movl $38, %%edx ;" /* 2*c = 38 = 2^256 */ ++ "mulx 32(%1), %%r8, %%r10 ;" /* c*C[4] */ ++ "mulx 40(%1), %%r9, %%r11 ;" /* c*C[5] */ ++ "addq %%r10, %%r9 ;" ++ "mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */ ++ "adcq %%r11, %%r10 ;" ++ "mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */ ++ "adcq %%rax, %%r11 ;" ++ /***************************************/ ++ "adcq $0, %%rcx ;" ++ "addq (%1), %%r8 ;" ++ "adcq 8(%1), %%r9 ;" ++ "adcq 16(%1), %%r10 ;" ++ "adcq 24(%1), %%r11 ;" ++ "adcq $0, %%rcx ;" ++ "imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */ ++ "addq %%rcx, %%r8 ;" ++ "adcq $0, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "adcq $0, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "adcq $0, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%edx, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ : ++ : "r"(c), "r"(a) ++ : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", ++ "%r11"); ++} ++ ++static __always_inline void ++add_eltfp25519_1w_adx(u64 *const c, const u64 *const a, const u64 *const b) ++{ ++ asm volatile( ++ "mov $38, %%eax ;" ++ "xorl %%ecx, %%ecx ;" ++ "movq (%2), %%r8 ;" ++ "adcx (%1), %%r8 ;" ++ "movq 8(%2), %%r9 ;" ++ "adcx 8(%1), %%r9 ;" ++ "movq 16(%2), %%r10 ;" ++ "adcx 16(%1), %%r10 ;" ++ "movq 24(%2), %%r11 ;" ++ "adcx 24(%1), %%r11 ;" ++ "cmovc %%eax, %%ecx ;" ++ "xorl %%eax, %%eax ;" ++ "adcx %%rcx, %%r8 ;" ++ "adcx %%rax, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "adcx %%rax, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "adcx %%rax, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $38, %%ecx ;" ++ "cmovc %%ecx, %%eax ;" ++ "addq %%rax, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(b) ++ : "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11"); ++} ++ ++static __always_inline void ++add_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a, const u64 *const b) ++{ ++ asm volatile( ++ "mov $38, %%eax ;" ++ "movq (%2), %%r8 ;" ++ "addq (%1), %%r8 ;" ++ "movq 8(%2), %%r9 ;" ++ "adcq 8(%1), %%r9 ;" ++ "movq 16(%2), %%r10 ;" ++ "adcq 16(%1), %%r10 ;" ++ "movq 24(%2), %%r11 ;" ++ "adcq 24(%1), %%r11 ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%eax, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "adcq $0, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "adcq $0, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "adcq $0, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%eax, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(b) ++ : "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11"); ++} ++ ++static __always_inline void ++sub_eltfp25519_1w(u64 *const c, const u64 *const a, const u64 *const b) ++{ ++ asm volatile( ++ "mov $38, %%eax ;" ++ "movq (%1), %%r8 ;" ++ "subq (%2), %%r8 ;" ++ "movq 8(%1), %%r9 ;" ++ "sbbq 8(%2), %%r9 ;" ++ "movq 16(%1), %%r10 ;" ++ "sbbq 16(%2), %%r10 ;" ++ "movq 24(%1), %%r11 ;" ++ "sbbq 24(%2), %%r11 ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%eax, %%ecx ;" ++ "subq %%rcx, %%r8 ;" ++ "sbbq $0, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "sbbq $0, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "sbbq $0, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%eax, %%ecx ;" ++ "subq %%rcx, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(b) ++ : "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11"); ++} ++ ++/* Multiplication by a24 = (A+2)/4 = (486662+2)/4 = 121666 */ ++static __always_inline void ++mul_a24_eltfp25519_1w(u64 *const c, const u64 *const a) ++{ ++ const u64 a24 = 121666; ++ asm volatile( ++ "movq %2, %%rdx ;" ++ "mulx (%1), %%r8, %%r10 ;" ++ "mulx 8(%1), %%r9, %%r11 ;" ++ "addq %%r10, %%r9 ;" ++ "mulx 16(%1), %%r10, %%rax ;" ++ "adcq %%r11, %%r10 ;" ++ "mulx 24(%1), %%r11, %%rcx ;" ++ "adcq %%rax, %%r11 ;" ++ /**************************/ ++ "adcq $0, %%rcx ;" ++ "movl $38, %%edx ;" /* 2*c = 38 = 2^256 mod 2^255-19*/ ++ "imul %%rdx, %%rcx ;" ++ "addq %%rcx, %%r8 ;" ++ "adcq $0, %%r9 ;" ++ "movq %%r9, 8(%0) ;" ++ "adcq $0, %%r10 ;" ++ "movq %%r10, 16(%0) ;" ++ "adcq $0, %%r11 ;" ++ "movq %%r11, 24(%0) ;" ++ "mov $0, %%ecx ;" ++ "cmovc %%edx, %%ecx ;" ++ "addq %%rcx, %%r8 ;" ++ "movq %%r8, (%0) ;" ++ : ++ : "r"(c), "r"(a), "r"(a24) ++ : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", ++ "%r11"); ++} ++ ++static void inv_eltfp25519_1w_adx(u64 *const c, const u64 *const a) ++{ ++ struct { ++ eltfp25519_1w_buffer buffer; ++ eltfp25519_1w x0, x1, x2; ++ } __aligned(32) m; ++ u64 *T[4]; ++ ++ T[0] = m.x0; ++ T[1] = c; /* x^(-1) */ ++ T[2] = m.x1; ++ T[3] = m.x2; ++ ++ copy_eltfp25519_1w(T[1], a); ++ sqrn_eltfp25519_1w_adx(T[1], 1); ++ copy_eltfp25519_1w(T[2], T[1]); ++ sqrn_eltfp25519_1w_adx(T[2], 2); ++ mul_eltfp25519_1w_adx(T[0], a, T[2]); ++ mul_eltfp25519_1w_adx(T[1], T[1], T[0]); ++ copy_eltfp25519_1w(T[2], T[1]); ++ sqrn_eltfp25519_1w_adx(T[2], 1); ++ mul_eltfp25519_1w_adx(T[0], T[0], T[2]); ++ copy_eltfp25519_1w(T[2], T[0]); ++ sqrn_eltfp25519_1w_adx(T[2], 5); ++ mul_eltfp25519_1w_adx(T[0], T[0], T[2]); ++ copy_eltfp25519_1w(T[2], T[0]); ++ sqrn_eltfp25519_1w_adx(T[2], 10); ++ mul_eltfp25519_1w_adx(T[2], T[2], T[0]); ++ copy_eltfp25519_1w(T[3], T[2]); ++ sqrn_eltfp25519_1w_adx(T[3], 20); ++ mul_eltfp25519_1w_adx(T[3], T[3], T[2]); ++ sqrn_eltfp25519_1w_adx(T[3], 10); ++ mul_eltfp25519_1w_adx(T[3], T[3], T[0]); ++ copy_eltfp25519_1w(T[0], T[3]); ++ sqrn_eltfp25519_1w_adx(T[0], 50); ++ mul_eltfp25519_1w_adx(T[0], T[0], T[3]); ++ copy_eltfp25519_1w(T[2], T[0]); ++ sqrn_eltfp25519_1w_adx(T[2], 100); ++ mul_eltfp25519_1w_adx(T[2], T[2], T[0]); ++ sqrn_eltfp25519_1w_adx(T[2], 50); ++ mul_eltfp25519_1w_adx(T[2], T[2], T[3]); ++ sqrn_eltfp25519_1w_adx(T[2], 5); ++ mul_eltfp25519_1w_adx(T[1], T[1], T[2]); ++ ++ memzero_explicit(&m, sizeof(m)); ++} ++ ++static void inv_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a) ++{ ++ struct { ++ eltfp25519_1w_buffer buffer; ++ eltfp25519_1w x0, x1, x2; ++ } __aligned(32) m; ++ u64 *T[5]; ++ ++ T[0] = m.x0; ++ T[1] = c; /* x^(-1) */ ++ T[2] = m.x1; ++ T[3] = m.x2; ++ ++ copy_eltfp25519_1w(T[1], a); ++ sqrn_eltfp25519_1w_bmi2(T[1], 1); ++ copy_eltfp25519_1w(T[2], T[1]); ++ sqrn_eltfp25519_1w_bmi2(T[2], 2); ++ mul_eltfp25519_1w_bmi2(T[0], a, T[2]); ++ mul_eltfp25519_1w_bmi2(T[1], T[1], T[0]); ++ copy_eltfp25519_1w(T[2], T[1]); ++ sqrn_eltfp25519_1w_bmi2(T[2], 1); ++ mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]); ++ copy_eltfp25519_1w(T[2], T[0]); ++ sqrn_eltfp25519_1w_bmi2(T[2], 5); ++ mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]); ++ copy_eltfp25519_1w(T[2], T[0]); ++ sqrn_eltfp25519_1w_bmi2(T[2], 10); ++ mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]); ++ copy_eltfp25519_1w(T[3], T[2]); ++ sqrn_eltfp25519_1w_bmi2(T[3], 20); ++ mul_eltfp25519_1w_bmi2(T[3], T[3], T[2]); ++ sqrn_eltfp25519_1w_bmi2(T[3], 10); ++ mul_eltfp25519_1w_bmi2(T[3], T[3], T[0]); ++ copy_eltfp25519_1w(T[0], T[3]); ++ sqrn_eltfp25519_1w_bmi2(T[0], 50); ++ mul_eltfp25519_1w_bmi2(T[0], T[0], T[3]); ++ copy_eltfp25519_1w(T[2], T[0]); ++ sqrn_eltfp25519_1w_bmi2(T[2], 100); ++ mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]); ++ sqrn_eltfp25519_1w_bmi2(T[2], 50); ++ mul_eltfp25519_1w_bmi2(T[2], T[2], T[3]); ++ sqrn_eltfp25519_1w_bmi2(T[2], 5); ++ mul_eltfp25519_1w_bmi2(T[1], T[1], T[2]); ++ ++ memzero_explicit(&m, sizeof(m)); ++} ++ ++/* Given c, a 256-bit number, fred_eltfp25519_1w updates c ++ * with a number such that 0 <= C < 2**255-19. ++ */ ++static __always_inline void fred_eltfp25519_1w(u64 *const c) ++{ ++ u64 tmp0 = 38, tmp1 = 19; ++ asm volatile( ++ "btrq $63, %3 ;" /* Put bit 255 in carry flag and clear */ ++ "cmovncl %k5, %k4 ;" /* c[255] ? 38 : 19 */ ++ ++ /* Add either 19 or 38 to c */ ++ "addq %4, %0 ;" ++ "adcq $0, %1 ;" ++ "adcq $0, %2 ;" ++ "adcq $0, %3 ;" ++ ++ /* Test for bit 255 again; only triggered on overflow modulo 2^255-19 */ ++ "movl $0, %k4 ;" ++ "cmovnsl %k5, %k4 ;" /* c[255] ? 0 : 19 */ ++ "btrq $63, %3 ;" /* Clear bit 255 */ ++ ++ /* Subtract 19 if necessary */ ++ "subq %4, %0 ;" ++ "sbbq $0, %1 ;" ++ "sbbq $0, %2 ;" ++ "sbbq $0, %3 ;" ++ ++ : "+r"(c[0]), "+r"(c[1]), "+r"(c[2]), "+r"(c[3]), "+r"(tmp0), ++ "+r"(tmp1) ++ : ++ : "memory", "cc"); ++} ++ ++static __always_inline void cswap(u8 bit, u64 *const px, u64 *const py) ++{ ++ u64 temp; ++ asm volatile( ++ "test %9, %9 ;" ++ "movq %0, %8 ;" ++ "cmovnzq %4, %0 ;" ++ "cmovnzq %8, %4 ;" ++ "movq %1, %8 ;" ++ "cmovnzq %5, %1 ;" ++ "cmovnzq %8, %5 ;" ++ "movq %2, %8 ;" ++ "cmovnzq %6, %2 ;" ++ "cmovnzq %8, %6 ;" ++ "movq %3, %8 ;" ++ "cmovnzq %7, %3 ;" ++ "cmovnzq %8, %7 ;" ++ : "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3]), ++ "+r"(py[0]), "+r"(py[1]), "+r"(py[2]), "+r"(py[3]), ++ "=r"(temp) ++ : "r"(bit) ++ : "cc" ++ ); ++} ++ ++static __always_inline void cselect(u8 bit, u64 *const px, const u64 *const py) ++{ ++ asm volatile( ++ "test %4, %4 ;" ++ "cmovnzq %5, %0 ;" ++ "cmovnzq %6, %1 ;" ++ "cmovnzq %7, %2 ;" ++ "cmovnzq %8, %3 ;" ++ : "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3]) ++ : "r"(bit), "rm"(py[0]), "rm"(py[1]), "rm"(py[2]), "rm"(py[3]) ++ : "cc" ++ ); ++} ++ ++static void curve25519_adx(u8 shared[CURVE25519_KEY_SIZE], ++ const u8 private_key[CURVE25519_KEY_SIZE], ++ const u8 session_key[CURVE25519_KEY_SIZE]) ++{ ++ struct { ++ u64 buffer[4 * NUM_WORDS_ELTFP25519]; ++ u64 coordinates[4 * NUM_WORDS_ELTFP25519]; ++ u64 workspace[6 * NUM_WORDS_ELTFP25519]; ++ u8 session[CURVE25519_KEY_SIZE]; ++ u8 private[CURVE25519_KEY_SIZE]; ++ } __aligned(32) m; ++ ++ int i = 0, j = 0; ++ u64 prev = 0; ++ u64 *const X1 = (u64 *)m.session; ++ u64 *const key = (u64 *)m.private; ++ u64 *const Px = m.coordinates + 0; ++ u64 *const Pz = m.coordinates + 4; ++ u64 *const Qx = m.coordinates + 8; ++ u64 *const Qz = m.coordinates + 12; ++ u64 *const X2 = Qx; ++ u64 *const Z2 = Qz; ++ u64 *const X3 = Px; ++ u64 *const Z3 = Pz; ++ u64 *const X2Z2 = Qx; ++ u64 *const X3Z3 = Px; ++ ++ u64 *const A = m.workspace + 0; ++ u64 *const B = m.workspace + 4; ++ u64 *const D = m.workspace + 8; ++ u64 *const C = m.workspace + 12; ++ u64 *const DA = m.workspace + 16; ++ u64 *const CB = m.workspace + 20; ++ u64 *const AB = A; ++ u64 *const DC = D; ++ u64 *const DACB = DA; ++ ++ memcpy(m.private, private_key, sizeof(m.private)); ++ memcpy(m.session, session_key, sizeof(m.session)); ++ ++ curve25519_clamp_secret(m.private); ++ ++ /* As in the draft: ++ * When receiving such an array, implementations of curve25519 ++ * MUST mask the most-significant bit in the final byte. This ++ * is done to preserve compatibility with point formats which ++ * reserve the sign bit for use in other protocols and to ++ * increase resistance to implementation fingerprinting ++ */ ++ m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1; ++ ++ copy_eltfp25519_1w(Px, X1); ++ setzero_eltfp25519_1w(Pz); ++ setzero_eltfp25519_1w(Qx); ++ setzero_eltfp25519_1w(Qz); ++ ++ Pz[0] = 1; ++ Qx[0] = 1; ++ ++ /* main-loop */ ++ prev = 0; ++ j = 62; ++ for (i = 3; i >= 0; --i) { ++ while (j >= 0) { ++ u64 bit = (key[i] >> j) & 0x1; ++ u64 swap = bit ^ prev; ++ prev = bit; ++ ++ add_eltfp25519_1w_adx(A, X2, Z2); /* A = (X2+Z2) */ ++ sub_eltfp25519_1w(B, X2, Z2); /* B = (X2-Z2) */ ++ add_eltfp25519_1w_adx(C, X3, Z3); /* C = (X3+Z3) */ ++ sub_eltfp25519_1w(D, X3, Z3); /* D = (X3-Z3) */ ++ mul_eltfp25519_2w_adx(DACB, AB, DC); /* [DA|CB] = [A|B]*[D|C] */ ++ ++ cselect(swap, A, C); ++ cselect(swap, B, D); ++ ++ sqr_eltfp25519_2w_adx(AB); /* [AA|BB] = [A^2|B^2] */ ++ add_eltfp25519_1w_adx(X3, DA, CB); /* X3 = (DA+CB) */ ++ sub_eltfp25519_1w(Z3, DA, CB); /* Z3 = (DA-CB) */ ++ sqr_eltfp25519_2w_adx(X3Z3); /* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */ ++ ++ copy_eltfp25519_1w(X2, B); /* X2 = B^2 */ ++ sub_eltfp25519_1w(Z2, A, B); /* Z2 = E = AA-BB */ ++ ++ mul_a24_eltfp25519_1w(B, Z2); /* B = a24*E */ ++ add_eltfp25519_1w_adx(B, B, X2); /* B = a24*E+B */ ++ mul_eltfp25519_2w_adx(X2Z2, X2Z2, AB); /* [X2|Z2] = [B|E]*[A|a24*E+B] */ ++ mul_eltfp25519_1w_adx(Z3, Z3, X1); /* Z3 = Z3*X1 */ ++ --j; ++ } ++ j = 63; ++ } ++ ++ inv_eltfp25519_1w_adx(A, Qz); ++ mul_eltfp25519_1w_adx((u64 *)shared, Qx, A); ++ fred_eltfp25519_1w((u64 *)shared); ++ ++ memzero_explicit(&m, sizeof(m)); ++} ++ ++static void curve25519_adx_base(u8 session_key[CURVE25519_KEY_SIZE], ++ const u8 private_key[CURVE25519_KEY_SIZE]) ++{ ++ struct { ++ u64 buffer[4 * NUM_WORDS_ELTFP25519]; ++ u64 coordinates[4 * NUM_WORDS_ELTFP25519]; ++ u64 workspace[4 * NUM_WORDS_ELTFP25519]; ++ u8 private[CURVE25519_KEY_SIZE]; ++ } __aligned(32) m; ++ ++ const int ite[4] = { 64, 64, 64, 63 }; ++ const int q = 3; ++ u64 swap = 1; ++ ++ int i = 0, j = 0, k = 0; ++ u64 *const key = (u64 *)m.private; ++ u64 *const Ur1 = m.coordinates + 0; ++ u64 *const Zr1 = m.coordinates + 4; ++ u64 *const Ur2 = m.coordinates + 8; ++ u64 *const Zr2 = m.coordinates + 12; ++ ++ u64 *const UZr1 = m.coordinates + 0; ++ u64 *const ZUr2 = m.coordinates + 8; ++ ++ u64 *const A = m.workspace + 0; ++ u64 *const B = m.workspace + 4; ++ u64 *const C = m.workspace + 8; ++ u64 *const D = m.workspace + 12; ++ ++ u64 *const AB = m.workspace + 0; ++ u64 *const CD = m.workspace + 8; ++ ++ const u64 *const P = table_ladder_8k; ++ ++ memcpy(m.private, private_key, sizeof(m.private)); ++ ++ curve25519_clamp_secret(m.private); ++ ++ setzero_eltfp25519_1w(Ur1); ++ setzero_eltfp25519_1w(Zr1); ++ setzero_eltfp25519_1w(Zr2); ++ Ur1[0] = 1; ++ Zr1[0] = 1; ++ Zr2[0] = 1; ++ ++ /* G-S */ ++ Ur2[3] = 0x1eaecdeee27cab34UL; ++ Ur2[2] = 0xadc7a0b9235d48e2UL; ++ Ur2[1] = 0xbbf095ae14b2edf8UL; ++ Ur2[0] = 0x7e94e1fec82faabdUL; ++ ++ /* main-loop */ ++ j = q; ++ for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) { ++ while (j < ite[i]) { ++ u64 bit = (key[i] >> j) & 0x1; ++ k = (64 * i + j - q); ++ swap = swap ^ bit; ++ cswap(swap, Ur1, Ur2); ++ cswap(swap, Zr1, Zr2); ++ swap = bit; ++ /* Addition */ ++ sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ ++ add_eltfp25519_1w_adx(A, Ur1, Zr1); /* A = Ur1+Zr1 */ ++ mul_eltfp25519_1w_adx(C, &P[4 * k], B); /* C = M0-B */ ++ sub_eltfp25519_1w(B, A, C); /* B = (Ur1+Zr1) - M*(Ur1-Zr1) */ ++ add_eltfp25519_1w_adx(A, A, C); /* A = (Ur1+Zr1) + M*(Ur1-Zr1) */ ++ sqr_eltfp25519_2w_adx(AB); /* A = A^2 | B = B^2 */ ++ mul_eltfp25519_2w_adx(UZr1, ZUr2, AB); /* Ur1 = Zr2*A | Zr1 = Ur2*B */ ++ ++j; ++ } ++ j = 0; ++ } ++ ++ /* Doubling */ ++ for (i = 0; i < q; ++i) { ++ add_eltfp25519_1w_adx(A, Ur1, Zr1); /* A = Ur1+Zr1 */ ++ sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ ++ sqr_eltfp25519_2w_adx(AB); /* A = A**2 B = B**2 */ ++ copy_eltfp25519_1w(C, B); /* C = B */ ++ sub_eltfp25519_1w(B, A, B); /* B = A-B */ ++ mul_a24_eltfp25519_1w(D, B); /* D = my_a24*B */ ++ add_eltfp25519_1w_adx(D, D, C); /* D = D+C */ ++ mul_eltfp25519_2w_adx(UZr1, AB, CD); /* Ur1 = A*B Zr1 = Zr1*A */ ++ } ++ ++ /* Convert to affine coordinates */ ++ inv_eltfp25519_1w_adx(A, Zr1); ++ mul_eltfp25519_1w_adx((u64 *)session_key, Ur1, A); ++ fred_eltfp25519_1w((u64 *)session_key); ++ ++ memzero_explicit(&m, sizeof(m)); ++} ++ ++static void curve25519_bmi2(u8 shared[CURVE25519_KEY_SIZE], ++ const u8 private_key[CURVE25519_KEY_SIZE], ++ const u8 session_key[CURVE25519_KEY_SIZE]) ++{ ++ struct { ++ u64 buffer[4 * NUM_WORDS_ELTFP25519]; ++ u64 coordinates[4 * NUM_WORDS_ELTFP25519]; ++ u64 workspace[6 * NUM_WORDS_ELTFP25519]; ++ u8 session[CURVE25519_KEY_SIZE]; ++ u8 private[CURVE25519_KEY_SIZE]; ++ } __aligned(32) m; ++ ++ int i = 0, j = 0; ++ u64 prev = 0; ++ u64 *const X1 = (u64 *)m.session; ++ u64 *const key = (u64 *)m.private; ++ u64 *const Px = m.coordinates + 0; ++ u64 *const Pz = m.coordinates + 4; ++ u64 *const Qx = m.coordinates + 8; ++ u64 *const Qz = m.coordinates + 12; ++ u64 *const X2 = Qx; ++ u64 *const Z2 = Qz; ++ u64 *const X3 = Px; ++ u64 *const Z3 = Pz; ++ u64 *const X2Z2 = Qx; ++ u64 *const X3Z3 = Px; ++ ++ u64 *const A = m.workspace + 0; ++ u64 *const B = m.workspace + 4; ++ u64 *const D = m.workspace + 8; ++ u64 *const C = m.workspace + 12; ++ u64 *const DA = m.workspace + 16; ++ u64 *const CB = m.workspace + 20; ++ u64 *const AB = A; ++ u64 *const DC = D; ++ u64 *const DACB = DA; ++ ++ memcpy(m.private, private_key, sizeof(m.private)); ++ memcpy(m.session, session_key, sizeof(m.session)); ++ ++ curve25519_clamp_secret(m.private); ++ ++ /* As in the draft: ++ * When receiving such an array, implementations of curve25519 ++ * MUST mask the most-significant bit in the final byte. This ++ * is done to preserve compatibility with point formats which ++ * reserve the sign bit for use in other protocols and to ++ * increase resistance to implementation fingerprinting ++ */ ++ m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1; ++ ++ copy_eltfp25519_1w(Px, X1); ++ setzero_eltfp25519_1w(Pz); ++ setzero_eltfp25519_1w(Qx); ++ setzero_eltfp25519_1w(Qz); ++ ++ Pz[0] = 1; ++ Qx[0] = 1; ++ ++ /* main-loop */ ++ prev = 0; ++ j = 62; ++ for (i = 3; i >= 0; --i) { ++ while (j >= 0) { ++ u64 bit = (key[i] >> j) & 0x1; ++ u64 swap = bit ^ prev; ++ prev = bit; ++ ++ add_eltfp25519_1w_bmi2(A, X2, Z2); /* A = (X2+Z2) */ ++ sub_eltfp25519_1w(B, X2, Z2); /* B = (X2-Z2) */ ++ add_eltfp25519_1w_bmi2(C, X3, Z3); /* C = (X3+Z3) */ ++ sub_eltfp25519_1w(D, X3, Z3); /* D = (X3-Z3) */ ++ mul_eltfp25519_2w_bmi2(DACB, AB, DC); /* [DA|CB] = [A|B]*[D|C] */ ++ ++ cselect(swap, A, C); ++ cselect(swap, B, D); ++ ++ sqr_eltfp25519_2w_bmi2(AB); /* [AA|BB] = [A^2|B^2] */ ++ add_eltfp25519_1w_bmi2(X3, DA, CB); /* X3 = (DA+CB) */ ++ sub_eltfp25519_1w(Z3, DA, CB); /* Z3 = (DA-CB) */ ++ sqr_eltfp25519_2w_bmi2(X3Z3); /* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */ ++ ++ copy_eltfp25519_1w(X2, B); /* X2 = B^2 */ ++ sub_eltfp25519_1w(Z2, A, B); /* Z2 = E = AA-BB */ ++ ++ mul_a24_eltfp25519_1w(B, Z2); /* B = a24*E */ ++ add_eltfp25519_1w_bmi2(B, B, X2); /* B = a24*E+B */ ++ mul_eltfp25519_2w_bmi2(X2Z2, X2Z2, AB); /* [X2|Z2] = [B|E]*[A|a24*E+B] */ ++ mul_eltfp25519_1w_bmi2(Z3, Z3, X1); /* Z3 = Z3*X1 */ ++ --j; ++ } ++ j = 63; ++ } ++ ++ inv_eltfp25519_1w_bmi2(A, Qz); ++ mul_eltfp25519_1w_bmi2((u64 *)shared, Qx, A); ++ fred_eltfp25519_1w((u64 *)shared); ++ ++ memzero_explicit(&m, sizeof(m)); ++} ++ ++static void curve25519_bmi2_base(u8 session_key[CURVE25519_KEY_SIZE], ++ const u8 private_key[CURVE25519_KEY_SIZE]) ++{ ++ struct { ++ u64 buffer[4 * NUM_WORDS_ELTFP25519]; ++ u64 coordinates[4 * NUM_WORDS_ELTFP25519]; ++ u64 workspace[4 * NUM_WORDS_ELTFP25519]; ++ u8 private[CURVE25519_KEY_SIZE]; ++ } __aligned(32) m; ++ ++ const int ite[4] = { 64, 64, 64, 63 }; ++ const int q = 3; ++ u64 swap = 1; ++ ++ int i = 0, j = 0, k = 0; ++ u64 *const key = (u64 *)m.private; ++ u64 *const Ur1 = m.coordinates + 0; ++ u64 *const Zr1 = m.coordinates + 4; ++ u64 *const Ur2 = m.coordinates + 8; ++ u64 *const Zr2 = m.coordinates + 12; ++ ++ u64 *const UZr1 = m.coordinates + 0; ++ u64 *const ZUr2 = m.coordinates + 8; ++ ++ u64 *const A = m.workspace + 0; ++ u64 *const B = m.workspace + 4; ++ u64 *const C = m.workspace + 8; ++ u64 *const D = m.workspace + 12; ++ ++ u64 *const AB = m.workspace + 0; ++ u64 *const CD = m.workspace + 8; ++ ++ const u64 *const P = table_ladder_8k; ++ ++ memcpy(m.private, private_key, sizeof(m.private)); ++ ++ curve25519_clamp_secret(m.private); ++ ++ setzero_eltfp25519_1w(Ur1); ++ setzero_eltfp25519_1w(Zr1); ++ setzero_eltfp25519_1w(Zr2); ++ Ur1[0] = 1; ++ Zr1[0] = 1; ++ Zr2[0] = 1; ++ ++ /* G-S */ ++ Ur2[3] = 0x1eaecdeee27cab34UL; ++ Ur2[2] = 0xadc7a0b9235d48e2UL; ++ Ur2[1] = 0xbbf095ae14b2edf8UL; ++ Ur2[0] = 0x7e94e1fec82faabdUL; ++ ++ /* main-loop */ ++ j = q; ++ for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) { ++ while (j < ite[i]) { ++ u64 bit = (key[i] >> j) & 0x1; ++ k = (64 * i + j - q); ++ swap = swap ^ bit; ++ cswap(swap, Ur1, Ur2); ++ cswap(swap, Zr1, Zr2); ++ swap = bit; ++ /* Addition */ ++ sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ ++ add_eltfp25519_1w_bmi2(A, Ur1, Zr1); /* A = Ur1+Zr1 */ ++ mul_eltfp25519_1w_bmi2(C, &P[4 * k], B);/* C = M0-B */ ++ sub_eltfp25519_1w(B, A, C); /* B = (Ur1+Zr1) - M*(Ur1-Zr1) */ ++ add_eltfp25519_1w_bmi2(A, A, C); /* A = (Ur1+Zr1) + M*(Ur1-Zr1) */ ++ sqr_eltfp25519_2w_bmi2(AB); /* A = A^2 | B = B^2 */ ++ mul_eltfp25519_2w_bmi2(UZr1, ZUr2, AB); /* Ur1 = Zr2*A | Zr1 = Ur2*B */ ++ ++j; ++ } ++ j = 0; ++ } ++ ++ /* Doubling */ ++ for (i = 0; i < q; ++i) { ++ add_eltfp25519_1w_bmi2(A, Ur1, Zr1); /* A = Ur1+Zr1 */ ++ sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ ++ sqr_eltfp25519_2w_bmi2(AB); /* A = A**2 B = B**2 */ ++ copy_eltfp25519_1w(C, B); /* C = B */ ++ sub_eltfp25519_1w(B, A, B); /* B = A-B */ ++ mul_a24_eltfp25519_1w(D, B); /* D = my_a24*B */ ++ add_eltfp25519_1w_bmi2(D, D, C); /* D = D+C */ ++ mul_eltfp25519_2w_bmi2(UZr1, AB, CD); /* Ur1 = A*B Zr1 = Zr1*A */ ++ } ++ ++ /* Convert to affine coordinates */ ++ inv_eltfp25519_1w_bmi2(A, Zr1); ++ mul_eltfp25519_1w_bmi2((u64 *)session_key, Ur1, A); ++ fred_eltfp25519_1w((u64 *)session_key); ++ ++ memzero_explicit(&m, sizeof(m)); ++} ++ ++void curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE], ++ const u8 basepoint[CURVE25519_KEY_SIZE]) ++{ ++ if (static_branch_likely(&curve25519_use_adx)) ++ curve25519_adx(mypublic, secret, basepoint); ++ else if (static_branch_likely(&curve25519_use_bmi2)) ++ curve25519_bmi2(mypublic, secret, basepoint); ++ else ++ curve25519_generic(mypublic, secret, basepoint); ++} ++EXPORT_SYMBOL(curve25519_arch); ++ ++void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE]) ++{ ++ if (static_branch_likely(&curve25519_use_adx)) ++ curve25519_adx_base(pub, secret); ++ else if (static_branch_likely(&curve25519_use_bmi2)) ++ curve25519_bmi2_base(pub, secret); ++ else ++ curve25519_generic(pub, secret, curve25519_base_point); ++} ++EXPORT_SYMBOL(curve25519_base_arch); ++ ++static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf, ++ unsigned int len) ++{ ++ u8 *secret = kpp_tfm_ctx(tfm); ++ ++ if (!len) ++ curve25519_generate_secret(secret); ++ else if (len == CURVE25519_KEY_SIZE && ++ crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE)) ++ memcpy(secret, buf, CURVE25519_KEY_SIZE); ++ else ++ return -EINVAL; ++ return 0; ++} ++ ++static int curve25519_generate_public_key(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ const u8 *secret = kpp_tfm_ctx(tfm); ++ u8 buf[CURVE25519_KEY_SIZE]; ++ int copied, nbytes; ++ ++ if (req->src) ++ return -EINVAL; ++ ++ curve25519_base_arch(buf, secret); ++ ++ /* might want less than we've got */ ++ nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len); ++ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, ++ nbytes), ++ buf, nbytes); ++ if (copied != nbytes) ++ return -EINVAL; ++ return 0; ++} ++ ++static int curve25519_compute_shared_secret(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ const u8 *secret = kpp_tfm_ctx(tfm); ++ u8 public_key[CURVE25519_KEY_SIZE]; ++ u8 buf[CURVE25519_KEY_SIZE]; ++ int copied, nbytes; ++ ++ if (!req->src) ++ return -EINVAL; ++ ++ copied = sg_copy_to_buffer(req->src, ++ sg_nents_for_len(req->src, ++ CURVE25519_KEY_SIZE), ++ public_key, CURVE25519_KEY_SIZE); ++ if (copied != CURVE25519_KEY_SIZE) ++ return -EINVAL; ++ ++ curve25519_arch(buf, secret, public_key); ++ ++ /* might want less than we've got */ ++ nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len); ++ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, ++ nbytes), ++ buf, nbytes); ++ if (copied != nbytes) ++ return -EINVAL; ++ return 0; ++} ++ ++static unsigned int curve25519_max_size(struct crypto_kpp *tfm) ++{ ++ return CURVE25519_KEY_SIZE; ++} ++ ++static struct kpp_alg curve25519_alg = { ++ .base.cra_name = "curve25519", ++ .base.cra_driver_name = "curve25519-x86", ++ .base.cra_priority = 200, ++ .base.cra_module = THIS_MODULE, ++ .base.cra_ctxsize = CURVE25519_KEY_SIZE, ++ ++ .set_secret = curve25519_set_secret, ++ .generate_public_key = curve25519_generate_public_key, ++ .compute_shared_secret = curve25519_compute_shared_secret, ++ .max_size = curve25519_max_size, ++}; ++ ++static int __init curve25519_mod_init(void) ++{ ++ if (boot_cpu_has(X86_FEATURE_BMI2)) ++ static_branch_enable(&curve25519_use_bmi2); ++ else if (boot_cpu_has(X86_FEATURE_ADX)) ++ static_branch_enable(&curve25519_use_adx); ++ else ++ return 0; ++ return crypto_register_kpp(&curve25519_alg); ++} ++ ++static void __exit curve25519_mod_exit(void) ++{ ++ if (boot_cpu_has(X86_FEATURE_BMI2) || ++ boot_cpu_has(X86_FEATURE_ADX)) ++ crypto_unregister_kpp(&curve25519_alg); ++} ++ ++module_init(curve25519_mod_init); ++module_exit(curve25519_mod_exit); ++ ++MODULE_ALIAS_CRYPTO("curve25519"); ++MODULE_ALIAS_CRYPTO("curve25519-x86"); ++MODULE_LICENSE("GPL v2"); +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -269,6 +269,12 @@ config CRYPTO_CURVE25519 + select CRYPTO_KPP + select CRYPTO_LIB_CURVE25519_GENERIC + ++config CRYPTO_CURVE25519_X86 ++ tristate "x86_64 accelerated Curve25519 scalar multiplication library" ++ depends on X86 && 64BIT ++ select CRYPTO_LIB_CURVE25519_GENERIC ++ select CRYPTO_ARCH_HAVE_LIB_CURVE25519 ++ + comment "Authenticated Encryption with Associated Data" + + config CRYPTO_CCM diff --git a/ipq806x/backport-5.4/080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch b/ipq806x/backport-5.4/080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch new file mode 100644 index 0000000..8fda25d --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0030-crypto-arm-curve25519-import-Bernstein-and-Schwabe-s.patch @@ -0,0 +1,2135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 8 Nov 2019 13:22:37 +0100 +Subject: [PATCH] crypto: arm/curve25519 - import Bernstein and Schwabe's + Curve25519 ARM implementation + +commit f0fb006b604f98e2309a30f34ef455ac734f7c1c upstream. + +This comes from Dan Bernstein and Peter Schwabe's public domain NEON +code, and is included here in raw form so that subsequent commits that +fix these up for the kernel can see how it has changed. This code does +have some entirely cosmetic formatting differences, adding indentation +and so forth, so that when we actually port it for use in the kernel in +the subsequent commit, it's obvious what's changed in the process. + +This code originates from SUPERCOP 20180818, available at +. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/curve25519-core.S | 2105 +++++++++++++++++++++++++++++ + 1 file changed, 2105 insertions(+) + create mode 100644 arch/arm/crypto/curve25519-core.S + +--- /dev/null ++++ b/arch/arm/crypto/curve25519-core.S +@@ -0,0 +1,2105 @@ ++/* ++ * Public domain code from Daniel J. Bernstein and Peter Schwabe, from ++ * SUPERCOP's curve25519/neon2/scalarmult.s. ++ */ ++ ++.fpu neon ++.text ++.align 4 ++.global _crypto_scalarmult_curve25519_neon2 ++.global crypto_scalarmult_curve25519_neon2 ++.type _crypto_scalarmult_curve25519_neon2 STT_FUNC ++.type crypto_scalarmult_curve25519_neon2 STT_FUNC ++ _crypto_scalarmult_curve25519_neon2: ++ crypto_scalarmult_curve25519_neon2: ++ vpush {q4, q5, q6, q7} ++ mov r12, sp ++ sub sp, sp, #736 ++ and sp, sp, #0xffffffe0 ++ strd r4, [sp, #0] ++ strd r6, [sp, #8] ++ strd r8, [sp, #16] ++ strd r10, [sp, #24] ++ str r12, [sp, #480] ++ str r14, [sp, #484] ++ mov r0, r0 ++ mov r1, r1 ++ mov r2, r2 ++ add r3, sp, #32 ++ ldr r4, =0 ++ ldr r5, =254 ++ vmov.i32 q0, #1 ++ vshr.u64 q1, q0, #7 ++ vshr.u64 q0, q0, #8 ++ vmov.i32 d4, #19 ++ vmov.i32 d5, #38 ++ add r6, sp, #512 ++ vst1.8 {d2-d3}, [r6, : 128] ++ add r6, sp, #528 ++ vst1.8 {d0-d1}, [r6, : 128] ++ add r6, sp, #544 ++ vst1.8 {d4-d5}, [r6, : 128] ++ add r6, r3, #0 ++ vmov.i32 q2, #0 ++ vst1.8 {d4-d5}, [r6, : 128]! ++ vst1.8 {d4-d5}, [r6, : 128]! ++ vst1.8 d4, [r6, : 64] ++ add r6, r3, #0 ++ ldr r7, =960 ++ sub r7, r7, #2 ++ neg r7, r7 ++ sub r7, r7, r7, LSL #7 ++ str r7, [r6] ++ add r6, sp, #704 ++ vld1.8 {d4-d5}, [r1]! ++ vld1.8 {d6-d7}, [r1] ++ vst1.8 {d4-d5}, [r6, : 128]! ++ vst1.8 {d6-d7}, [r6, : 128] ++ sub r1, r6, #16 ++ ldrb r6, [r1] ++ and r6, r6, #248 ++ strb r6, [r1] ++ ldrb r6, [r1, #31] ++ and r6, r6, #127 ++ orr r6, r6, #64 ++ strb r6, [r1, #31] ++ vmov.i64 q2, #0xffffffff ++ vshr.u64 q3, q2, #7 ++ vshr.u64 q2, q2, #6 ++ vld1.8 {d8}, [r2] ++ vld1.8 {d10}, [r2] ++ add r2, r2, #6 ++ vld1.8 {d12}, [r2] ++ vld1.8 {d14}, [r2] ++ add r2, r2, #6 ++ vld1.8 {d16}, [r2] ++ add r2, r2, #4 ++ vld1.8 {d18}, [r2] ++ vld1.8 {d20}, [r2] ++ add r2, r2, #6 ++ vld1.8 {d22}, [r2] ++ add r2, r2, #2 ++ vld1.8 {d24}, [r2] ++ vld1.8 {d26}, [r2] ++ vshr.u64 q5, q5, #26 ++ vshr.u64 q6, q6, #3 ++ vshr.u64 q7, q7, #29 ++ vshr.u64 q8, q8, #6 ++ vshr.u64 q10, q10, #25 ++ vshr.u64 q11, q11, #3 ++ vshr.u64 q12, q12, #12 ++ vshr.u64 q13, q13, #38 ++ vand q4, q4, q2 ++ vand q6, q6, q2 ++ vand q8, q8, q2 ++ vand q10, q10, q2 ++ vand q2, q12, q2 ++ vand q5, q5, q3 ++ vand q7, q7, q3 ++ vand q9, q9, q3 ++ vand q11, q11, q3 ++ vand q3, q13, q3 ++ add r2, r3, #48 ++ vadd.i64 q12, q4, q1 ++ vadd.i64 q13, q10, q1 ++ vshr.s64 q12, q12, #26 ++ vshr.s64 q13, q13, #26 ++ vadd.i64 q5, q5, q12 ++ vshl.i64 q12, q12, #26 ++ vadd.i64 q14, q5, q0 ++ vadd.i64 q11, q11, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q15, q11, q0 ++ vsub.i64 q4, q4, q12 ++ vshr.s64 q12, q14, #25 ++ vsub.i64 q10, q10, q13 ++ vshr.s64 q13, q15, #25 ++ vadd.i64 q6, q6, q12 ++ vshl.i64 q12, q12, #25 ++ vadd.i64 q14, q6, q1 ++ vadd.i64 q2, q2, q13 ++ vsub.i64 q5, q5, q12 ++ vshr.s64 q12, q14, #26 ++ vshl.i64 q13, q13, #25 ++ vadd.i64 q14, q2, q1 ++ vadd.i64 q7, q7, q12 ++ vshl.i64 q12, q12, #26 ++ vadd.i64 q15, q7, q0 ++ vsub.i64 q11, q11, q13 ++ vshr.s64 q13, q14, #26 ++ vsub.i64 q6, q6, q12 ++ vshr.s64 q12, q15, #25 ++ vadd.i64 q3, q3, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q14, q3, q0 ++ vadd.i64 q8, q8, q12 ++ vshl.i64 q12, q12, #25 ++ vadd.i64 q15, q8, q1 ++ add r2, r2, #8 ++ vsub.i64 q2, q2, q13 ++ vshr.s64 q13, q14, #25 ++ vsub.i64 q7, q7, q12 ++ vshr.s64 q12, q15, #26 ++ vadd.i64 q14, q13, q13 ++ vadd.i64 q9, q9, q12 ++ vtrn.32 d12, d14 ++ vshl.i64 q12, q12, #26 ++ vtrn.32 d13, d15 ++ vadd.i64 q0, q9, q0 ++ vadd.i64 q4, q4, q14 ++ vst1.8 d12, [r2, : 64]! ++ vshl.i64 q6, q13, #4 ++ vsub.i64 q7, q8, q12 ++ vshr.s64 q0, q0, #25 ++ vadd.i64 q4, q4, q6 ++ vadd.i64 q6, q10, q0 ++ vshl.i64 q0, q0, #25 ++ vadd.i64 q8, q6, q1 ++ vadd.i64 q4, q4, q13 ++ vshl.i64 q10, q13, #25 ++ vadd.i64 q1, q4, q1 ++ vsub.i64 q0, q9, q0 ++ vshr.s64 q8, q8, #26 ++ vsub.i64 q3, q3, q10 ++ vtrn.32 d14, d0 ++ vshr.s64 q1, q1, #26 ++ vtrn.32 d15, d1 ++ vadd.i64 q0, q11, q8 ++ vst1.8 d14, [r2, : 64] ++ vshl.i64 q7, q8, #26 ++ vadd.i64 q5, q5, q1 ++ vtrn.32 d4, d6 ++ vshl.i64 q1, q1, #26 ++ vtrn.32 d5, d7 ++ vsub.i64 q3, q6, q7 ++ add r2, r2, #16 ++ vsub.i64 q1, q4, q1 ++ vst1.8 d4, [r2, : 64] ++ vtrn.32 d6, d0 ++ vtrn.32 d7, d1 ++ sub r2, r2, #8 ++ vtrn.32 d2, d10 ++ vtrn.32 d3, d11 ++ vst1.8 d6, [r2, : 64] ++ sub r2, r2, #24 ++ vst1.8 d2, [r2, : 64] ++ add r2, r3, #96 ++ vmov.i32 q0, #0 ++ vmov.i64 d2, #0xff ++ vmov.i64 d3, #0 ++ vshr.u32 q1, q1, #7 ++ vst1.8 {d2-d3}, [r2, : 128]! ++ vst1.8 {d0-d1}, [r2, : 128]! ++ vst1.8 d0, [r2, : 64] ++ add r2, r3, #144 ++ vmov.i32 q0, #0 ++ vst1.8 {d0-d1}, [r2, : 128]! ++ vst1.8 {d0-d1}, [r2, : 128]! ++ vst1.8 d0, [r2, : 64] ++ add r2, r3, #240 ++ vmov.i32 q0, #0 ++ vmov.i64 d2, #0xff ++ vmov.i64 d3, #0 ++ vshr.u32 q1, q1, #7 ++ vst1.8 {d2-d3}, [r2, : 128]! ++ vst1.8 {d0-d1}, [r2, : 128]! ++ vst1.8 d0, [r2, : 64] ++ add r2, r3, #48 ++ add r6, r3, #192 ++ vld1.8 {d0-d1}, [r2, : 128]! ++ vld1.8 {d2-d3}, [r2, : 128]! ++ vld1.8 {d4}, [r2, : 64] ++ vst1.8 {d0-d1}, [r6, : 128]! ++ vst1.8 {d2-d3}, [r6, : 128]! ++ vst1.8 d4, [r6, : 64] ++._mainloop: ++ mov r2, r5, LSR #3 ++ and r6, r5, #7 ++ ldrb r2, [r1, r2] ++ mov r2, r2, LSR r6 ++ and r2, r2, #1 ++ str r5, [sp, #488] ++ eor r4, r4, r2 ++ str r2, [sp, #492] ++ neg r2, r4 ++ add r4, r3, #96 ++ add r5, r3, #192 ++ add r6, r3, #144 ++ vld1.8 {d8-d9}, [r4, : 128]! ++ add r7, r3, #240 ++ vld1.8 {d10-d11}, [r5, : 128]! ++ veor q6, q4, q5 ++ vld1.8 {d14-d15}, [r6, : 128]! ++ vdup.i32 q8, r2 ++ vld1.8 {d18-d19}, [r7, : 128]! ++ veor q10, q7, q9 ++ vld1.8 {d22-d23}, [r4, : 128]! ++ vand q6, q6, q8 ++ vld1.8 {d24-d25}, [r5, : 128]! ++ vand q10, q10, q8 ++ vld1.8 {d26-d27}, [r6, : 128]! ++ veor q4, q4, q6 ++ vld1.8 {d28-d29}, [r7, : 128]! ++ veor q5, q5, q6 ++ vld1.8 {d0}, [r4, : 64] ++ veor q6, q7, q10 ++ vld1.8 {d2}, [r5, : 64] ++ veor q7, q9, q10 ++ vld1.8 {d4}, [r6, : 64] ++ veor q9, q11, q12 ++ vld1.8 {d6}, [r7, : 64] ++ veor q10, q0, q1 ++ sub r2, r4, #32 ++ vand q9, q9, q8 ++ sub r4, r5, #32 ++ vand q10, q10, q8 ++ sub r5, r6, #32 ++ veor q11, q11, q9 ++ sub r6, r7, #32 ++ veor q0, q0, q10 ++ veor q9, q12, q9 ++ veor q1, q1, q10 ++ veor q10, q13, q14 ++ veor q12, q2, q3 ++ vand q10, q10, q8 ++ vand q8, q12, q8 ++ veor q12, q13, q10 ++ veor q2, q2, q8 ++ veor q10, q14, q10 ++ veor q3, q3, q8 ++ vadd.i32 q8, q4, q6 ++ vsub.i32 q4, q4, q6 ++ vst1.8 {d16-d17}, [r2, : 128]! ++ vadd.i32 q6, q11, q12 ++ vst1.8 {d8-d9}, [r5, : 128]! ++ vsub.i32 q4, q11, q12 ++ vst1.8 {d12-d13}, [r2, : 128]! ++ vadd.i32 q6, q0, q2 ++ vst1.8 {d8-d9}, [r5, : 128]! ++ vsub.i32 q0, q0, q2 ++ vst1.8 d12, [r2, : 64] ++ vadd.i32 q2, q5, q7 ++ vst1.8 d0, [r5, : 64] ++ vsub.i32 q0, q5, q7 ++ vst1.8 {d4-d5}, [r4, : 128]! ++ vadd.i32 q2, q9, q10 ++ vst1.8 {d0-d1}, [r6, : 128]! ++ vsub.i32 q0, q9, q10 ++ vst1.8 {d4-d5}, [r4, : 128]! ++ vadd.i32 q2, q1, q3 ++ vst1.8 {d0-d1}, [r6, : 128]! ++ vsub.i32 q0, q1, q3 ++ vst1.8 d4, [r4, : 64] ++ vst1.8 d0, [r6, : 64] ++ add r2, sp, #544 ++ add r4, r3, #96 ++ add r5, r3, #144 ++ vld1.8 {d0-d1}, [r2, : 128] ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vld1.8 {d4-d5}, [r5, : 128]! ++ vzip.i32 q1, q2 ++ vld1.8 {d6-d7}, [r4, : 128]! ++ vld1.8 {d8-d9}, [r5, : 128]! ++ vshl.i32 q5, q1, #1 ++ vzip.i32 q3, q4 ++ vshl.i32 q6, q2, #1 ++ vld1.8 {d14}, [r4, : 64] ++ vshl.i32 q8, q3, #1 ++ vld1.8 {d15}, [r5, : 64] ++ vshl.i32 q9, q4, #1 ++ vmul.i32 d21, d7, d1 ++ vtrn.32 d14, d15 ++ vmul.i32 q11, q4, q0 ++ vmul.i32 q0, q7, q0 ++ vmull.s32 q12, d2, d2 ++ vmlal.s32 q12, d11, d1 ++ vmlal.s32 q12, d12, d0 ++ vmlal.s32 q12, d13, d23 ++ vmlal.s32 q12, d16, d22 ++ vmlal.s32 q12, d7, d21 ++ vmull.s32 q10, d2, d11 ++ vmlal.s32 q10, d4, d1 ++ vmlal.s32 q10, d13, d0 ++ vmlal.s32 q10, d6, d23 ++ vmlal.s32 q10, d17, d22 ++ vmull.s32 q13, d10, d4 ++ vmlal.s32 q13, d11, d3 ++ vmlal.s32 q13, d13, d1 ++ vmlal.s32 q13, d16, d0 ++ vmlal.s32 q13, d17, d23 ++ vmlal.s32 q13, d8, d22 ++ vmull.s32 q1, d10, d5 ++ vmlal.s32 q1, d11, d4 ++ vmlal.s32 q1, d6, d1 ++ vmlal.s32 q1, d17, d0 ++ vmlal.s32 q1, d8, d23 ++ vmull.s32 q14, d10, d6 ++ vmlal.s32 q14, d11, d13 ++ vmlal.s32 q14, d4, d4 ++ vmlal.s32 q14, d17, d1 ++ vmlal.s32 q14, d18, d0 ++ vmlal.s32 q14, d9, d23 ++ vmull.s32 q11, d10, d7 ++ vmlal.s32 q11, d11, d6 ++ vmlal.s32 q11, d12, d5 ++ vmlal.s32 q11, d8, d1 ++ vmlal.s32 q11, d19, d0 ++ vmull.s32 q15, d10, d8 ++ vmlal.s32 q15, d11, d17 ++ vmlal.s32 q15, d12, d6 ++ vmlal.s32 q15, d13, d5 ++ vmlal.s32 q15, d19, d1 ++ vmlal.s32 q15, d14, d0 ++ vmull.s32 q2, d10, d9 ++ vmlal.s32 q2, d11, d8 ++ vmlal.s32 q2, d12, d7 ++ vmlal.s32 q2, d13, d6 ++ vmlal.s32 q2, d14, d1 ++ vmull.s32 q0, d15, d1 ++ vmlal.s32 q0, d10, d14 ++ vmlal.s32 q0, d11, d19 ++ vmlal.s32 q0, d12, d8 ++ vmlal.s32 q0, d13, d17 ++ vmlal.s32 q0, d6, d6 ++ add r2, sp, #512 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmull.s32 q3, d16, d7 ++ vmlal.s32 q3, d10, d15 ++ vmlal.s32 q3, d11, d14 ++ vmlal.s32 q3, d12, d9 ++ vmlal.s32 q3, d13, d8 ++ add r2, sp, #528 ++ vld1.8 {d8-d9}, [r2, : 128] ++ vadd.i64 q5, q12, q9 ++ vadd.i64 q6, q15, q9 ++ vshr.s64 q5, q5, #26 ++ vshr.s64 q6, q6, #26 ++ vadd.i64 q7, q10, q5 ++ vshl.i64 q5, q5, #26 ++ vadd.i64 q8, q7, q4 ++ vadd.i64 q2, q2, q6 ++ vshl.i64 q6, q6, #26 ++ vadd.i64 q10, q2, q4 ++ vsub.i64 q5, q12, q5 ++ vshr.s64 q8, q8, #25 ++ vsub.i64 q6, q15, q6 ++ vshr.s64 q10, q10, #25 ++ vadd.i64 q12, q13, q8 ++ vshl.i64 q8, q8, #25 ++ vadd.i64 q13, q12, q9 ++ vadd.i64 q0, q0, q10 ++ vsub.i64 q7, q7, q8 ++ vshr.s64 q8, q13, #26 ++ vshl.i64 q10, q10, #25 ++ vadd.i64 q13, q0, q9 ++ vadd.i64 q1, q1, q8 ++ vshl.i64 q8, q8, #26 ++ vadd.i64 q15, q1, q4 ++ vsub.i64 q2, q2, q10 ++ vshr.s64 q10, q13, #26 ++ vsub.i64 q8, q12, q8 ++ vshr.s64 q12, q15, #25 ++ vadd.i64 q3, q3, q10 ++ vshl.i64 q10, q10, #26 ++ vadd.i64 q13, q3, q4 ++ vadd.i64 q14, q14, q12 ++ add r2, r3, #288 ++ vshl.i64 q12, q12, #25 ++ add r4, r3, #336 ++ vadd.i64 q15, q14, q9 ++ add r2, r2, #8 ++ vsub.i64 q0, q0, q10 ++ add r4, r4, #8 ++ vshr.s64 q10, q13, #25 ++ vsub.i64 q1, q1, q12 ++ vshr.s64 q12, q15, #26 ++ vadd.i64 q13, q10, q10 ++ vadd.i64 q11, q11, q12 ++ vtrn.32 d16, d2 ++ vshl.i64 q12, q12, #26 ++ vtrn.32 d17, d3 ++ vadd.i64 q1, q11, q4 ++ vadd.i64 q4, q5, q13 ++ vst1.8 d16, [r2, : 64]! ++ vshl.i64 q5, q10, #4 ++ vst1.8 d17, [r4, : 64]! ++ vsub.i64 q8, q14, q12 ++ vshr.s64 q1, q1, #25 ++ vadd.i64 q4, q4, q5 ++ vadd.i64 q5, q6, q1 ++ vshl.i64 q1, q1, #25 ++ vadd.i64 q6, q5, q9 ++ vadd.i64 q4, q4, q10 ++ vshl.i64 q10, q10, #25 ++ vadd.i64 q9, q4, q9 ++ vsub.i64 q1, q11, q1 ++ vshr.s64 q6, q6, #26 ++ vsub.i64 q3, q3, q10 ++ vtrn.32 d16, d2 ++ vshr.s64 q9, q9, #26 ++ vtrn.32 d17, d3 ++ vadd.i64 q1, q2, q6 ++ vst1.8 d16, [r2, : 64] ++ vshl.i64 q2, q6, #26 ++ vst1.8 d17, [r4, : 64] ++ vadd.i64 q6, q7, q9 ++ vtrn.32 d0, d6 ++ vshl.i64 q7, q9, #26 ++ vtrn.32 d1, d7 ++ vsub.i64 q2, q5, q2 ++ add r2, r2, #16 ++ vsub.i64 q3, q4, q7 ++ vst1.8 d0, [r2, : 64] ++ add r4, r4, #16 ++ vst1.8 d1, [r4, : 64] ++ vtrn.32 d4, d2 ++ vtrn.32 d5, d3 ++ sub r2, r2, #8 ++ sub r4, r4, #8 ++ vtrn.32 d6, d12 ++ vtrn.32 d7, d13 ++ vst1.8 d4, [r2, : 64] ++ vst1.8 d5, [r4, : 64] ++ sub r2, r2, #24 ++ sub r4, r4, #24 ++ vst1.8 d6, [r2, : 64] ++ vst1.8 d7, [r4, : 64] ++ add r2, r3, #240 ++ add r4, r3, #96 ++ vld1.8 {d0-d1}, [r4, : 128]! ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vld1.8 {d4}, [r4, : 64] ++ add r4, r3, #144 ++ vld1.8 {d6-d7}, [r4, : 128]! ++ vtrn.32 q0, q3 ++ vld1.8 {d8-d9}, [r4, : 128]! ++ vshl.i32 q5, q0, #4 ++ vtrn.32 q1, q4 ++ vshl.i32 q6, q3, #4 ++ vadd.i32 q5, q5, q0 ++ vadd.i32 q6, q6, q3 ++ vshl.i32 q7, q1, #4 ++ vld1.8 {d5}, [r4, : 64] ++ vshl.i32 q8, q4, #4 ++ vtrn.32 d4, d5 ++ vadd.i32 q7, q7, q1 ++ vadd.i32 q8, q8, q4 ++ vld1.8 {d18-d19}, [r2, : 128]! ++ vshl.i32 q10, q2, #4 ++ vld1.8 {d22-d23}, [r2, : 128]! ++ vadd.i32 q10, q10, q2 ++ vld1.8 {d24}, [r2, : 64] ++ vadd.i32 q5, q5, q0 ++ add r2, r3, #192 ++ vld1.8 {d26-d27}, [r2, : 128]! ++ vadd.i32 q6, q6, q3 ++ vld1.8 {d28-d29}, [r2, : 128]! ++ vadd.i32 q8, q8, q4 ++ vld1.8 {d25}, [r2, : 64] ++ vadd.i32 q10, q10, q2 ++ vtrn.32 q9, q13 ++ vadd.i32 q7, q7, q1 ++ vadd.i32 q5, q5, q0 ++ vtrn.32 q11, q14 ++ vadd.i32 q6, q6, q3 ++ add r2, sp, #560 ++ vadd.i32 q10, q10, q2 ++ vtrn.32 d24, d25 ++ vst1.8 {d12-d13}, [r2, : 128] ++ vshl.i32 q6, q13, #1 ++ add r2, sp, #576 ++ vst1.8 {d20-d21}, [r2, : 128] ++ vshl.i32 q10, q14, #1 ++ add r2, sp, #592 ++ vst1.8 {d12-d13}, [r2, : 128] ++ vshl.i32 q15, q12, #1 ++ vadd.i32 q8, q8, q4 ++ vext.32 d10, d31, d30, #0 ++ vadd.i32 q7, q7, q1 ++ add r2, sp, #608 ++ vst1.8 {d16-d17}, [r2, : 128] ++ vmull.s32 q8, d18, d5 ++ vmlal.s32 q8, d26, d4 ++ vmlal.s32 q8, d19, d9 ++ vmlal.s32 q8, d27, d3 ++ vmlal.s32 q8, d22, d8 ++ vmlal.s32 q8, d28, d2 ++ vmlal.s32 q8, d23, d7 ++ vmlal.s32 q8, d29, d1 ++ vmlal.s32 q8, d24, d6 ++ vmlal.s32 q8, d25, d0 ++ add r2, sp, #624 ++ vst1.8 {d14-d15}, [r2, : 128] ++ vmull.s32 q2, d18, d4 ++ vmlal.s32 q2, d12, d9 ++ vmlal.s32 q2, d13, d8 ++ vmlal.s32 q2, d19, d3 ++ vmlal.s32 q2, d22, d2 ++ vmlal.s32 q2, d23, d1 ++ vmlal.s32 q2, d24, d0 ++ add r2, sp, #640 ++ vst1.8 {d20-d21}, [r2, : 128] ++ vmull.s32 q7, d18, d9 ++ vmlal.s32 q7, d26, d3 ++ vmlal.s32 q7, d19, d8 ++ vmlal.s32 q7, d27, d2 ++ vmlal.s32 q7, d22, d7 ++ vmlal.s32 q7, d28, d1 ++ vmlal.s32 q7, d23, d6 ++ vmlal.s32 q7, d29, d0 ++ add r2, sp, #656 ++ vst1.8 {d10-d11}, [r2, : 128] ++ vmull.s32 q5, d18, d3 ++ vmlal.s32 q5, d19, d2 ++ vmlal.s32 q5, d22, d1 ++ vmlal.s32 q5, d23, d0 ++ vmlal.s32 q5, d12, d8 ++ add r2, sp, #672 ++ vst1.8 {d16-d17}, [r2, : 128] ++ vmull.s32 q4, d18, d8 ++ vmlal.s32 q4, d26, d2 ++ vmlal.s32 q4, d19, d7 ++ vmlal.s32 q4, d27, d1 ++ vmlal.s32 q4, d22, d6 ++ vmlal.s32 q4, d28, d0 ++ vmull.s32 q8, d18, d7 ++ vmlal.s32 q8, d26, d1 ++ vmlal.s32 q8, d19, d6 ++ vmlal.s32 q8, d27, d0 ++ add r2, sp, #576 ++ vld1.8 {d20-d21}, [r2, : 128] ++ vmlal.s32 q7, d24, d21 ++ vmlal.s32 q7, d25, d20 ++ vmlal.s32 q4, d23, d21 ++ vmlal.s32 q4, d29, d20 ++ vmlal.s32 q8, d22, d21 ++ vmlal.s32 q8, d28, d20 ++ vmlal.s32 q5, d24, d20 ++ add r2, sp, #576 ++ vst1.8 {d14-d15}, [r2, : 128] ++ vmull.s32 q7, d18, d6 ++ vmlal.s32 q7, d26, d0 ++ add r2, sp, #656 ++ vld1.8 {d30-d31}, [r2, : 128] ++ vmlal.s32 q2, d30, d21 ++ vmlal.s32 q7, d19, d21 ++ vmlal.s32 q7, d27, d20 ++ add r2, sp, #624 ++ vld1.8 {d26-d27}, [r2, : 128] ++ vmlal.s32 q4, d25, d27 ++ vmlal.s32 q8, d29, d27 ++ vmlal.s32 q8, d25, d26 ++ vmlal.s32 q7, d28, d27 ++ vmlal.s32 q7, d29, d26 ++ add r2, sp, #608 ++ vld1.8 {d28-d29}, [r2, : 128] ++ vmlal.s32 q4, d24, d29 ++ vmlal.s32 q8, d23, d29 ++ vmlal.s32 q8, d24, d28 ++ vmlal.s32 q7, d22, d29 ++ vmlal.s32 q7, d23, d28 ++ add r2, sp, #608 ++ vst1.8 {d8-d9}, [r2, : 128] ++ add r2, sp, #560 ++ vld1.8 {d8-d9}, [r2, : 128] ++ vmlal.s32 q7, d24, d9 ++ vmlal.s32 q7, d25, d31 ++ vmull.s32 q1, d18, d2 ++ vmlal.s32 q1, d19, d1 ++ vmlal.s32 q1, d22, d0 ++ vmlal.s32 q1, d24, d27 ++ vmlal.s32 q1, d23, d20 ++ vmlal.s32 q1, d12, d7 ++ vmlal.s32 q1, d13, d6 ++ vmull.s32 q6, d18, d1 ++ vmlal.s32 q6, d19, d0 ++ vmlal.s32 q6, d23, d27 ++ vmlal.s32 q6, d22, d20 ++ vmlal.s32 q6, d24, d26 ++ vmull.s32 q0, d18, d0 ++ vmlal.s32 q0, d22, d27 ++ vmlal.s32 q0, d23, d26 ++ vmlal.s32 q0, d24, d31 ++ vmlal.s32 q0, d19, d20 ++ add r2, sp, #640 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmlal.s32 q2, d18, d7 ++ vmlal.s32 q2, d19, d6 ++ vmlal.s32 q5, d18, d6 ++ vmlal.s32 q5, d19, d21 ++ vmlal.s32 q1, d18, d21 ++ vmlal.s32 q1, d19, d29 ++ vmlal.s32 q0, d18, d28 ++ vmlal.s32 q0, d19, d9 ++ vmlal.s32 q6, d18, d29 ++ vmlal.s32 q6, d19, d28 ++ add r2, sp, #592 ++ vld1.8 {d18-d19}, [r2, : 128] ++ add r2, sp, #512 ++ vld1.8 {d22-d23}, [r2, : 128] ++ vmlal.s32 q5, d19, d7 ++ vmlal.s32 q0, d18, d21 ++ vmlal.s32 q0, d19, d29 ++ vmlal.s32 q6, d18, d6 ++ add r2, sp, #528 ++ vld1.8 {d6-d7}, [r2, : 128] ++ vmlal.s32 q6, d19, d21 ++ add r2, sp, #576 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmlal.s32 q0, d30, d8 ++ add r2, sp, #672 ++ vld1.8 {d20-d21}, [r2, : 128] ++ vmlal.s32 q5, d30, d29 ++ add r2, sp, #608 ++ vld1.8 {d24-d25}, [r2, : 128] ++ vmlal.s32 q1, d30, d28 ++ vadd.i64 q13, q0, q11 ++ vadd.i64 q14, q5, q11 ++ vmlal.s32 q6, d30, d9 ++ vshr.s64 q4, q13, #26 ++ vshr.s64 q13, q14, #26 ++ vadd.i64 q7, q7, q4 ++ vshl.i64 q4, q4, #26 ++ vadd.i64 q14, q7, q3 ++ vadd.i64 q9, q9, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q15, q9, q3 ++ vsub.i64 q0, q0, q4 ++ vshr.s64 q4, q14, #25 ++ vsub.i64 q5, q5, q13 ++ vshr.s64 q13, q15, #25 ++ vadd.i64 q6, q6, q4 ++ vshl.i64 q4, q4, #25 ++ vadd.i64 q14, q6, q11 ++ vadd.i64 q2, q2, q13 ++ vsub.i64 q4, q7, q4 ++ vshr.s64 q7, q14, #26 ++ vshl.i64 q13, q13, #25 ++ vadd.i64 q14, q2, q11 ++ vadd.i64 q8, q8, q7 ++ vshl.i64 q7, q7, #26 ++ vadd.i64 q15, q8, q3 ++ vsub.i64 q9, q9, q13 ++ vshr.s64 q13, q14, #26 ++ vsub.i64 q6, q6, q7 ++ vshr.s64 q7, q15, #25 ++ vadd.i64 q10, q10, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q14, q10, q3 ++ vadd.i64 q1, q1, q7 ++ add r2, r3, #144 ++ vshl.i64 q7, q7, #25 ++ add r4, r3, #96 ++ vadd.i64 q15, q1, q11 ++ add r2, r2, #8 ++ vsub.i64 q2, q2, q13 ++ add r4, r4, #8 ++ vshr.s64 q13, q14, #25 ++ vsub.i64 q7, q8, q7 ++ vshr.s64 q8, q15, #26 ++ vadd.i64 q14, q13, q13 ++ vadd.i64 q12, q12, q8 ++ vtrn.32 d12, d14 ++ vshl.i64 q8, q8, #26 ++ vtrn.32 d13, d15 ++ vadd.i64 q3, q12, q3 ++ vadd.i64 q0, q0, q14 ++ vst1.8 d12, [r2, : 64]! ++ vshl.i64 q7, q13, #4 ++ vst1.8 d13, [r4, : 64]! ++ vsub.i64 q1, q1, q8 ++ vshr.s64 q3, q3, #25 ++ vadd.i64 q0, q0, q7 ++ vadd.i64 q5, q5, q3 ++ vshl.i64 q3, q3, #25 ++ vadd.i64 q6, q5, q11 ++ vadd.i64 q0, q0, q13 ++ vshl.i64 q7, q13, #25 ++ vadd.i64 q8, q0, q11 ++ vsub.i64 q3, q12, q3 ++ vshr.s64 q6, q6, #26 ++ vsub.i64 q7, q10, q7 ++ vtrn.32 d2, d6 ++ vshr.s64 q8, q8, #26 ++ vtrn.32 d3, d7 ++ vadd.i64 q3, q9, q6 ++ vst1.8 d2, [r2, : 64] ++ vshl.i64 q6, q6, #26 ++ vst1.8 d3, [r4, : 64] ++ vadd.i64 q1, q4, q8 ++ vtrn.32 d4, d14 ++ vshl.i64 q4, q8, #26 ++ vtrn.32 d5, d15 ++ vsub.i64 q5, q5, q6 ++ add r2, r2, #16 ++ vsub.i64 q0, q0, q4 ++ vst1.8 d4, [r2, : 64] ++ add r4, r4, #16 ++ vst1.8 d5, [r4, : 64] ++ vtrn.32 d10, d6 ++ vtrn.32 d11, d7 ++ sub r2, r2, #8 ++ sub r4, r4, #8 ++ vtrn.32 d0, d2 ++ vtrn.32 d1, d3 ++ vst1.8 d10, [r2, : 64] ++ vst1.8 d11, [r4, : 64] ++ sub r2, r2, #24 ++ sub r4, r4, #24 ++ vst1.8 d0, [r2, : 64] ++ vst1.8 d1, [r4, : 64] ++ add r2, r3, #288 ++ add r4, r3, #336 ++ vld1.8 {d0-d1}, [r2, : 128]! ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vsub.i32 q0, q0, q1 ++ vld1.8 {d2-d3}, [r2, : 128]! ++ vld1.8 {d4-d5}, [r4, : 128]! ++ vsub.i32 q1, q1, q2 ++ add r5, r3, #240 ++ vld1.8 {d4}, [r2, : 64] ++ vld1.8 {d6}, [r4, : 64] ++ vsub.i32 q2, q2, q3 ++ vst1.8 {d0-d1}, [r5, : 128]! ++ vst1.8 {d2-d3}, [r5, : 128]! ++ vst1.8 d4, [r5, : 64] ++ add r2, r3, #144 ++ add r4, r3, #96 ++ add r5, r3, #144 ++ add r6, r3, #192 ++ vld1.8 {d0-d1}, [r2, : 128]! ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vsub.i32 q2, q0, q1 ++ vadd.i32 q0, q0, q1 ++ vld1.8 {d2-d3}, [r2, : 128]! ++ vld1.8 {d6-d7}, [r4, : 128]! ++ vsub.i32 q4, q1, q3 ++ vadd.i32 q1, q1, q3 ++ vld1.8 {d6}, [r2, : 64] ++ vld1.8 {d10}, [r4, : 64] ++ vsub.i32 q6, q3, q5 ++ vadd.i32 q3, q3, q5 ++ vst1.8 {d4-d5}, [r5, : 128]! ++ vst1.8 {d0-d1}, [r6, : 128]! ++ vst1.8 {d8-d9}, [r5, : 128]! ++ vst1.8 {d2-d3}, [r6, : 128]! ++ vst1.8 d12, [r5, : 64] ++ vst1.8 d6, [r6, : 64] ++ add r2, r3, #0 ++ add r4, r3, #240 ++ vld1.8 {d0-d1}, [r4, : 128]! ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vld1.8 {d4}, [r4, : 64] ++ add r4, r3, #336 ++ vld1.8 {d6-d7}, [r4, : 128]! ++ vtrn.32 q0, q3 ++ vld1.8 {d8-d9}, [r4, : 128]! ++ vshl.i32 q5, q0, #4 ++ vtrn.32 q1, q4 ++ vshl.i32 q6, q3, #4 ++ vadd.i32 q5, q5, q0 ++ vadd.i32 q6, q6, q3 ++ vshl.i32 q7, q1, #4 ++ vld1.8 {d5}, [r4, : 64] ++ vshl.i32 q8, q4, #4 ++ vtrn.32 d4, d5 ++ vadd.i32 q7, q7, q1 ++ vadd.i32 q8, q8, q4 ++ vld1.8 {d18-d19}, [r2, : 128]! ++ vshl.i32 q10, q2, #4 ++ vld1.8 {d22-d23}, [r2, : 128]! ++ vadd.i32 q10, q10, q2 ++ vld1.8 {d24}, [r2, : 64] ++ vadd.i32 q5, q5, q0 ++ add r2, r3, #288 ++ vld1.8 {d26-d27}, [r2, : 128]! ++ vadd.i32 q6, q6, q3 ++ vld1.8 {d28-d29}, [r2, : 128]! ++ vadd.i32 q8, q8, q4 ++ vld1.8 {d25}, [r2, : 64] ++ vadd.i32 q10, q10, q2 ++ vtrn.32 q9, q13 ++ vadd.i32 q7, q7, q1 ++ vadd.i32 q5, q5, q0 ++ vtrn.32 q11, q14 ++ vadd.i32 q6, q6, q3 ++ add r2, sp, #560 ++ vadd.i32 q10, q10, q2 ++ vtrn.32 d24, d25 ++ vst1.8 {d12-d13}, [r2, : 128] ++ vshl.i32 q6, q13, #1 ++ add r2, sp, #576 ++ vst1.8 {d20-d21}, [r2, : 128] ++ vshl.i32 q10, q14, #1 ++ add r2, sp, #592 ++ vst1.8 {d12-d13}, [r2, : 128] ++ vshl.i32 q15, q12, #1 ++ vadd.i32 q8, q8, q4 ++ vext.32 d10, d31, d30, #0 ++ vadd.i32 q7, q7, q1 ++ add r2, sp, #608 ++ vst1.8 {d16-d17}, [r2, : 128] ++ vmull.s32 q8, d18, d5 ++ vmlal.s32 q8, d26, d4 ++ vmlal.s32 q8, d19, d9 ++ vmlal.s32 q8, d27, d3 ++ vmlal.s32 q8, d22, d8 ++ vmlal.s32 q8, d28, d2 ++ vmlal.s32 q8, d23, d7 ++ vmlal.s32 q8, d29, d1 ++ vmlal.s32 q8, d24, d6 ++ vmlal.s32 q8, d25, d0 ++ add r2, sp, #624 ++ vst1.8 {d14-d15}, [r2, : 128] ++ vmull.s32 q2, d18, d4 ++ vmlal.s32 q2, d12, d9 ++ vmlal.s32 q2, d13, d8 ++ vmlal.s32 q2, d19, d3 ++ vmlal.s32 q2, d22, d2 ++ vmlal.s32 q2, d23, d1 ++ vmlal.s32 q2, d24, d0 ++ add r2, sp, #640 ++ vst1.8 {d20-d21}, [r2, : 128] ++ vmull.s32 q7, d18, d9 ++ vmlal.s32 q7, d26, d3 ++ vmlal.s32 q7, d19, d8 ++ vmlal.s32 q7, d27, d2 ++ vmlal.s32 q7, d22, d7 ++ vmlal.s32 q7, d28, d1 ++ vmlal.s32 q7, d23, d6 ++ vmlal.s32 q7, d29, d0 ++ add r2, sp, #656 ++ vst1.8 {d10-d11}, [r2, : 128] ++ vmull.s32 q5, d18, d3 ++ vmlal.s32 q5, d19, d2 ++ vmlal.s32 q5, d22, d1 ++ vmlal.s32 q5, d23, d0 ++ vmlal.s32 q5, d12, d8 ++ add r2, sp, #672 ++ vst1.8 {d16-d17}, [r2, : 128] ++ vmull.s32 q4, d18, d8 ++ vmlal.s32 q4, d26, d2 ++ vmlal.s32 q4, d19, d7 ++ vmlal.s32 q4, d27, d1 ++ vmlal.s32 q4, d22, d6 ++ vmlal.s32 q4, d28, d0 ++ vmull.s32 q8, d18, d7 ++ vmlal.s32 q8, d26, d1 ++ vmlal.s32 q8, d19, d6 ++ vmlal.s32 q8, d27, d0 ++ add r2, sp, #576 ++ vld1.8 {d20-d21}, [r2, : 128] ++ vmlal.s32 q7, d24, d21 ++ vmlal.s32 q7, d25, d20 ++ vmlal.s32 q4, d23, d21 ++ vmlal.s32 q4, d29, d20 ++ vmlal.s32 q8, d22, d21 ++ vmlal.s32 q8, d28, d20 ++ vmlal.s32 q5, d24, d20 ++ add r2, sp, #576 ++ vst1.8 {d14-d15}, [r2, : 128] ++ vmull.s32 q7, d18, d6 ++ vmlal.s32 q7, d26, d0 ++ add r2, sp, #656 ++ vld1.8 {d30-d31}, [r2, : 128] ++ vmlal.s32 q2, d30, d21 ++ vmlal.s32 q7, d19, d21 ++ vmlal.s32 q7, d27, d20 ++ add r2, sp, #624 ++ vld1.8 {d26-d27}, [r2, : 128] ++ vmlal.s32 q4, d25, d27 ++ vmlal.s32 q8, d29, d27 ++ vmlal.s32 q8, d25, d26 ++ vmlal.s32 q7, d28, d27 ++ vmlal.s32 q7, d29, d26 ++ add r2, sp, #608 ++ vld1.8 {d28-d29}, [r2, : 128] ++ vmlal.s32 q4, d24, d29 ++ vmlal.s32 q8, d23, d29 ++ vmlal.s32 q8, d24, d28 ++ vmlal.s32 q7, d22, d29 ++ vmlal.s32 q7, d23, d28 ++ add r2, sp, #608 ++ vst1.8 {d8-d9}, [r2, : 128] ++ add r2, sp, #560 ++ vld1.8 {d8-d9}, [r2, : 128] ++ vmlal.s32 q7, d24, d9 ++ vmlal.s32 q7, d25, d31 ++ vmull.s32 q1, d18, d2 ++ vmlal.s32 q1, d19, d1 ++ vmlal.s32 q1, d22, d0 ++ vmlal.s32 q1, d24, d27 ++ vmlal.s32 q1, d23, d20 ++ vmlal.s32 q1, d12, d7 ++ vmlal.s32 q1, d13, d6 ++ vmull.s32 q6, d18, d1 ++ vmlal.s32 q6, d19, d0 ++ vmlal.s32 q6, d23, d27 ++ vmlal.s32 q6, d22, d20 ++ vmlal.s32 q6, d24, d26 ++ vmull.s32 q0, d18, d0 ++ vmlal.s32 q0, d22, d27 ++ vmlal.s32 q0, d23, d26 ++ vmlal.s32 q0, d24, d31 ++ vmlal.s32 q0, d19, d20 ++ add r2, sp, #640 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmlal.s32 q2, d18, d7 ++ vmlal.s32 q2, d19, d6 ++ vmlal.s32 q5, d18, d6 ++ vmlal.s32 q5, d19, d21 ++ vmlal.s32 q1, d18, d21 ++ vmlal.s32 q1, d19, d29 ++ vmlal.s32 q0, d18, d28 ++ vmlal.s32 q0, d19, d9 ++ vmlal.s32 q6, d18, d29 ++ vmlal.s32 q6, d19, d28 ++ add r2, sp, #592 ++ vld1.8 {d18-d19}, [r2, : 128] ++ add r2, sp, #512 ++ vld1.8 {d22-d23}, [r2, : 128] ++ vmlal.s32 q5, d19, d7 ++ vmlal.s32 q0, d18, d21 ++ vmlal.s32 q0, d19, d29 ++ vmlal.s32 q6, d18, d6 ++ add r2, sp, #528 ++ vld1.8 {d6-d7}, [r2, : 128] ++ vmlal.s32 q6, d19, d21 ++ add r2, sp, #576 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmlal.s32 q0, d30, d8 ++ add r2, sp, #672 ++ vld1.8 {d20-d21}, [r2, : 128] ++ vmlal.s32 q5, d30, d29 ++ add r2, sp, #608 ++ vld1.8 {d24-d25}, [r2, : 128] ++ vmlal.s32 q1, d30, d28 ++ vadd.i64 q13, q0, q11 ++ vadd.i64 q14, q5, q11 ++ vmlal.s32 q6, d30, d9 ++ vshr.s64 q4, q13, #26 ++ vshr.s64 q13, q14, #26 ++ vadd.i64 q7, q7, q4 ++ vshl.i64 q4, q4, #26 ++ vadd.i64 q14, q7, q3 ++ vadd.i64 q9, q9, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q15, q9, q3 ++ vsub.i64 q0, q0, q4 ++ vshr.s64 q4, q14, #25 ++ vsub.i64 q5, q5, q13 ++ vshr.s64 q13, q15, #25 ++ vadd.i64 q6, q6, q4 ++ vshl.i64 q4, q4, #25 ++ vadd.i64 q14, q6, q11 ++ vadd.i64 q2, q2, q13 ++ vsub.i64 q4, q7, q4 ++ vshr.s64 q7, q14, #26 ++ vshl.i64 q13, q13, #25 ++ vadd.i64 q14, q2, q11 ++ vadd.i64 q8, q8, q7 ++ vshl.i64 q7, q7, #26 ++ vadd.i64 q15, q8, q3 ++ vsub.i64 q9, q9, q13 ++ vshr.s64 q13, q14, #26 ++ vsub.i64 q6, q6, q7 ++ vshr.s64 q7, q15, #25 ++ vadd.i64 q10, q10, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q14, q10, q3 ++ vadd.i64 q1, q1, q7 ++ add r2, r3, #288 ++ vshl.i64 q7, q7, #25 ++ add r4, r3, #96 ++ vadd.i64 q15, q1, q11 ++ add r2, r2, #8 ++ vsub.i64 q2, q2, q13 ++ add r4, r4, #8 ++ vshr.s64 q13, q14, #25 ++ vsub.i64 q7, q8, q7 ++ vshr.s64 q8, q15, #26 ++ vadd.i64 q14, q13, q13 ++ vadd.i64 q12, q12, q8 ++ vtrn.32 d12, d14 ++ vshl.i64 q8, q8, #26 ++ vtrn.32 d13, d15 ++ vadd.i64 q3, q12, q3 ++ vadd.i64 q0, q0, q14 ++ vst1.8 d12, [r2, : 64]! ++ vshl.i64 q7, q13, #4 ++ vst1.8 d13, [r4, : 64]! ++ vsub.i64 q1, q1, q8 ++ vshr.s64 q3, q3, #25 ++ vadd.i64 q0, q0, q7 ++ vadd.i64 q5, q5, q3 ++ vshl.i64 q3, q3, #25 ++ vadd.i64 q6, q5, q11 ++ vadd.i64 q0, q0, q13 ++ vshl.i64 q7, q13, #25 ++ vadd.i64 q8, q0, q11 ++ vsub.i64 q3, q12, q3 ++ vshr.s64 q6, q6, #26 ++ vsub.i64 q7, q10, q7 ++ vtrn.32 d2, d6 ++ vshr.s64 q8, q8, #26 ++ vtrn.32 d3, d7 ++ vadd.i64 q3, q9, q6 ++ vst1.8 d2, [r2, : 64] ++ vshl.i64 q6, q6, #26 ++ vst1.8 d3, [r4, : 64] ++ vadd.i64 q1, q4, q8 ++ vtrn.32 d4, d14 ++ vshl.i64 q4, q8, #26 ++ vtrn.32 d5, d15 ++ vsub.i64 q5, q5, q6 ++ add r2, r2, #16 ++ vsub.i64 q0, q0, q4 ++ vst1.8 d4, [r2, : 64] ++ add r4, r4, #16 ++ vst1.8 d5, [r4, : 64] ++ vtrn.32 d10, d6 ++ vtrn.32 d11, d7 ++ sub r2, r2, #8 ++ sub r4, r4, #8 ++ vtrn.32 d0, d2 ++ vtrn.32 d1, d3 ++ vst1.8 d10, [r2, : 64] ++ vst1.8 d11, [r4, : 64] ++ sub r2, r2, #24 ++ sub r4, r4, #24 ++ vst1.8 d0, [r2, : 64] ++ vst1.8 d1, [r4, : 64] ++ add r2, sp, #544 ++ add r4, r3, #144 ++ add r5, r3, #192 ++ vld1.8 {d0-d1}, [r2, : 128] ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vld1.8 {d4-d5}, [r5, : 128]! ++ vzip.i32 q1, q2 ++ vld1.8 {d6-d7}, [r4, : 128]! ++ vld1.8 {d8-d9}, [r5, : 128]! ++ vshl.i32 q5, q1, #1 ++ vzip.i32 q3, q4 ++ vshl.i32 q6, q2, #1 ++ vld1.8 {d14}, [r4, : 64] ++ vshl.i32 q8, q3, #1 ++ vld1.8 {d15}, [r5, : 64] ++ vshl.i32 q9, q4, #1 ++ vmul.i32 d21, d7, d1 ++ vtrn.32 d14, d15 ++ vmul.i32 q11, q4, q0 ++ vmul.i32 q0, q7, q0 ++ vmull.s32 q12, d2, d2 ++ vmlal.s32 q12, d11, d1 ++ vmlal.s32 q12, d12, d0 ++ vmlal.s32 q12, d13, d23 ++ vmlal.s32 q12, d16, d22 ++ vmlal.s32 q12, d7, d21 ++ vmull.s32 q10, d2, d11 ++ vmlal.s32 q10, d4, d1 ++ vmlal.s32 q10, d13, d0 ++ vmlal.s32 q10, d6, d23 ++ vmlal.s32 q10, d17, d22 ++ vmull.s32 q13, d10, d4 ++ vmlal.s32 q13, d11, d3 ++ vmlal.s32 q13, d13, d1 ++ vmlal.s32 q13, d16, d0 ++ vmlal.s32 q13, d17, d23 ++ vmlal.s32 q13, d8, d22 ++ vmull.s32 q1, d10, d5 ++ vmlal.s32 q1, d11, d4 ++ vmlal.s32 q1, d6, d1 ++ vmlal.s32 q1, d17, d0 ++ vmlal.s32 q1, d8, d23 ++ vmull.s32 q14, d10, d6 ++ vmlal.s32 q14, d11, d13 ++ vmlal.s32 q14, d4, d4 ++ vmlal.s32 q14, d17, d1 ++ vmlal.s32 q14, d18, d0 ++ vmlal.s32 q14, d9, d23 ++ vmull.s32 q11, d10, d7 ++ vmlal.s32 q11, d11, d6 ++ vmlal.s32 q11, d12, d5 ++ vmlal.s32 q11, d8, d1 ++ vmlal.s32 q11, d19, d0 ++ vmull.s32 q15, d10, d8 ++ vmlal.s32 q15, d11, d17 ++ vmlal.s32 q15, d12, d6 ++ vmlal.s32 q15, d13, d5 ++ vmlal.s32 q15, d19, d1 ++ vmlal.s32 q15, d14, d0 ++ vmull.s32 q2, d10, d9 ++ vmlal.s32 q2, d11, d8 ++ vmlal.s32 q2, d12, d7 ++ vmlal.s32 q2, d13, d6 ++ vmlal.s32 q2, d14, d1 ++ vmull.s32 q0, d15, d1 ++ vmlal.s32 q0, d10, d14 ++ vmlal.s32 q0, d11, d19 ++ vmlal.s32 q0, d12, d8 ++ vmlal.s32 q0, d13, d17 ++ vmlal.s32 q0, d6, d6 ++ add r2, sp, #512 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmull.s32 q3, d16, d7 ++ vmlal.s32 q3, d10, d15 ++ vmlal.s32 q3, d11, d14 ++ vmlal.s32 q3, d12, d9 ++ vmlal.s32 q3, d13, d8 ++ add r2, sp, #528 ++ vld1.8 {d8-d9}, [r2, : 128] ++ vadd.i64 q5, q12, q9 ++ vadd.i64 q6, q15, q9 ++ vshr.s64 q5, q5, #26 ++ vshr.s64 q6, q6, #26 ++ vadd.i64 q7, q10, q5 ++ vshl.i64 q5, q5, #26 ++ vadd.i64 q8, q7, q4 ++ vadd.i64 q2, q2, q6 ++ vshl.i64 q6, q6, #26 ++ vadd.i64 q10, q2, q4 ++ vsub.i64 q5, q12, q5 ++ vshr.s64 q8, q8, #25 ++ vsub.i64 q6, q15, q6 ++ vshr.s64 q10, q10, #25 ++ vadd.i64 q12, q13, q8 ++ vshl.i64 q8, q8, #25 ++ vadd.i64 q13, q12, q9 ++ vadd.i64 q0, q0, q10 ++ vsub.i64 q7, q7, q8 ++ vshr.s64 q8, q13, #26 ++ vshl.i64 q10, q10, #25 ++ vadd.i64 q13, q0, q9 ++ vadd.i64 q1, q1, q8 ++ vshl.i64 q8, q8, #26 ++ vadd.i64 q15, q1, q4 ++ vsub.i64 q2, q2, q10 ++ vshr.s64 q10, q13, #26 ++ vsub.i64 q8, q12, q8 ++ vshr.s64 q12, q15, #25 ++ vadd.i64 q3, q3, q10 ++ vshl.i64 q10, q10, #26 ++ vadd.i64 q13, q3, q4 ++ vadd.i64 q14, q14, q12 ++ add r2, r3, #144 ++ vshl.i64 q12, q12, #25 ++ add r4, r3, #192 ++ vadd.i64 q15, q14, q9 ++ add r2, r2, #8 ++ vsub.i64 q0, q0, q10 ++ add r4, r4, #8 ++ vshr.s64 q10, q13, #25 ++ vsub.i64 q1, q1, q12 ++ vshr.s64 q12, q15, #26 ++ vadd.i64 q13, q10, q10 ++ vadd.i64 q11, q11, q12 ++ vtrn.32 d16, d2 ++ vshl.i64 q12, q12, #26 ++ vtrn.32 d17, d3 ++ vadd.i64 q1, q11, q4 ++ vadd.i64 q4, q5, q13 ++ vst1.8 d16, [r2, : 64]! ++ vshl.i64 q5, q10, #4 ++ vst1.8 d17, [r4, : 64]! ++ vsub.i64 q8, q14, q12 ++ vshr.s64 q1, q1, #25 ++ vadd.i64 q4, q4, q5 ++ vadd.i64 q5, q6, q1 ++ vshl.i64 q1, q1, #25 ++ vadd.i64 q6, q5, q9 ++ vadd.i64 q4, q4, q10 ++ vshl.i64 q10, q10, #25 ++ vadd.i64 q9, q4, q9 ++ vsub.i64 q1, q11, q1 ++ vshr.s64 q6, q6, #26 ++ vsub.i64 q3, q3, q10 ++ vtrn.32 d16, d2 ++ vshr.s64 q9, q9, #26 ++ vtrn.32 d17, d3 ++ vadd.i64 q1, q2, q6 ++ vst1.8 d16, [r2, : 64] ++ vshl.i64 q2, q6, #26 ++ vst1.8 d17, [r4, : 64] ++ vadd.i64 q6, q7, q9 ++ vtrn.32 d0, d6 ++ vshl.i64 q7, q9, #26 ++ vtrn.32 d1, d7 ++ vsub.i64 q2, q5, q2 ++ add r2, r2, #16 ++ vsub.i64 q3, q4, q7 ++ vst1.8 d0, [r2, : 64] ++ add r4, r4, #16 ++ vst1.8 d1, [r4, : 64] ++ vtrn.32 d4, d2 ++ vtrn.32 d5, d3 ++ sub r2, r2, #8 ++ sub r4, r4, #8 ++ vtrn.32 d6, d12 ++ vtrn.32 d7, d13 ++ vst1.8 d4, [r2, : 64] ++ vst1.8 d5, [r4, : 64] ++ sub r2, r2, #24 ++ sub r4, r4, #24 ++ vst1.8 d6, [r2, : 64] ++ vst1.8 d7, [r4, : 64] ++ add r2, r3, #336 ++ add r4, r3, #288 ++ vld1.8 {d0-d1}, [r2, : 128]! ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vadd.i32 q0, q0, q1 ++ vld1.8 {d2-d3}, [r2, : 128]! ++ vld1.8 {d4-d5}, [r4, : 128]! ++ vadd.i32 q1, q1, q2 ++ add r5, r3, #288 ++ vld1.8 {d4}, [r2, : 64] ++ vld1.8 {d6}, [r4, : 64] ++ vadd.i32 q2, q2, q3 ++ vst1.8 {d0-d1}, [r5, : 128]! ++ vst1.8 {d2-d3}, [r5, : 128]! ++ vst1.8 d4, [r5, : 64] ++ add r2, r3, #48 ++ add r4, r3, #144 ++ vld1.8 {d0-d1}, [r4, : 128]! ++ vld1.8 {d2-d3}, [r4, : 128]! ++ vld1.8 {d4}, [r4, : 64] ++ add r4, r3, #288 ++ vld1.8 {d6-d7}, [r4, : 128]! ++ vtrn.32 q0, q3 ++ vld1.8 {d8-d9}, [r4, : 128]! ++ vshl.i32 q5, q0, #4 ++ vtrn.32 q1, q4 ++ vshl.i32 q6, q3, #4 ++ vadd.i32 q5, q5, q0 ++ vadd.i32 q6, q6, q3 ++ vshl.i32 q7, q1, #4 ++ vld1.8 {d5}, [r4, : 64] ++ vshl.i32 q8, q4, #4 ++ vtrn.32 d4, d5 ++ vadd.i32 q7, q7, q1 ++ vadd.i32 q8, q8, q4 ++ vld1.8 {d18-d19}, [r2, : 128]! ++ vshl.i32 q10, q2, #4 ++ vld1.8 {d22-d23}, [r2, : 128]! ++ vadd.i32 q10, q10, q2 ++ vld1.8 {d24}, [r2, : 64] ++ vadd.i32 q5, q5, q0 ++ add r2, r3, #240 ++ vld1.8 {d26-d27}, [r2, : 128]! ++ vadd.i32 q6, q6, q3 ++ vld1.8 {d28-d29}, [r2, : 128]! ++ vadd.i32 q8, q8, q4 ++ vld1.8 {d25}, [r2, : 64] ++ vadd.i32 q10, q10, q2 ++ vtrn.32 q9, q13 ++ vadd.i32 q7, q7, q1 ++ vadd.i32 q5, q5, q0 ++ vtrn.32 q11, q14 ++ vadd.i32 q6, q6, q3 ++ add r2, sp, #560 ++ vadd.i32 q10, q10, q2 ++ vtrn.32 d24, d25 ++ vst1.8 {d12-d13}, [r2, : 128] ++ vshl.i32 q6, q13, #1 ++ add r2, sp, #576 ++ vst1.8 {d20-d21}, [r2, : 128] ++ vshl.i32 q10, q14, #1 ++ add r2, sp, #592 ++ vst1.8 {d12-d13}, [r2, : 128] ++ vshl.i32 q15, q12, #1 ++ vadd.i32 q8, q8, q4 ++ vext.32 d10, d31, d30, #0 ++ vadd.i32 q7, q7, q1 ++ add r2, sp, #608 ++ vst1.8 {d16-d17}, [r2, : 128] ++ vmull.s32 q8, d18, d5 ++ vmlal.s32 q8, d26, d4 ++ vmlal.s32 q8, d19, d9 ++ vmlal.s32 q8, d27, d3 ++ vmlal.s32 q8, d22, d8 ++ vmlal.s32 q8, d28, d2 ++ vmlal.s32 q8, d23, d7 ++ vmlal.s32 q8, d29, d1 ++ vmlal.s32 q8, d24, d6 ++ vmlal.s32 q8, d25, d0 ++ add r2, sp, #624 ++ vst1.8 {d14-d15}, [r2, : 128] ++ vmull.s32 q2, d18, d4 ++ vmlal.s32 q2, d12, d9 ++ vmlal.s32 q2, d13, d8 ++ vmlal.s32 q2, d19, d3 ++ vmlal.s32 q2, d22, d2 ++ vmlal.s32 q2, d23, d1 ++ vmlal.s32 q2, d24, d0 ++ add r2, sp, #640 ++ vst1.8 {d20-d21}, [r2, : 128] ++ vmull.s32 q7, d18, d9 ++ vmlal.s32 q7, d26, d3 ++ vmlal.s32 q7, d19, d8 ++ vmlal.s32 q7, d27, d2 ++ vmlal.s32 q7, d22, d7 ++ vmlal.s32 q7, d28, d1 ++ vmlal.s32 q7, d23, d6 ++ vmlal.s32 q7, d29, d0 ++ add r2, sp, #656 ++ vst1.8 {d10-d11}, [r2, : 128] ++ vmull.s32 q5, d18, d3 ++ vmlal.s32 q5, d19, d2 ++ vmlal.s32 q5, d22, d1 ++ vmlal.s32 q5, d23, d0 ++ vmlal.s32 q5, d12, d8 ++ add r2, sp, #672 ++ vst1.8 {d16-d17}, [r2, : 128] ++ vmull.s32 q4, d18, d8 ++ vmlal.s32 q4, d26, d2 ++ vmlal.s32 q4, d19, d7 ++ vmlal.s32 q4, d27, d1 ++ vmlal.s32 q4, d22, d6 ++ vmlal.s32 q4, d28, d0 ++ vmull.s32 q8, d18, d7 ++ vmlal.s32 q8, d26, d1 ++ vmlal.s32 q8, d19, d6 ++ vmlal.s32 q8, d27, d0 ++ add r2, sp, #576 ++ vld1.8 {d20-d21}, [r2, : 128] ++ vmlal.s32 q7, d24, d21 ++ vmlal.s32 q7, d25, d20 ++ vmlal.s32 q4, d23, d21 ++ vmlal.s32 q4, d29, d20 ++ vmlal.s32 q8, d22, d21 ++ vmlal.s32 q8, d28, d20 ++ vmlal.s32 q5, d24, d20 ++ add r2, sp, #576 ++ vst1.8 {d14-d15}, [r2, : 128] ++ vmull.s32 q7, d18, d6 ++ vmlal.s32 q7, d26, d0 ++ add r2, sp, #656 ++ vld1.8 {d30-d31}, [r2, : 128] ++ vmlal.s32 q2, d30, d21 ++ vmlal.s32 q7, d19, d21 ++ vmlal.s32 q7, d27, d20 ++ add r2, sp, #624 ++ vld1.8 {d26-d27}, [r2, : 128] ++ vmlal.s32 q4, d25, d27 ++ vmlal.s32 q8, d29, d27 ++ vmlal.s32 q8, d25, d26 ++ vmlal.s32 q7, d28, d27 ++ vmlal.s32 q7, d29, d26 ++ add r2, sp, #608 ++ vld1.8 {d28-d29}, [r2, : 128] ++ vmlal.s32 q4, d24, d29 ++ vmlal.s32 q8, d23, d29 ++ vmlal.s32 q8, d24, d28 ++ vmlal.s32 q7, d22, d29 ++ vmlal.s32 q7, d23, d28 ++ add r2, sp, #608 ++ vst1.8 {d8-d9}, [r2, : 128] ++ add r2, sp, #560 ++ vld1.8 {d8-d9}, [r2, : 128] ++ vmlal.s32 q7, d24, d9 ++ vmlal.s32 q7, d25, d31 ++ vmull.s32 q1, d18, d2 ++ vmlal.s32 q1, d19, d1 ++ vmlal.s32 q1, d22, d0 ++ vmlal.s32 q1, d24, d27 ++ vmlal.s32 q1, d23, d20 ++ vmlal.s32 q1, d12, d7 ++ vmlal.s32 q1, d13, d6 ++ vmull.s32 q6, d18, d1 ++ vmlal.s32 q6, d19, d0 ++ vmlal.s32 q6, d23, d27 ++ vmlal.s32 q6, d22, d20 ++ vmlal.s32 q6, d24, d26 ++ vmull.s32 q0, d18, d0 ++ vmlal.s32 q0, d22, d27 ++ vmlal.s32 q0, d23, d26 ++ vmlal.s32 q0, d24, d31 ++ vmlal.s32 q0, d19, d20 ++ add r2, sp, #640 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmlal.s32 q2, d18, d7 ++ vmlal.s32 q2, d19, d6 ++ vmlal.s32 q5, d18, d6 ++ vmlal.s32 q5, d19, d21 ++ vmlal.s32 q1, d18, d21 ++ vmlal.s32 q1, d19, d29 ++ vmlal.s32 q0, d18, d28 ++ vmlal.s32 q0, d19, d9 ++ vmlal.s32 q6, d18, d29 ++ vmlal.s32 q6, d19, d28 ++ add r2, sp, #592 ++ vld1.8 {d18-d19}, [r2, : 128] ++ add r2, sp, #512 ++ vld1.8 {d22-d23}, [r2, : 128] ++ vmlal.s32 q5, d19, d7 ++ vmlal.s32 q0, d18, d21 ++ vmlal.s32 q0, d19, d29 ++ vmlal.s32 q6, d18, d6 ++ add r2, sp, #528 ++ vld1.8 {d6-d7}, [r2, : 128] ++ vmlal.s32 q6, d19, d21 ++ add r2, sp, #576 ++ vld1.8 {d18-d19}, [r2, : 128] ++ vmlal.s32 q0, d30, d8 ++ add r2, sp, #672 ++ vld1.8 {d20-d21}, [r2, : 128] ++ vmlal.s32 q5, d30, d29 ++ add r2, sp, #608 ++ vld1.8 {d24-d25}, [r2, : 128] ++ vmlal.s32 q1, d30, d28 ++ vadd.i64 q13, q0, q11 ++ vadd.i64 q14, q5, q11 ++ vmlal.s32 q6, d30, d9 ++ vshr.s64 q4, q13, #26 ++ vshr.s64 q13, q14, #26 ++ vadd.i64 q7, q7, q4 ++ vshl.i64 q4, q4, #26 ++ vadd.i64 q14, q7, q3 ++ vadd.i64 q9, q9, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q15, q9, q3 ++ vsub.i64 q0, q0, q4 ++ vshr.s64 q4, q14, #25 ++ vsub.i64 q5, q5, q13 ++ vshr.s64 q13, q15, #25 ++ vadd.i64 q6, q6, q4 ++ vshl.i64 q4, q4, #25 ++ vadd.i64 q14, q6, q11 ++ vadd.i64 q2, q2, q13 ++ vsub.i64 q4, q7, q4 ++ vshr.s64 q7, q14, #26 ++ vshl.i64 q13, q13, #25 ++ vadd.i64 q14, q2, q11 ++ vadd.i64 q8, q8, q7 ++ vshl.i64 q7, q7, #26 ++ vadd.i64 q15, q8, q3 ++ vsub.i64 q9, q9, q13 ++ vshr.s64 q13, q14, #26 ++ vsub.i64 q6, q6, q7 ++ vshr.s64 q7, q15, #25 ++ vadd.i64 q10, q10, q13 ++ vshl.i64 q13, q13, #26 ++ vadd.i64 q14, q10, q3 ++ vadd.i64 q1, q1, q7 ++ add r2, r3, #240 ++ vshl.i64 q7, q7, #25 ++ add r4, r3, #144 ++ vadd.i64 q15, q1, q11 ++ add r2, r2, #8 ++ vsub.i64 q2, q2, q13 ++ add r4, r4, #8 ++ vshr.s64 q13, q14, #25 ++ vsub.i64 q7, q8, q7 ++ vshr.s64 q8, q15, #26 ++ vadd.i64 q14, q13, q13 ++ vadd.i64 q12, q12, q8 ++ vtrn.32 d12, d14 ++ vshl.i64 q8, q8, #26 ++ vtrn.32 d13, d15 ++ vadd.i64 q3, q12, q3 ++ vadd.i64 q0, q0, q14 ++ vst1.8 d12, [r2, : 64]! ++ vshl.i64 q7, q13, #4 ++ vst1.8 d13, [r4, : 64]! ++ vsub.i64 q1, q1, q8 ++ vshr.s64 q3, q3, #25 ++ vadd.i64 q0, q0, q7 ++ vadd.i64 q5, q5, q3 ++ vshl.i64 q3, q3, #25 ++ vadd.i64 q6, q5, q11 ++ vadd.i64 q0, q0, q13 ++ vshl.i64 q7, q13, #25 ++ vadd.i64 q8, q0, q11 ++ vsub.i64 q3, q12, q3 ++ vshr.s64 q6, q6, #26 ++ vsub.i64 q7, q10, q7 ++ vtrn.32 d2, d6 ++ vshr.s64 q8, q8, #26 ++ vtrn.32 d3, d7 ++ vadd.i64 q3, q9, q6 ++ vst1.8 d2, [r2, : 64] ++ vshl.i64 q6, q6, #26 ++ vst1.8 d3, [r4, : 64] ++ vadd.i64 q1, q4, q8 ++ vtrn.32 d4, d14 ++ vshl.i64 q4, q8, #26 ++ vtrn.32 d5, d15 ++ vsub.i64 q5, q5, q6 ++ add r2, r2, #16 ++ vsub.i64 q0, q0, q4 ++ vst1.8 d4, [r2, : 64] ++ add r4, r4, #16 ++ vst1.8 d5, [r4, : 64] ++ vtrn.32 d10, d6 ++ vtrn.32 d11, d7 ++ sub r2, r2, #8 ++ sub r4, r4, #8 ++ vtrn.32 d0, d2 ++ vtrn.32 d1, d3 ++ vst1.8 d10, [r2, : 64] ++ vst1.8 d11, [r4, : 64] ++ sub r2, r2, #24 ++ sub r4, r4, #24 ++ vst1.8 d0, [r2, : 64] ++ vst1.8 d1, [r4, : 64] ++ ldr r2, [sp, #488] ++ ldr r4, [sp, #492] ++ subs r5, r2, #1 ++ bge ._mainloop ++ add r1, r3, #144 ++ add r2, r3, #336 ++ vld1.8 {d0-d1}, [r1, : 128]! ++ vld1.8 {d2-d3}, [r1, : 128]! ++ vld1.8 {d4}, [r1, : 64] ++ vst1.8 {d0-d1}, [r2, : 128]! ++ vst1.8 {d2-d3}, [r2, : 128]! ++ vst1.8 d4, [r2, : 64] ++ ldr r1, =0 ++._invertloop: ++ add r2, r3, #144 ++ ldr r4, =0 ++ ldr r5, =2 ++ cmp r1, #1 ++ ldreq r5, =1 ++ addeq r2, r3, #336 ++ addeq r4, r3, #48 ++ cmp r1, #2 ++ ldreq r5, =1 ++ addeq r2, r3, #48 ++ cmp r1, #3 ++ ldreq r5, =5 ++ addeq r4, r3, #336 ++ cmp r1, #4 ++ ldreq r5, =10 ++ cmp r1, #5 ++ ldreq r5, =20 ++ cmp r1, #6 ++ ldreq r5, =10 ++ addeq r2, r3, #336 ++ addeq r4, r3, #336 ++ cmp r1, #7 ++ ldreq r5, =50 ++ cmp r1, #8 ++ ldreq r5, =100 ++ cmp r1, #9 ++ ldreq r5, =50 ++ addeq r2, r3, #336 ++ cmp r1, #10 ++ ldreq r5, =5 ++ addeq r2, r3, #48 ++ cmp r1, #11 ++ ldreq r5, =0 ++ addeq r2, r3, #96 ++ add r6, r3, #144 ++ add r7, r3, #288 ++ vld1.8 {d0-d1}, [r6, : 128]! ++ vld1.8 {d2-d3}, [r6, : 128]! ++ vld1.8 {d4}, [r6, : 64] ++ vst1.8 {d0-d1}, [r7, : 128]! ++ vst1.8 {d2-d3}, [r7, : 128]! ++ vst1.8 d4, [r7, : 64] ++ cmp r5, #0 ++ beq ._skipsquaringloop ++._squaringloop: ++ add r6, r3, #288 ++ add r7, r3, #288 ++ add r8, r3, #288 ++ vmov.i32 q0, #19 ++ vmov.i32 q1, #0 ++ vmov.i32 q2, #1 ++ vzip.i32 q1, q2 ++ vld1.8 {d4-d5}, [r7, : 128]! ++ vld1.8 {d6-d7}, [r7, : 128]! ++ vld1.8 {d9}, [r7, : 64] ++ vld1.8 {d10-d11}, [r6, : 128]! ++ add r7, sp, #416 ++ vld1.8 {d12-d13}, [r6, : 128]! ++ vmul.i32 q7, q2, q0 ++ vld1.8 {d8}, [r6, : 64] ++ vext.32 d17, d11, d10, #1 ++ vmul.i32 q9, q3, q0 ++ vext.32 d16, d10, d8, #1 ++ vshl.u32 q10, q5, q1 ++ vext.32 d22, d14, d4, #1 ++ vext.32 d24, d18, d6, #1 ++ vshl.u32 q13, q6, q1 ++ vshl.u32 d28, d8, d2 ++ vrev64.i32 d22, d22 ++ vmul.i32 d1, d9, d1 ++ vrev64.i32 d24, d24 ++ vext.32 d29, d8, d13, #1 ++ vext.32 d0, d1, d9, #1 ++ vrev64.i32 d0, d0 ++ vext.32 d2, d9, d1, #1 ++ vext.32 d23, d15, d5, #1 ++ vmull.s32 q4, d20, d4 ++ vrev64.i32 d23, d23 ++ vmlal.s32 q4, d21, d1 ++ vrev64.i32 d2, d2 ++ vmlal.s32 q4, d26, d19 ++ vext.32 d3, d5, d15, #1 ++ vmlal.s32 q4, d27, d18 ++ vrev64.i32 d3, d3 ++ vmlal.s32 q4, d28, d15 ++ vext.32 d14, d12, d11, #1 ++ vmull.s32 q5, d16, d23 ++ vext.32 d15, d13, d12, #1 ++ vmlal.s32 q5, d17, d4 ++ vst1.8 d8, [r7, : 64]! ++ vmlal.s32 q5, d14, d1 ++ vext.32 d12, d9, d8, #0 ++ vmlal.s32 q5, d15, d19 ++ vmov.i64 d13, #0 ++ vmlal.s32 q5, d29, d18 ++ vext.32 d25, d19, d7, #1 ++ vmlal.s32 q6, d20, d5 ++ vrev64.i32 d25, d25 ++ vmlal.s32 q6, d21, d4 ++ vst1.8 d11, [r7, : 64]! ++ vmlal.s32 q6, d26, d1 ++ vext.32 d9, d10, d10, #0 ++ vmlal.s32 q6, d27, d19 ++ vmov.i64 d8, #0 ++ vmlal.s32 q6, d28, d18 ++ vmlal.s32 q4, d16, d24 ++ vmlal.s32 q4, d17, d5 ++ vmlal.s32 q4, d14, d4 ++ vst1.8 d12, [r7, : 64]! ++ vmlal.s32 q4, d15, d1 ++ vext.32 d10, d13, d12, #0 ++ vmlal.s32 q4, d29, d19 ++ vmov.i64 d11, #0 ++ vmlal.s32 q5, d20, d6 ++ vmlal.s32 q5, d21, d5 ++ vmlal.s32 q5, d26, d4 ++ vext.32 d13, d8, d8, #0 ++ vmlal.s32 q5, d27, d1 ++ vmov.i64 d12, #0 ++ vmlal.s32 q5, d28, d19 ++ vst1.8 d9, [r7, : 64]! ++ vmlal.s32 q6, d16, d25 ++ vmlal.s32 q6, d17, d6 ++ vst1.8 d10, [r7, : 64] ++ vmlal.s32 q6, d14, d5 ++ vext.32 d8, d11, d10, #0 ++ vmlal.s32 q6, d15, d4 ++ vmov.i64 d9, #0 ++ vmlal.s32 q6, d29, d1 ++ vmlal.s32 q4, d20, d7 ++ vmlal.s32 q4, d21, d6 ++ vmlal.s32 q4, d26, d5 ++ vext.32 d11, d12, d12, #0 ++ vmlal.s32 q4, d27, d4 ++ vmov.i64 d10, #0 ++ vmlal.s32 q4, d28, d1 ++ vmlal.s32 q5, d16, d0 ++ sub r6, r7, #32 ++ vmlal.s32 q5, d17, d7 ++ vmlal.s32 q5, d14, d6 ++ vext.32 d30, d9, d8, #0 ++ vmlal.s32 q5, d15, d5 ++ vld1.8 {d31}, [r6, : 64]! ++ vmlal.s32 q5, d29, d4 ++ vmlal.s32 q15, d20, d0 ++ vext.32 d0, d6, d18, #1 ++ vmlal.s32 q15, d21, d25 ++ vrev64.i32 d0, d0 ++ vmlal.s32 q15, d26, d24 ++ vext.32 d1, d7, d19, #1 ++ vext.32 d7, d10, d10, #0 ++ vmlal.s32 q15, d27, d23 ++ vrev64.i32 d1, d1 ++ vld1.8 {d6}, [r6, : 64] ++ vmlal.s32 q15, d28, d22 ++ vmlal.s32 q3, d16, d4 ++ add r6, r6, #24 ++ vmlal.s32 q3, d17, d2 ++ vext.32 d4, d31, d30, #0 ++ vmov d17, d11 ++ vmlal.s32 q3, d14, d1 ++ vext.32 d11, d13, d13, #0 ++ vext.32 d13, d30, d30, #0 ++ vmlal.s32 q3, d15, d0 ++ vext.32 d1, d8, d8, #0 ++ vmlal.s32 q3, d29, d3 ++ vld1.8 {d5}, [r6, : 64] ++ sub r6, r6, #16 ++ vext.32 d10, d6, d6, #0 ++ vmov.i32 q1, #0xffffffff ++ vshl.i64 q4, q1, #25 ++ add r7, sp, #512 ++ vld1.8 {d14-d15}, [r7, : 128] ++ vadd.i64 q9, q2, q7 ++ vshl.i64 q1, q1, #26 ++ vshr.s64 q10, q9, #26 ++ vld1.8 {d0}, [r6, : 64]! ++ vadd.i64 q5, q5, q10 ++ vand q9, q9, q1 ++ vld1.8 {d16}, [r6, : 64]! ++ add r6, sp, #528 ++ vld1.8 {d20-d21}, [r6, : 128] ++ vadd.i64 q11, q5, q10 ++ vsub.i64 q2, q2, q9 ++ vshr.s64 q9, q11, #25 ++ vext.32 d12, d5, d4, #0 ++ vand q11, q11, q4 ++ vadd.i64 q0, q0, q9 ++ vmov d19, d7 ++ vadd.i64 q3, q0, q7 ++ vsub.i64 q5, q5, q11 ++ vshr.s64 q11, q3, #26 ++ vext.32 d18, d11, d10, #0 ++ vand q3, q3, q1 ++ vadd.i64 q8, q8, q11 ++ vadd.i64 q11, q8, q10 ++ vsub.i64 q0, q0, q3 ++ vshr.s64 q3, q11, #25 ++ vand q11, q11, q4 ++ vadd.i64 q3, q6, q3 ++ vadd.i64 q6, q3, q7 ++ vsub.i64 q8, q8, q11 ++ vshr.s64 q11, q6, #26 ++ vand q6, q6, q1 ++ vadd.i64 q9, q9, q11 ++ vadd.i64 d25, d19, d21 ++ vsub.i64 q3, q3, q6 ++ vshr.s64 d23, d25, #25 ++ vand q4, q12, q4 ++ vadd.i64 d21, d23, d23 ++ vshl.i64 d25, d23, #4 ++ vadd.i64 d21, d21, d23 ++ vadd.i64 d25, d25, d21 ++ vadd.i64 d4, d4, d25 ++ vzip.i32 q0, q8 ++ vadd.i64 d12, d4, d14 ++ add r6, r8, #8 ++ vst1.8 d0, [r6, : 64] ++ vsub.i64 d19, d19, d9 ++ add r6, r6, #16 ++ vst1.8 d16, [r6, : 64] ++ vshr.s64 d22, d12, #26 ++ vand q0, q6, q1 ++ vadd.i64 d10, d10, d22 ++ vzip.i32 q3, q9 ++ vsub.i64 d4, d4, d0 ++ sub r6, r6, #8 ++ vst1.8 d6, [r6, : 64] ++ add r6, r6, #16 ++ vst1.8 d18, [r6, : 64] ++ vzip.i32 q2, q5 ++ sub r6, r6, #32 ++ vst1.8 d4, [r6, : 64] ++ subs r5, r5, #1 ++ bhi ._squaringloop ++._skipsquaringloop: ++ mov r2, r2 ++ add r5, r3, #288 ++ add r6, r3, #144 ++ vmov.i32 q0, #19 ++ vmov.i32 q1, #0 ++ vmov.i32 q2, #1 ++ vzip.i32 q1, q2 ++ vld1.8 {d4-d5}, [r5, : 128]! ++ vld1.8 {d6-d7}, [r5, : 128]! ++ vld1.8 {d9}, [r5, : 64] ++ vld1.8 {d10-d11}, [r2, : 128]! ++ add r5, sp, #416 ++ vld1.8 {d12-d13}, [r2, : 128]! ++ vmul.i32 q7, q2, q0 ++ vld1.8 {d8}, [r2, : 64] ++ vext.32 d17, d11, d10, #1 ++ vmul.i32 q9, q3, q0 ++ vext.32 d16, d10, d8, #1 ++ vshl.u32 q10, q5, q1 ++ vext.32 d22, d14, d4, #1 ++ vext.32 d24, d18, d6, #1 ++ vshl.u32 q13, q6, q1 ++ vshl.u32 d28, d8, d2 ++ vrev64.i32 d22, d22 ++ vmul.i32 d1, d9, d1 ++ vrev64.i32 d24, d24 ++ vext.32 d29, d8, d13, #1 ++ vext.32 d0, d1, d9, #1 ++ vrev64.i32 d0, d0 ++ vext.32 d2, d9, d1, #1 ++ vext.32 d23, d15, d5, #1 ++ vmull.s32 q4, d20, d4 ++ vrev64.i32 d23, d23 ++ vmlal.s32 q4, d21, d1 ++ vrev64.i32 d2, d2 ++ vmlal.s32 q4, d26, d19 ++ vext.32 d3, d5, d15, #1 ++ vmlal.s32 q4, d27, d18 ++ vrev64.i32 d3, d3 ++ vmlal.s32 q4, d28, d15 ++ vext.32 d14, d12, d11, #1 ++ vmull.s32 q5, d16, d23 ++ vext.32 d15, d13, d12, #1 ++ vmlal.s32 q5, d17, d4 ++ vst1.8 d8, [r5, : 64]! ++ vmlal.s32 q5, d14, d1 ++ vext.32 d12, d9, d8, #0 ++ vmlal.s32 q5, d15, d19 ++ vmov.i64 d13, #0 ++ vmlal.s32 q5, d29, d18 ++ vext.32 d25, d19, d7, #1 ++ vmlal.s32 q6, d20, d5 ++ vrev64.i32 d25, d25 ++ vmlal.s32 q6, d21, d4 ++ vst1.8 d11, [r5, : 64]! ++ vmlal.s32 q6, d26, d1 ++ vext.32 d9, d10, d10, #0 ++ vmlal.s32 q6, d27, d19 ++ vmov.i64 d8, #0 ++ vmlal.s32 q6, d28, d18 ++ vmlal.s32 q4, d16, d24 ++ vmlal.s32 q4, d17, d5 ++ vmlal.s32 q4, d14, d4 ++ vst1.8 d12, [r5, : 64]! ++ vmlal.s32 q4, d15, d1 ++ vext.32 d10, d13, d12, #0 ++ vmlal.s32 q4, d29, d19 ++ vmov.i64 d11, #0 ++ vmlal.s32 q5, d20, d6 ++ vmlal.s32 q5, d21, d5 ++ vmlal.s32 q5, d26, d4 ++ vext.32 d13, d8, d8, #0 ++ vmlal.s32 q5, d27, d1 ++ vmov.i64 d12, #0 ++ vmlal.s32 q5, d28, d19 ++ vst1.8 d9, [r5, : 64]! ++ vmlal.s32 q6, d16, d25 ++ vmlal.s32 q6, d17, d6 ++ vst1.8 d10, [r5, : 64] ++ vmlal.s32 q6, d14, d5 ++ vext.32 d8, d11, d10, #0 ++ vmlal.s32 q6, d15, d4 ++ vmov.i64 d9, #0 ++ vmlal.s32 q6, d29, d1 ++ vmlal.s32 q4, d20, d7 ++ vmlal.s32 q4, d21, d6 ++ vmlal.s32 q4, d26, d5 ++ vext.32 d11, d12, d12, #0 ++ vmlal.s32 q4, d27, d4 ++ vmov.i64 d10, #0 ++ vmlal.s32 q4, d28, d1 ++ vmlal.s32 q5, d16, d0 ++ sub r2, r5, #32 ++ vmlal.s32 q5, d17, d7 ++ vmlal.s32 q5, d14, d6 ++ vext.32 d30, d9, d8, #0 ++ vmlal.s32 q5, d15, d5 ++ vld1.8 {d31}, [r2, : 64]! ++ vmlal.s32 q5, d29, d4 ++ vmlal.s32 q15, d20, d0 ++ vext.32 d0, d6, d18, #1 ++ vmlal.s32 q15, d21, d25 ++ vrev64.i32 d0, d0 ++ vmlal.s32 q15, d26, d24 ++ vext.32 d1, d7, d19, #1 ++ vext.32 d7, d10, d10, #0 ++ vmlal.s32 q15, d27, d23 ++ vrev64.i32 d1, d1 ++ vld1.8 {d6}, [r2, : 64] ++ vmlal.s32 q15, d28, d22 ++ vmlal.s32 q3, d16, d4 ++ add r2, r2, #24 ++ vmlal.s32 q3, d17, d2 ++ vext.32 d4, d31, d30, #0 ++ vmov d17, d11 ++ vmlal.s32 q3, d14, d1 ++ vext.32 d11, d13, d13, #0 ++ vext.32 d13, d30, d30, #0 ++ vmlal.s32 q3, d15, d0 ++ vext.32 d1, d8, d8, #0 ++ vmlal.s32 q3, d29, d3 ++ vld1.8 {d5}, [r2, : 64] ++ sub r2, r2, #16 ++ vext.32 d10, d6, d6, #0 ++ vmov.i32 q1, #0xffffffff ++ vshl.i64 q4, q1, #25 ++ add r5, sp, #512 ++ vld1.8 {d14-d15}, [r5, : 128] ++ vadd.i64 q9, q2, q7 ++ vshl.i64 q1, q1, #26 ++ vshr.s64 q10, q9, #26 ++ vld1.8 {d0}, [r2, : 64]! ++ vadd.i64 q5, q5, q10 ++ vand q9, q9, q1 ++ vld1.8 {d16}, [r2, : 64]! ++ add r2, sp, #528 ++ vld1.8 {d20-d21}, [r2, : 128] ++ vadd.i64 q11, q5, q10 ++ vsub.i64 q2, q2, q9 ++ vshr.s64 q9, q11, #25 ++ vext.32 d12, d5, d4, #0 ++ vand q11, q11, q4 ++ vadd.i64 q0, q0, q9 ++ vmov d19, d7 ++ vadd.i64 q3, q0, q7 ++ vsub.i64 q5, q5, q11 ++ vshr.s64 q11, q3, #26 ++ vext.32 d18, d11, d10, #0 ++ vand q3, q3, q1 ++ vadd.i64 q8, q8, q11 ++ vadd.i64 q11, q8, q10 ++ vsub.i64 q0, q0, q3 ++ vshr.s64 q3, q11, #25 ++ vand q11, q11, q4 ++ vadd.i64 q3, q6, q3 ++ vadd.i64 q6, q3, q7 ++ vsub.i64 q8, q8, q11 ++ vshr.s64 q11, q6, #26 ++ vand q6, q6, q1 ++ vadd.i64 q9, q9, q11 ++ vadd.i64 d25, d19, d21 ++ vsub.i64 q3, q3, q6 ++ vshr.s64 d23, d25, #25 ++ vand q4, q12, q4 ++ vadd.i64 d21, d23, d23 ++ vshl.i64 d25, d23, #4 ++ vadd.i64 d21, d21, d23 ++ vadd.i64 d25, d25, d21 ++ vadd.i64 d4, d4, d25 ++ vzip.i32 q0, q8 ++ vadd.i64 d12, d4, d14 ++ add r2, r6, #8 ++ vst1.8 d0, [r2, : 64] ++ vsub.i64 d19, d19, d9 ++ add r2, r2, #16 ++ vst1.8 d16, [r2, : 64] ++ vshr.s64 d22, d12, #26 ++ vand q0, q6, q1 ++ vadd.i64 d10, d10, d22 ++ vzip.i32 q3, q9 ++ vsub.i64 d4, d4, d0 ++ sub r2, r2, #8 ++ vst1.8 d6, [r2, : 64] ++ add r2, r2, #16 ++ vst1.8 d18, [r2, : 64] ++ vzip.i32 q2, q5 ++ sub r2, r2, #32 ++ vst1.8 d4, [r2, : 64] ++ cmp r4, #0 ++ beq ._skippostcopy ++ add r2, r3, #144 ++ mov r4, r4 ++ vld1.8 {d0-d1}, [r2, : 128]! ++ vld1.8 {d2-d3}, [r2, : 128]! ++ vld1.8 {d4}, [r2, : 64] ++ vst1.8 {d0-d1}, [r4, : 128]! ++ vst1.8 {d2-d3}, [r4, : 128]! ++ vst1.8 d4, [r4, : 64] ++._skippostcopy: ++ cmp r1, #1 ++ bne ._skipfinalcopy ++ add r2, r3, #288 ++ add r4, r3, #144 ++ vld1.8 {d0-d1}, [r2, : 128]! ++ vld1.8 {d2-d3}, [r2, : 128]! ++ vld1.8 {d4}, [r2, : 64] ++ vst1.8 {d0-d1}, [r4, : 128]! ++ vst1.8 {d2-d3}, [r4, : 128]! ++ vst1.8 d4, [r4, : 64] ++._skipfinalcopy: ++ add r1, r1, #1 ++ cmp r1, #12 ++ blo ._invertloop ++ add r1, r3, #144 ++ ldr r2, [r1], #4 ++ ldr r3, [r1], #4 ++ ldr r4, [r1], #4 ++ ldr r5, [r1], #4 ++ ldr r6, [r1], #4 ++ ldr r7, [r1], #4 ++ ldr r8, [r1], #4 ++ ldr r9, [r1], #4 ++ ldr r10, [r1], #4 ++ ldr r1, [r1] ++ add r11, r1, r1, LSL #4 ++ add r11, r11, r1, LSL #1 ++ add r11, r11, #16777216 ++ mov r11, r11, ASR #25 ++ add r11, r11, r2 ++ mov r11, r11, ASR #26 ++ add r11, r11, r3 ++ mov r11, r11, ASR #25 ++ add r11, r11, r4 ++ mov r11, r11, ASR #26 ++ add r11, r11, r5 ++ mov r11, r11, ASR #25 ++ add r11, r11, r6 ++ mov r11, r11, ASR #26 ++ add r11, r11, r7 ++ mov r11, r11, ASR #25 ++ add r11, r11, r8 ++ mov r11, r11, ASR #26 ++ add r11, r11, r9 ++ mov r11, r11, ASR #25 ++ add r11, r11, r10 ++ mov r11, r11, ASR #26 ++ add r11, r11, r1 ++ mov r11, r11, ASR #25 ++ add r2, r2, r11 ++ add r2, r2, r11, LSL #1 ++ add r2, r2, r11, LSL #4 ++ mov r11, r2, ASR #26 ++ add r3, r3, r11 ++ sub r2, r2, r11, LSL #26 ++ mov r11, r3, ASR #25 ++ add r4, r4, r11 ++ sub r3, r3, r11, LSL #25 ++ mov r11, r4, ASR #26 ++ add r5, r5, r11 ++ sub r4, r4, r11, LSL #26 ++ mov r11, r5, ASR #25 ++ add r6, r6, r11 ++ sub r5, r5, r11, LSL #25 ++ mov r11, r6, ASR #26 ++ add r7, r7, r11 ++ sub r6, r6, r11, LSL #26 ++ mov r11, r7, ASR #25 ++ add r8, r8, r11 ++ sub r7, r7, r11, LSL #25 ++ mov r11, r8, ASR #26 ++ add r9, r9, r11 ++ sub r8, r8, r11, LSL #26 ++ mov r11, r9, ASR #25 ++ add r10, r10, r11 ++ sub r9, r9, r11, LSL #25 ++ mov r11, r10, ASR #26 ++ add r1, r1, r11 ++ sub r10, r10, r11, LSL #26 ++ mov r11, r1, ASR #25 ++ sub r1, r1, r11, LSL #25 ++ add r2, r2, r3, LSL #26 ++ mov r3, r3, LSR #6 ++ add r3, r3, r4, LSL #19 ++ mov r4, r4, LSR #13 ++ add r4, r4, r5, LSL #13 ++ mov r5, r5, LSR #19 ++ add r5, r5, r6, LSL #6 ++ add r6, r7, r8, LSL #25 ++ mov r7, r8, LSR #7 ++ add r7, r7, r9, LSL #19 ++ mov r8, r9, LSR #13 ++ add r8, r8, r10, LSL #12 ++ mov r9, r10, LSR #20 ++ add r1, r9, r1, LSL #6 ++ str r2, [r0], #4 ++ str r3, [r0], #4 ++ str r4, [r0], #4 ++ str r5, [r0], #4 ++ str r6, [r0], #4 ++ str r7, [r0], #4 ++ str r8, [r0], #4 ++ str r1, [r0] ++ ldrd r4, [sp, #0] ++ ldrd r6, [sp, #8] ++ ldrd r8, [sp, #16] ++ ldrd r10, [sp, #24] ++ ldr r12, [sp, #480] ++ ldr r14, [sp, #484] ++ ldr r0, =0 ++ mov sp, r12 ++ vpop {q4, q5, q6, q7} ++ bx lr diff --git a/ipq806x/backport-5.4/080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch b/ipq806x/backport-5.4/080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch new file mode 100644 index 0000000..d84726b --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0031-crypto-arm-curve25519-wire-up-NEON-implementation.patch @@ -0,0 +1,1058 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 8 Nov 2019 13:22:38 +0100 +Subject: [PATCH] crypto: arm/curve25519 - wire up NEON implementation + +commit d8f1308a025fc7e00414194ed742d5f05a21e13c upstream. + +This ports the SUPERCOP implementation for usage in kernel space. In +addition to the usual header, macro, and style changes required for +kernel space, it makes a few small changes to the code: + + - The stack alignment is relaxed to 16 bytes. + - Superfluous mov statements have been removed. + - ldr for constants has been replaced with movw. + - ldreq has been replaced with moveq. + - The str epilogue has been made more idiomatic. + - SIMD registers are not pushed and popped at the beginning and end. + - The prologue and epilogue have been made idiomatic. + - A hole has been removed from the stack, saving 32 bytes. + - We write-back the base register whenever possible for vld1.8. + - Some multiplications have been reordered for better A7 performance. + +There are more opportunities for cleanup, since this code is from qhasm, +which doesn't always do the most opportune thing. But even prior to +extensive hand optimizations, this code delivers significant performance +improvements (given in get_cycles() per call): + + ----------- ------------- + | generic C | this commit | + ------------ ----------- ------------- + | Cortex-A7 | 49136 | 22395 | + ------------ ----------- ------------- + | Cortex-A17 | 17326 | 4983 | + ------------ ----------- ------------- + +Signed-off-by: Jason A. Donenfeld +[ardb: - move to arch/arm/crypto + - wire into lib/crypto framework + - implement crypto API KPP hooks ] +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/Kconfig | 6 + + arch/arm/crypto/Makefile | 2 + + arch/arm/crypto/curve25519-core.S | 347 +++++++++++++----------------- + arch/arm/crypto/curve25519-glue.c | 127 +++++++++++ + 4 files changed, 287 insertions(+), 195 deletions(-) + create mode 100644 arch/arm/crypto/curve25519-glue.c + +--- a/arch/arm/crypto/Kconfig ++++ b/arch/arm/crypto/Kconfig +@@ -141,4 +141,10 @@ config CRYPTO_NHPOLY1305_NEON + depends on KERNEL_MODE_NEON + select CRYPTO_NHPOLY1305 + ++config CRYPTO_CURVE25519_NEON ++ tristate "NEON accelerated Curve25519 scalar multiplication library" ++ depends on KERNEL_MODE_NEON ++ select CRYPTO_LIB_CURVE25519_GENERIC ++ select CRYPTO_ARCH_HAVE_LIB_CURVE25519 ++ + endif +--- a/arch/arm/crypto/Makefile ++++ b/arch/arm/crypto/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_CRYPTO_SHA512_ARM) += sha51 + obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o + obj-$(CONFIG_CRYPTO_POLY1305_ARM) += poly1305-arm.o + obj-$(CONFIG_CRYPTO_NHPOLY1305_NEON) += nhpoly1305-neon.o ++obj-$(CONFIG_CRYPTO_CURVE25519_NEON) += curve25519-neon.o + + ce-obj-$(CONFIG_CRYPTO_AES_ARM_CE) += aes-arm-ce.o + ce-obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o +@@ -58,6 +59,7 @@ chacha-neon-y := chacha-scalar-core.o ch + chacha-neon-$(CONFIG_KERNEL_MODE_NEON) += chacha-neon-core.o + poly1305-arm-y := poly1305-core.o poly1305-glue.o + nhpoly1305-neon-y := nh-neon-core.o nhpoly1305-neon-glue.o ++curve25519-neon-y := curve25519-core.o curve25519-glue.o + + ifdef REGENERATE_ARM_CRYPTO + quiet_cmd_perl = PERL $@ +--- a/arch/arm/crypto/curve25519-core.S ++++ b/arch/arm/crypto/curve25519-core.S +@@ -1,43 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ + /* +- * Public domain code from Daniel J. Bernstein and Peter Schwabe, from +- * SUPERCOP's curve25519/neon2/scalarmult.s. ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * Based on public domain code from Daniel J. Bernstein and Peter Schwabe. This ++ * began from SUPERCOP's curve25519/neon2/scalarmult.s, but has subsequently been ++ * manually reworked for use in kernel space. + */ + +-.fpu neon ++#include ++ + .text ++.fpu neon ++.arch armv7-a + .align 4 +-.global _crypto_scalarmult_curve25519_neon2 +-.global crypto_scalarmult_curve25519_neon2 +-.type _crypto_scalarmult_curve25519_neon2 STT_FUNC +-.type crypto_scalarmult_curve25519_neon2 STT_FUNC +- _crypto_scalarmult_curve25519_neon2: +- crypto_scalarmult_curve25519_neon2: +- vpush {q4, q5, q6, q7} +- mov r12, sp +- sub sp, sp, #736 +- and sp, sp, #0xffffffe0 +- strd r4, [sp, #0] +- strd r6, [sp, #8] +- strd r8, [sp, #16] +- strd r10, [sp, #24] +- str r12, [sp, #480] +- str r14, [sp, #484] +- mov r0, r0 +- mov r1, r1 +- mov r2, r2 +- add r3, sp, #32 +- ldr r4, =0 +- ldr r5, =254 ++ ++ENTRY(curve25519_neon) ++ push {r4-r11, lr} ++ mov ip, sp ++ sub r3, sp, #704 ++ and r3, r3, #0xfffffff0 ++ mov sp, r3 ++ movw r4, #0 ++ movw r5, #254 + vmov.i32 q0, #1 + vshr.u64 q1, q0, #7 + vshr.u64 q0, q0, #8 + vmov.i32 d4, #19 + vmov.i32 d5, #38 +- add r6, sp, #512 +- vst1.8 {d2-d3}, [r6, : 128] +- add r6, sp, #528 +- vst1.8 {d0-d1}, [r6, : 128] +- add r6, sp, #544 ++ add r6, sp, #480 ++ vst1.8 {d2-d3}, [r6, : 128]! ++ vst1.8 {d0-d1}, [r6, : 128]! + vst1.8 {d4-d5}, [r6, : 128] + add r6, r3, #0 + vmov.i32 q2, #0 +@@ -45,12 +37,12 @@ + vst1.8 {d4-d5}, [r6, : 128]! + vst1.8 d4, [r6, : 64] + add r6, r3, #0 +- ldr r7, =960 ++ movw r7, #960 + sub r7, r7, #2 + neg r7, r7 + sub r7, r7, r7, LSL #7 + str r7, [r6] +- add r6, sp, #704 ++ add r6, sp, #672 + vld1.8 {d4-d5}, [r1]! + vld1.8 {d6-d7}, [r1] + vst1.8 {d4-d5}, [r6, : 128]! +@@ -212,15 +204,15 @@ + vst1.8 {d0-d1}, [r6, : 128]! + vst1.8 {d2-d3}, [r6, : 128]! + vst1.8 d4, [r6, : 64] +-._mainloop: ++.Lmainloop: + mov r2, r5, LSR #3 + and r6, r5, #7 + ldrb r2, [r1, r2] + mov r2, r2, LSR r6 + and r2, r2, #1 +- str r5, [sp, #488] ++ str r5, [sp, #456] + eor r4, r4, r2 +- str r2, [sp, #492] ++ str r2, [sp, #460] + neg r2, r4 + add r4, r3, #96 + add r5, r3, #192 +@@ -291,7 +283,7 @@ + vsub.i32 q0, q1, q3 + vst1.8 d4, [r4, : 64] + vst1.8 d0, [r6, : 64] +- add r2, sp, #544 ++ add r2, sp, #512 + add r4, r3, #96 + add r5, r3, #144 + vld1.8 {d0-d1}, [r2, : 128] +@@ -361,14 +353,13 @@ + vmlal.s32 q0, d12, d8 + vmlal.s32 q0, d13, d17 + vmlal.s32 q0, d6, d6 +- add r2, sp, #512 +- vld1.8 {d18-d19}, [r2, : 128] ++ add r2, sp, #480 ++ vld1.8 {d18-d19}, [r2, : 128]! + vmull.s32 q3, d16, d7 + vmlal.s32 q3, d10, d15 + vmlal.s32 q3, d11, d14 + vmlal.s32 q3, d12, d9 + vmlal.s32 q3, d13, d8 +- add r2, sp, #528 + vld1.8 {d8-d9}, [r2, : 128] + vadd.i64 q5, q12, q9 + vadd.i64 q6, q15, q9 +@@ -502,22 +493,19 @@ + vadd.i32 q5, q5, q0 + vtrn.32 q11, q14 + vadd.i32 q6, q6, q3 +- add r2, sp, #560 ++ add r2, sp, #528 + vadd.i32 q10, q10, q2 + vtrn.32 d24, d25 +- vst1.8 {d12-d13}, [r2, : 128] ++ vst1.8 {d12-d13}, [r2, : 128]! + vshl.i32 q6, q13, #1 +- add r2, sp, #576 +- vst1.8 {d20-d21}, [r2, : 128] ++ vst1.8 {d20-d21}, [r2, : 128]! + vshl.i32 q10, q14, #1 +- add r2, sp, #592 +- vst1.8 {d12-d13}, [r2, : 128] ++ vst1.8 {d12-d13}, [r2, : 128]! + vshl.i32 q15, q12, #1 + vadd.i32 q8, q8, q4 + vext.32 d10, d31, d30, #0 + vadd.i32 q7, q7, q1 +- add r2, sp, #608 +- vst1.8 {d16-d17}, [r2, : 128] ++ vst1.8 {d16-d17}, [r2, : 128]! + vmull.s32 q8, d18, d5 + vmlal.s32 q8, d26, d4 + vmlal.s32 q8, d19, d9 +@@ -528,8 +516,7 @@ + vmlal.s32 q8, d29, d1 + vmlal.s32 q8, d24, d6 + vmlal.s32 q8, d25, d0 +- add r2, sp, #624 +- vst1.8 {d14-d15}, [r2, : 128] ++ vst1.8 {d14-d15}, [r2, : 128]! + vmull.s32 q2, d18, d4 + vmlal.s32 q2, d12, d9 + vmlal.s32 q2, d13, d8 +@@ -537,8 +524,7 @@ + vmlal.s32 q2, d22, d2 + vmlal.s32 q2, d23, d1 + vmlal.s32 q2, d24, d0 +- add r2, sp, #640 +- vst1.8 {d20-d21}, [r2, : 128] ++ vst1.8 {d20-d21}, [r2, : 128]! + vmull.s32 q7, d18, d9 + vmlal.s32 q7, d26, d3 + vmlal.s32 q7, d19, d8 +@@ -547,14 +533,12 @@ + vmlal.s32 q7, d28, d1 + vmlal.s32 q7, d23, d6 + vmlal.s32 q7, d29, d0 +- add r2, sp, #656 +- vst1.8 {d10-d11}, [r2, : 128] ++ vst1.8 {d10-d11}, [r2, : 128]! + vmull.s32 q5, d18, d3 + vmlal.s32 q5, d19, d2 + vmlal.s32 q5, d22, d1 + vmlal.s32 q5, d23, d0 + vmlal.s32 q5, d12, d8 +- add r2, sp, #672 + vst1.8 {d16-d17}, [r2, : 128] + vmull.s32 q4, d18, d8 + vmlal.s32 q4, d26, d2 +@@ -566,7 +550,7 @@ + vmlal.s32 q8, d26, d1 + vmlal.s32 q8, d19, d6 + vmlal.s32 q8, d27, d0 +- add r2, sp, #576 ++ add r2, sp, #544 + vld1.8 {d20-d21}, [r2, : 128] + vmlal.s32 q7, d24, d21 + vmlal.s32 q7, d25, d20 +@@ -575,32 +559,30 @@ + vmlal.s32 q8, d22, d21 + vmlal.s32 q8, d28, d20 + vmlal.s32 q5, d24, d20 +- add r2, sp, #576 + vst1.8 {d14-d15}, [r2, : 128] + vmull.s32 q7, d18, d6 + vmlal.s32 q7, d26, d0 +- add r2, sp, #656 ++ add r2, sp, #624 + vld1.8 {d30-d31}, [r2, : 128] + vmlal.s32 q2, d30, d21 + vmlal.s32 q7, d19, d21 + vmlal.s32 q7, d27, d20 +- add r2, sp, #624 ++ add r2, sp, #592 + vld1.8 {d26-d27}, [r2, : 128] + vmlal.s32 q4, d25, d27 + vmlal.s32 q8, d29, d27 + vmlal.s32 q8, d25, d26 + vmlal.s32 q7, d28, d27 + vmlal.s32 q7, d29, d26 +- add r2, sp, #608 ++ add r2, sp, #576 + vld1.8 {d28-d29}, [r2, : 128] + vmlal.s32 q4, d24, d29 + vmlal.s32 q8, d23, d29 + vmlal.s32 q8, d24, d28 + vmlal.s32 q7, d22, d29 + vmlal.s32 q7, d23, d28 +- add r2, sp, #608 + vst1.8 {d8-d9}, [r2, : 128] +- add r2, sp, #560 ++ add r2, sp, #528 + vld1.8 {d8-d9}, [r2, : 128] + vmlal.s32 q7, d24, d9 + vmlal.s32 q7, d25, d31 +@@ -621,36 +603,36 @@ + vmlal.s32 q0, d23, d26 + vmlal.s32 q0, d24, d31 + vmlal.s32 q0, d19, d20 +- add r2, sp, #640 ++ add r2, sp, #608 + vld1.8 {d18-d19}, [r2, : 128] + vmlal.s32 q2, d18, d7 +- vmlal.s32 q2, d19, d6 + vmlal.s32 q5, d18, d6 +- vmlal.s32 q5, d19, d21 + vmlal.s32 q1, d18, d21 +- vmlal.s32 q1, d19, d29 + vmlal.s32 q0, d18, d28 +- vmlal.s32 q0, d19, d9 + vmlal.s32 q6, d18, d29 ++ vmlal.s32 q2, d19, d6 ++ vmlal.s32 q5, d19, d21 ++ vmlal.s32 q1, d19, d29 ++ vmlal.s32 q0, d19, d9 + vmlal.s32 q6, d19, d28 +- add r2, sp, #592 ++ add r2, sp, #560 + vld1.8 {d18-d19}, [r2, : 128] +- add r2, sp, #512 ++ add r2, sp, #480 + vld1.8 {d22-d23}, [r2, : 128] + vmlal.s32 q5, d19, d7 + vmlal.s32 q0, d18, d21 + vmlal.s32 q0, d19, d29 + vmlal.s32 q6, d18, d6 +- add r2, sp, #528 ++ add r2, sp, #496 + vld1.8 {d6-d7}, [r2, : 128] + vmlal.s32 q6, d19, d21 +- add r2, sp, #576 ++ add r2, sp, #544 + vld1.8 {d18-d19}, [r2, : 128] + vmlal.s32 q0, d30, d8 +- add r2, sp, #672 ++ add r2, sp, #640 + vld1.8 {d20-d21}, [r2, : 128] + vmlal.s32 q5, d30, d29 +- add r2, sp, #608 ++ add r2, sp, #576 + vld1.8 {d24-d25}, [r2, : 128] + vmlal.s32 q1, d30, d28 + vadd.i64 q13, q0, q11 +@@ -823,22 +805,19 @@ + vadd.i32 q5, q5, q0 + vtrn.32 q11, q14 + vadd.i32 q6, q6, q3 +- add r2, sp, #560 ++ add r2, sp, #528 + vadd.i32 q10, q10, q2 + vtrn.32 d24, d25 +- vst1.8 {d12-d13}, [r2, : 128] ++ vst1.8 {d12-d13}, [r2, : 128]! + vshl.i32 q6, q13, #1 +- add r2, sp, #576 +- vst1.8 {d20-d21}, [r2, : 128] ++ vst1.8 {d20-d21}, [r2, : 128]! + vshl.i32 q10, q14, #1 +- add r2, sp, #592 +- vst1.8 {d12-d13}, [r2, : 128] ++ vst1.8 {d12-d13}, [r2, : 128]! + vshl.i32 q15, q12, #1 + vadd.i32 q8, q8, q4 + vext.32 d10, d31, d30, #0 + vadd.i32 q7, q7, q1 +- add r2, sp, #608 +- vst1.8 {d16-d17}, [r2, : 128] ++ vst1.8 {d16-d17}, [r2, : 128]! + vmull.s32 q8, d18, d5 + vmlal.s32 q8, d26, d4 + vmlal.s32 q8, d19, d9 +@@ -849,8 +828,7 @@ + vmlal.s32 q8, d29, d1 + vmlal.s32 q8, d24, d6 + vmlal.s32 q8, d25, d0 +- add r2, sp, #624 +- vst1.8 {d14-d15}, [r2, : 128] ++ vst1.8 {d14-d15}, [r2, : 128]! + vmull.s32 q2, d18, d4 + vmlal.s32 q2, d12, d9 + vmlal.s32 q2, d13, d8 +@@ -858,8 +836,7 @@ + vmlal.s32 q2, d22, d2 + vmlal.s32 q2, d23, d1 + vmlal.s32 q2, d24, d0 +- add r2, sp, #640 +- vst1.8 {d20-d21}, [r2, : 128] ++ vst1.8 {d20-d21}, [r2, : 128]! + vmull.s32 q7, d18, d9 + vmlal.s32 q7, d26, d3 + vmlal.s32 q7, d19, d8 +@@ -868,15 +845,13 @@ + vmlal.s32 q7, d28, d1 + vmlal.s32 q7, d23, d6 + vmlal.s32 q7, d29, d0 +- add r2, sp, #656 +- vst1.8 {d10-d11}, [r2, : 128] ++ vst1.8 {d10-d11}, [r2, : 128]! + vmull.s32 q5, d18, d3 + vmlal.s32 q5, d19, d2 + vmlal.s32 q5, d22, d1 + vmlal.s32 q5, d23, d0 + vmlal.s32 q5, d12, d8 +- add r2, sp, #672 +- vst1.8 {d16-d17}, [r2, : 128] ++ vst1.8 {d16-d17}, [r2, : 128]! + vmull.s32 q4, d18, d8 + vmlal.s32 q4, d26, d2 + vmlal.s32 q4, d19, d7 +@@ -887,7 +862,7 @@ + vmlal.s32 q8, d26, d1 + vmlal.s32 q8, d19, d6 + vmlal.s32 q8, d27, d0 +- add r2, sp, #576 ++ add r2, sp, #544 + vld1.8 {d20-d21}, [r2, : 128] + vmlal.s32 q7, d24, d21 + vmlal.s32 q7, d25, d20 +@@ -896,32 +871,30 @@ + vmlal.s32 q8, d22, d21 + vmlal.s32 q8, d28, d20 + vmlal.s32 q5, d24, d20 +- add r2, sp, #576 + vst1.8 {d14-d15}, [r2, : 128] + vmull.s32 q7, d18, d6 + vmlal.s32 q7, d26, d0 +- add r2, sp, #656 ++ add r2, sp, #624 + vld1.8 {d30-d31}, [r2, : 128] + vmlal.s32 q2, d30, d21 + vmlal.s32 q7, d19, d21 + vmlal.s32 q7, d27, d20 +- add r2, sp, #624 ++ add r2, sp, #592 + vld1.8 {d26-d27}, [r2, : 128] + vmlal.s32 q4, d25, d27 + vmlal.s32 q8, d29, d27 + vmlal.s32 q8, d25, d26 + vmlal.s32 q7, d28, d27 + vmlal.s32 q7, d29, d26 +- add r2, sp, #608 ++ add r2, sp, #576 + vld1.8 {d28-d29}, [r2, : 128] + vmlal.s32 q4, d24, d29 + vmlal.s32 q8, d23, d29 + vmlal.s32 q8, d24, d28 + vmlal.s32 q7, d22, d29 + vmlal.s32 q7, d23, d28 +- add r2, sp, #608 + vst1.8 {d8-d9}, [r2, : 128] +- add r2, sp, #560 ++ add r2, sp, #528 + vld1.8 {d8-d9}, [r2, : 128] + vmlal.s32 q7, d24, d9 + vmlal.s32 q7, d25, d31 +@@ -942,36 +915,36 @@ + vmlal.s32 q0, d23, d26 + vmlal.s32 q0, d24, d31 + vmlal.s32 q0, d19, d20 +- add r2, sp, #640 ++ add r2, sp, #608 + vld1.8 {d18-d19}, [r2, : 128] + vmlal.s32 q2, d18, d7 +- vmlal.s32 q2, d19, d6 + vmlal.s32 q5, d18, d6 +- vmlal.s32 q5, d19, d21 + vmlal.s32 q1, d18, d21 +- vmlal.s32 q1, d19, d29 + vmlal.s32 q0, d18, d28 +- vmlal.s32 q0, d19, d9 + vmlal.s32 q6, d18, d29 ++ vmlal.s32 q2, d19, d6 ++ vmlal.s32 q5, d19, d21 ++ vmlal.s32 q1, d19, d29 ++ vmlal.s32 q0, d19, d9 + vmlal.s32 q6, d19, d28 +- add r2, sp, #592 ++ add r2, sp, #560 + vld1.8 {d18-d19}, [r2, : 128] +- add r2, sp, #512 ++ add r2, sp, #480 + vld1.8 {d22-d23}, [r2, : 128] + vmlal.s32 q5, d19, d7 + vmlal.s32 q0, d18, d21 + vmlal.s32 q0, d19, d29 + vmlal.s32 q6, d18, d6 +- add r2, sp, #528 ++ add r2, sp, #496 + vld1.8 {d6-d7}, [r2, : 128] + vmlal.s32 q6, d19, d21 +- add r2, sp, #576 ++ add r2, sp, #544 + vld1.8 {d18-d19}, [r2, : 128] + vmlal.s32 q0, d30, d8 +- add r2, sp, #672 ++ add r2, sp, #640 + vld1.8 {d20-d21}, [r2, : 128] + vmlal.s32 q5, d30, d29 +- add r2, sp, #608 ++ add r2, sp, #576 + vld1.8 {d24-d25}, [r2, : 128] + vmlal.s32 q1, d30, d28 + vadd.i64 q13, q0, q11 +@@ -1069,7 +1042,7 @@ + sub r4, r4, #24 + vst1.8 d0, [r2, : 64] + vst1.8 d1, [r4, : 64] +- add r2, sp, #544 ++ add r2, sp, #512 + add r4, r3, #144 + add r5, r3, #192 + vld1.8 {d0-d1}, [r2, : 128] +@@ -1139,14 +1112,13 @@ + vmlal.s32 q0, d12, d8 + vmlal.s32 q0, d13, d17 + vmlal.s32 q0, d6, d6 +- add r2, sp, #512 +- vld1.8 {d18-d19}, [r2, : 128] ++ add r2, sp, #480 ++ vld1.8 {d18-d19}, [r2, : 128]! + vmull.s32 q3, d16, d7 + vmlal.s32 q3, d10, d15 + vmlal.s32 q3, d11, d14 + vmlal.s32 q3, d12, d9 + vmlal.s32 q3, d13, d8 +- add r2, sp, #528 + vld1.8 {d8-d9}, [r2, : 128] + vadd.i64 q5, q12, q9 + vadd.i64 q6, q15, q9 +@@ -1295,22 +1267,19 @@ + vadd.i32 q5, q5, q0 + vtrn.32 q11, q14 + vadd.i32 q6, q6, q3 +- add r2, sp, #560 ++ add r2, sp, #528 + vadd.i32 q10, q10, q2 + vtrn.32 d24, d25 +- vst1.8 {d12-d13}, [r2, : 128] ++ vst1.8 {d12-d13}, [r2, : 128]! + vshl.i32 q6, q13, #1 +- add r2, sp, #576 +- vst1.8 {d20-d21}, [r2, : 128] ++ vst1.8 {d20-d21}, [r2, : 128]! + vshl.i32 q10, q14, #1 +- add r2, sp, #592 +- vst1.8 {d12-d13}, [r2, : 128] ++ vst1.8 {d12-d13}, [r2, : 128]! + vshl.i32 q15, q12, #1 + vadd.i32 q8, q8, q4 + vext.32 d10, d31, d30, #0 + vadd.i32 q7, q7, q1 +- add r2, sp, #608 +- vst1.8 {d16-d17}, [r2, : 128] ++ vst1.8 {d16-d17}, [r2, : 128]! + vmull.s32 q8, d18, d5 + vmlal.s32 q8, d26, d4 + vmlal.s32 q8, d19, d9 +@@ -1321,8 +1290,7 @@ + vmlal.s32 q8, d29, d1 + vmlal.s32 q8, d24, d6 + vmlal.s32 q8, d25, d0 +- add r2, sp, #624 +- vst1.8 {d14-d15}, [r2, : 128] ++ vst1.8 {d14-d15}, [r2, : 128]! + vmull.s32 q2, d18, d4 + vmlal.s32 q2, d12, d9 + vmlal.s32 q2, d13, d8 +@@ -1330,8 +1298,7 @@ + vmlal.s32 q2, d22, d2 + vmlal.s32 q2, d23, d1 + vmlal.s32 q2, d24, d0 +- add r2, sp, #640 +- vst1.8 {d20-d21}, [r2, : 128] ++ vst1.8 {d20-d21}, [r2, : 128]! + vmull.s32 q7, d18, d9 + vmlal.s32 q7, d26, d3 + vmlal.s32 q7, d19, d8 +@@ -1340,15 +1307,13 @@ + vmlal.s32 q7, d28, d1 + vmlal.s32 q7, d23, d6 + vmlal.s32 q7, d29, d0 +- add r2, sp, #656 +- vst1.8 {d10-d11}, [r2, : 128] ++ vst1.8 {d10-d11}, [r2, : 128]! + vmull.s32 q5, d18, d3 + vmlal.s32 q5, d19, d2 + vmlal.s32 q5, d22, d1 + vmlal.s32 q5, d23, d0 + vmlal.s32 q5, d12, d8 +- add r2, sp, #672 +- vst1.8 {d16-d17}, [r2, : 128] ++ vst1.8 {d16-d17}, [r2, : 128]! + vmull.s32 q4, d18, d8 + vmlal.s32 q4, d26, d2 + vmlal.s32 q4, d19, d7 +@@ -1359,7 +1324,7 @@ + vmlal.s32 q8, d26, d1 + vmlal.s32 q8, d19, d6 + vmlal.s32 q8, d27, d0 +- add r2, sp, #576 ++ add r2, sp, #544 + vld1.8 {d20-d21}, [r2, : 128] + vmlal.s32 q7, d24, d21 + vmlal.s32 q7, d25, d20 +@@ -1368,32 +1333,30 @@ + vmlal.s32 q8, d22, d21 + vmlal.s32 q8, d28, d20 + vmlal.s32 q5, d24, d20 +- add r2, sp, #576 + vst1.8 {d14-d15}, [r2, : 128] + vmull.s32 q7, d18, d6 + vmlal.s32 q7, d26, d0 +- add r2, sp, #656 ++ add r2, sp, #624 + vld1.8 {d30-d31}, [r2, : 128] + vmlal.s32 q2, d30, d21 + vmlal.s32 q7, d19, d21 + vmlal.s32 q7, d27, d20 +- add r2, sp, #624 ++ add r2, sp, #592 + vld1.8 {d26-d27}, [r2, : 128] + vmlal.s32 q4, d25, d27 + vmlal.s32 q8, d29, d27 + vmlal.s32 q8, d25, d26 + vmlal.s32 q7, d28, d27 + vmlal.s32 q7, d29, d26 +- add r2, sp, #608 ++ add r2, sp, #576 + vld1.8 {d28-d29}, [r2, : 128] + vmlal.s32 q4, d24, d29 + vmlal.s32 q8, d23, d29 + vmlal.s32 q8, d24, d28 + vmlal.s32 q7, d22, d29 + vmlal.s32 q7, d23, d28 +- add r2, sp, #608 + vst1.8 {d8-d9}, [r2, : 128] +- add r2, sp, #560 ++ add r2, sp, #528 + vld1.8 {d8-d9}, [r2, : 128] + vmlal.s32 q7, d24, d9 + vmlal.s32 q7, d25, d31 +@@ -1414,36 +1377,36 @@ + vmlal.s32 q0, d23, d26 + vmlal.s32 q0, d24, d31 + vmlal.s32 q0, d19, d20 +- add r2, sp, #640 ++ add r2, sp, #608 + vld1.8 {d18-d19}, [r2, : 128] + vmlal.s32 q2, d18, d7 +- vmlal.s32 q2, d19, d6 + vmlal.s32 q5, d18, d6 +- vmlal.s32 q5, d19, d21 + vmlal.s32 q1, d18, d21 +- vmlal.s32 q1, d19, d29 + vmlal.s32 q0, d18, d28 +- vmlal.s32 q0, d19, d9 + vmlal.s32 q6, d18, d29 ++ vmlal.s32 q2, d19, d6 ++ vmlal.s32 q5, d19, d21 ++ vmlal.s32 q1, d19, d29 ++ vmlal.s32 q0, d19, d9 + vmlal.s32 q6, d19, d28 +- add r2, sp, #592 ++ add r2, sp, #560 + vld1.8 {d18-d19}, [r2, : 128] +- add r2, sp, #512 ++ add r2, sp, #480 + vld1.8 {d22-d23}, [r2, : 128] + vmlal.s32 q5, d19, d7 + vmlal.s32 q0, d18, d21 + vmlal.s32 q0, d19, d29 + vmlal.s32 q6, d18, d6 +- add r2, sp, #528 ++ add r2, sp, #496 + vld1.8 {d6-d7}, [r2, : 128] + vmlal.s32 q6, d19, d21 +- add r2, sp, #576 ++ add r2, sp, #544 + vld1.8 {d18-d19}, [r2, : 128] + vmlal.s32 q0, d30, d8 +- add r2, sp, #672 ++ add r2, sp, #640 + vld1.8 {d20-d21}, [r2, : 128] + vmlal.s32 q5, d30, d29 +- add r2, sp, #608 ++ add r2, sp, #576 + vld1.8 {d24-d25}, [r2, : 128] + vmlal.s32 q1, d30, d28 + vadd.i64 q13, q0, q11 +@@ -1541,10 +1504,10 @@ + sub r4, r4, #24 + vst1.8 d0, [r2, : 64] + vst1.8 d1, [r4, : 64] +- ldr r2, [sp, #488] +- ldr r4, [sp, #492] ++ ldr r2, [sp, #456] ++ ldr r4, [sp, #460] + subs r5, r2, #1 +- bge ._mainloop ++ bge .Lmainloop + add r1, r3, #144 + add r2, r3, #336 + vld1.8 {d0-d1}, [r1, : 128]! +@@ -1553,41 +1516,41 @@ + vst1.8 {d0-d1}, [r2, : 128]! + vst1.8 {d2-d3}, [r2, : 128]! + vst1.8 d4, [r2, : 64] +- ldr r1, =0 +-._invertloop: ++ movw r1, #0 ++.Linvertloop: + add r2, r3, #144 +- ldr r4, =0 +- ldr r5, =2 ++ movw r4, #0 ++ movw r5, #2 + cmp r1, #1 +- ldreq r5, =1 ++ moveq r5, #1 + addeq r2, r3, #336 + addeq r4, r3, #48 + cmp r1, #2 +- ldreq r5, =1 ++ moveq r5, #1 + addeq r2, r3, #48 + cmp r1, #3 +- ldreq r5, =5 ++ moveq r5, #5 + addeq r4, r3, #336 + cmp r1, #4 +- ldreq r5, =10 ++ moveq r5, #10 + cmp r1, #5 +- ldreq r5, =20 ++ moveq r5, #20 + cmp r1, #6 +- ldreq r5, =10 ++ moveq r5, #10 + addeq r2, r3, #336 + addeq r4, r3, #336 + cmp r1, #7 +- ldreq r5, =50 ++ moveq r5, #50 + cmp r1, #8 +- ldreq r5, =100 ++ moveq r5, #100 + cmp r1, #9 +- ldreq r5, =50 ++ moveq r5, #50 + addeq r2, r3, #336 + cmp r1, #10 +- ldreq r5, =5 ++ moveq r5, #5 + addeq r2, r3, #48 + cmp r1, #11 +- ldreq r5, =0 ++ moveq r5, #0 + addeq r2, r3, #96 + add r6, r3, #144 + add r7, r3, #288 +@@ -1598,8 +1561,8 @@ + vst1.8 {d2-d3}, [r7, : 128]! + vst1.8 d4, [r7, : 64] + cmp r5, #0 +- beq ._skipsquaringloop +-._squaringloop: ++ beq .Lskipsquaringloop ++.Lsquaringloop: + add r6, r3, #288 + add r7, r3, #288 + add r8, r3, #288 +@@ -1611,7 +1574,7 @@ + vld1.8 {d6-d7}, [r7, : 128]! + vld1.8 {d9}, [r7, : 64] + vld1.8 {d10-d11}, [r6, : 128]! +- add r7, sp, #416 ++ add r7, sp, #384 + vld1.8 {d12-d13}, [r6, : 128]! + vmul.i32 q7, q2, q0 + vld1.8 {d8}, [r6, : 64] +@@ -1726,7 +1689,7 @@ + vext.32 d10, d6, d6, #0 + vmov.i32 q1, #0xffffffff + vshl.i64 q4, q1, #25 +- add r7, sp, #512 ++ add r7, sp, #480 + vld1.8 {d14-d15}, [r7, : 128] + vadd.i64 q9, q2, q7 + vshl.i64 q1, q1, #26 +@@ -1735,7 +1698,7 @@ + vadd.i64 q5, q5, q10 + vand q9, q9, q1 + vld1.8 {d16}, [r6, : 64]! +- add r6, sp, #528 ++ add r6, sp, #496 + vld1.8 {d20-d21}, [r6, : 128] + vadd.i64 q11, q5, q10 + vsub.i64 q2, q2, q9 +@@ -1789,8 +1752,8 @@ + sub r6, r6, #32 + vst1.8 d4, [r6, : 64] + subs r5, r5, #1 +- bhi ._squaringloop +-._skipsquaringloop: ++ bhi .Lsquaringloop ++.Lskipsquaringloop: + mov r2, r2 + add r5, r3, #288 + add r6, r3, #144 +@@ -1802,7 +1765,7 @@ + vld1.8 {d6-d7}, [r5, : 128]! + vld1.8 {d9}, [r5, : 64] + vld1.8 {d10-d11}, [r2, : 128]! +- add r5, sp, #416 ++ add r5, sp, #384 + vld1.8 {d12-d13}, [r2, : 128]! + vmul.i32 q7, q2, q0 + vld1.8 {d8}, [r2, : 64] +@@ -1917,7 +1880,7 @@ + vext.32 d10, d6, d6, #0 + vmov.i32 q1, #0xffffffff + vshl.i64 q4, q1, #25 +- add r5, sp, #512 ++ add r5, sp, #480 + vld1.8 {d14-d15}, [r5, : 128] + vadd.i64 q9, q2, q7 + vshl.i64 q1, q1, #26 +@@ -1926,7 +1889,7 @@ + vadd.i64 q5, q5, q10 + vand q9, q9, q1 + vld1.8 {d16}, [r2, : 64]! +- add r2, sp, #528 ++ add r2, sp, #496 + vld1.8 {d20-d21}, [r2, : 128] + vadd.i64 q11, q5, q10 + vsub.i64 q2, q2, q9 +@@ -1980,7 +1943,7 @@ + sub r2, r2, #32 + vst1.8 d4, [r2, : 64] + cmp r4, #0 +- beq ._skippostcopy ++ beq .Lskippostcopy + add r2, r3, #144 + mov r4, r4 + vld1.8 {d0-d1}, [r2, : 128]! +@@ -1989,9 +1952,9 @@ + vst1.8 {d0-d1}, [r4, : 128]! + vst1.8 {d2-d3}, [r4, : 128]! + vst1.8 d4, [r4, : 64] +-._skippostcopy: ++.Lskippostcopy: + cmp r1, #1 +- bne ._skipfinalcopy ++ bne .Lskipfinalcopy + add r2, r3, #288 + add r4, r3, #144 + vld1.8 {d0-d1}, [r2, : 128]! +@@ -2000,10 +1963,10 @@ + vst1.8 {d0-d1}, [r4, : 128]! + vst1.8 {d2-d3}, [r4, : 128]! + vst1.8 d4, [r4, : 64] +-._skipfinalcopy: ++.Lskipfinalcopy: + add r1, r1, #1 + cmp r1, #12 +- blo ._invertloop ++ blo .Linvertloop + add r1, r3, #144 + ldr r2, [r1], #4 + ldr r3, [r1], #4 +@@ -2085,21 +2048,15 @@ + add r8, r8, r10, LSL #12 + mov r9, r10, LSR #20 + add r1, r9, r1, LSL #6 +- str r2, [r0], #4 +- str r3, [r0], #4 +- str r4, [r0], #4 +- str r5, [r0], #4 +- str r6, [r0], #4 +- str r7, [r0], #4 +- str r8, [r0], #4 +- str r1, [r0] +- ldrd r4, [sp, #0] +- ldrd r6, [sp, #8] +- ldrd r8, [sp, #16] +- ldrd r10, [sp, #24] +- ldr r12, [sp, #480] +- ldr r14, [sp, #484] +- ldr r0, =0 +- mov sp, r12 +- vpop {q4, q5, q6, q7} +- bx lr ++ str r2, [r0] ++ str r3, [r0, #4] ++ str r4, [r0, #8] ++ str r5, [r0, #12] ++ str r6, [r0, #16] ++ str r7, [r0, #20] ++ str r8, [r0, #24] ++ str r1, [r0, #28] ++ movw r0, #0 ++ mov sp, ip ++ pop {r4-r11, pc} ++ENDPROC(curve25519_neon) +--- /dev/null ++++ b/arch/arm/crypto/curve25519-glue.c +@@ -0,0 +1,127 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * Based on public domain code from Daniel J. Bernstein and Peter Schwabe. This ++ * began from SUPERCOP's curve25519/neon2/scalarmult.s, but has subsequently been ++ * manually reworked for use in kernel space. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE], ++ const u8 basepoint[CURVE25519_KEY_SIZE]); ++ ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); ++ ++void curve25519_arch(u8 out[CURVE25519_KEY_SIZE], ++ const u8 scalar[CURVE25519_KEY_SIZE], ++ const u8 point[CURVE25519_KEY_SIZE]) ++{ ++ if (static_branch_likely(&have_neon) && crypto_simd_usable()) { ++ kernel_neon_begin(); ++ curve25519_neon(out, scalar, point); ++ kernel_neon_end(); ++ } else { ++ curve25519_generic(out, scalar, point); ++ } ++} ++EXPORT_SYMBOL(curve25519_arch); ++ ++static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf, ++ unsigned int len) ++{ ++ u8 *secret = kpp_tfm_ctx(tfm); ++ ++ if (!len) ++ curve25519_generate_secret(secret); ++ else if (len == CURVE25519_KEY_SIZE && ++ crypto_memneq(buf, curve25519_null_point, CURVE25519_KEY_SIZE)) ++ memcpy(secret, buf, CURVE25519_KEY_SIZE); ++ else ++ return -EINVAL; ++ return 0; ++} ++ ++static int curve25519_compute_value(struct kpp_request *req) ++{ ++ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); ++ const u8 *secret = kpp_tfm_ctx(tfm); ++ u8 public_key[CURVE25519_KEY_SIZE]; ++ u8 buf[CURVE25519_KEY_SIZE]; ++ int copied, nbytes; ++ u8 const *bp; ++ ++ if (req->src) { ++ copied = sg_copy_to_buffer(req->src, ++ sg_nents_for_len(req->src, ++ CURVE25519_KEY_SIZE), ++ public_key, CURVE25519_KEY_SIZE); ++ if (copied != CURVE25519_KEY_SIZE) ++ return -EINVAL; ++ bp = public_key; ++ } else { ++ bp = curve25519_base_point; ++ } ++ ++ curve25519_arch(buf, secret, bp); ++ ++ /* might want less than we've got */ ++ nbytes = min_t(size_t, CURVE25519_KEY_SIZE, req->dst_len); ++ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, ++ nbytes), ++ buf, nbytes); ++ if (copied != nbytes) ++ return -EINVAL; ++ return 0; ++} ++ ++static unsigned int curve25519_max_size(struct crypto_kpp *tfm) ++{ ++ return CURVE25519_KEY_SIZE; ++} ++ ++static struct kpp_alg curve25519_alg = { ++ .base.cra_name = "curve25519", ++ .base.cra_driver_name = "curve25519-neon", ++ .base.cra_priority = 200, ++ .base.cra_module = THIS_MODULE, ++ .base.cra_ctxsize = CURVE25519_KEY_SIZE, ++ ++ .set_secret = curve25519_set_secret, ++ .generate_public_key = curve25519_compute_value, ++ .compute_shared_secret = curve25519_compute_value, ++ .max_size = curve25519_max_size, ++}; ++ ++static int __init mod_init(void) ++{ ++ if (elf_hwcap & HWCAP_NEON) { ++ static_branch_enable(&have_neon); ++ return crypto_register_kpp(&curve25519_alg); ++ } ++ return 0; ++} ++ ++static void __exit mod_exit(void) ++{ ++ if (elf_hwcap & HWCAP_NEON) ++ crypto_unregister_kpp(&curve25519_alg); ++} ++ ++module_init(mod_init); ++module_exit(mod_exit); ++ ++MODULE_ALIAS_CRYPTO("curve25519"); ++MODULE_ALIAS_CRYPTO("curve25519-neon"); ++MODULE_LICENSE("GPL v2"); diff --git a/ipq806x/backport-5.4/080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch b/ipq806x/backport-5.4/080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch new file mode 100644 index 0000000..2d5601d --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0032-crypto-chacha20poly1305-import-construction-and-self.patch @@ -0,0 +1,7677 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:39 +0100 +Subject: [PATCH] crypto: chacha20poly1305 - import construction and selftest + from Zinc + +commit ed20078b7e3331e82828be357147af6a3282e4ce upstream. + +This incorporates the chacha20poly1305 from the Zinc library, retaining +the library interface, but replacing the implementation with calls into +the code that already existed in the kernel's crypto API. + +Note that this library API does not implement RFC7539 fully, given that +it is limited to 64-bit nonces. (The 96-bit nonce version that was part +of the selftest only has been removed, along with the 96-bit nonce test +vectors that only tested the selftest but not the actual library itself) + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + include/crypto/chacha20poly1305.h | 37 + + lib/crypto/Kconfig | 7 + + lib/crypto/Makefile | 4 + + lib/crypto/chacha20poly1305-selftest.c | 7348 ++++++++++++++++++++++++ + lib/crypto/chacha20poly1305.c | 219 + + 5 files changed, 7615 insertions(+) + create mode 100644 include/crypto/chacha20poly1305.h + create mode 100644 lib/crypto/chacha20poly1305-selftest.c + create mode 100644 lib/crypto/chacha20poly1305.c + +--- /dev/null ++++ b/include/crypto/chacha20poly1305.h +@@ -0,0 +1,37 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef __CHACHA20POLY1305_H ++#define __CHACHA20POLY1305_H ++ ++#include ++ ++enum chacha20poly1305_lengths { ++ XCHACHA20POLY1305_NONCE_SIZE = 24, ++ CHACHA20POLY1305_KEY_SIZE = 32, ++ CHACHA20POLY1305_AUTHTAG_SIZE = 16 ++}; ++ ++void chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]); ++ ++bool __must_check ++chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]); ++ ++void xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]); ++ ++bool __must_check xchacha20poly1305_decrypt( ++ u8 *dst, const u8 *src, const size_t src_len, const u8 *ad, ++ const size_t ad_len, const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]); ++ ++#endif /* __CHACHA20POLY1305_H */ +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -119,5 +119,12 @@ config CRYPTO_LIB_POLY1305 + by either the generic implementation or an arch-specific one, if one + is available and enabled. + ++config CRYPTO_LIB_CHACHA20POLY1305 ++ tristate "ChaCha20-Poly1305 AEAD support (8-byte nonce library version)" ++ depends on CRYPTO_ARCH_HAVE_LIB_CHACHA || !CRYPTO_ARCH_HAVE_LIB_CHACHA ++ depends on CRYPTO_ARCH_HAVE_LIB_POLY1305 || !CRYPTO_ARCH_HAVE_LIB_POLY1305 ++ select CRYPTO_LIB_CHACHA ++ select CRYPTO_LIB_POLY1305 ++ + config CRYPTO_LIB_SHA256 + tristate +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -16,6 +16,9 @@ libblake2s-generic-y += blake2s-gener + obj-$(CONFIG_CRYPTO_LIB_BLAKE2S) += libblake2s.o + libblake2s-y += blake2s.o + ++obj-$(CONFIG_CRYPTO_LIB_CHACHA20POLY1305) += libchacha20poly1305.o ++libchacha20poly1305-y += chacha20poly1305.o ++ + obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC) += libcurve25519.o + libcurve25519-y := curve25519-fiat32.o + libcurve25519-$(CONFIG_ARCH_SUPPORTS_INT128) := curve25519-hacl64.o +@@ -32,4 +35,5 @@ libsha256-y := sha256.o + + ifneq ($(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS),y) + libblake2s-y += blake2s-selftest.o ++libchacha20poly1305-y += chacha20poly1305-selftest.o + endif +--- /dev/null ++++ b/lib/crypto/chacha20poly1305-selftest.c +@@ -0,0 +1,7348 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct chacha20poly1305_testvec { ++ const u8 *input, *output, *assoc, *nonce, *key; ++ size_t ilen, alen, nlen; ++ bool failure; ++}; ++ ++/* The first of these are the ChaCha20-Poly1305 AEAD test vectors from RFC7539 ++ * 2.8.2. After they are generated by reference implementations. And the final ++ * marked ones are taken from wycheproof, but we only do these for the encrypt ++ * side, because mostly we're stressing the primitives rather than the actual ++ * chapoly construction. ++ */ ++ ++static const u8 enc_input001[] __initconst = { ++ 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, ++ 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, ++ 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66, ++ 0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69, ++ 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, ++ 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, ++ 0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d, ++ 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e, ++ 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, ++ 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, ++ 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, ++ 0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, ++ 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64, ++ 0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65, ++ 0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, ++ 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, ++ 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, ++ 0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, ++ 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, ++ 0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, ++ 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, ++ 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72, ++ 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, ++ 0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, ++ 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, ++ 0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, ++ 0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, ++ 0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20, ++ 0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, ++ 0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, ++ 0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80, ++ 0x9d ++}; ++static const u8 enc_output001[] __initconst = { ++ 0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4, ++ 0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd, ++ 0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89, ++ 0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2, ++ 0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee, ++ 0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0, ++ 0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00, ++ 0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf, ++ 0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce, ++ 0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81, ++ 0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd, ++ 0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55, ++ 0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61, ++ 0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38, ++ 0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0, ++ 0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4, ++ 0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46, ++ 0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9, ++ 0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e, ++ 0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e, ++ 0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15, ++ 0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a, ++ 0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea, ++ 0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a, ++ 0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99, ++ 0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e, ++ 0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10, ++ 0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10, ++ 0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94, ++ 0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30, ++ 0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf, ++ 0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29, ++ 0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70, ++ 0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, ++ 0x22, 0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f, ++ 0x38 ++}; ++static const u8 enc_assoc001[] __initconst = { ++ 0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x4e, 0x91 ++}; ++static const u8 enc_nonce001[] __initconst = { ++ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ++}; ++static const u8 enc_key001[] __initconst = { ++ 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, ++ 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, ++ 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, ++ 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 ++}; ++ ++static const u8 enc_input002[] __initconst = { }; ++static const u8 enc_output002[] __initconst = { ++ 0xea, 0xe0, 0x1e, 0x9e, 0x2c, 0x91, 0xaa, 0xe1, ++ 0xdb, 0x5d, 0x99, 0x3f, 0x8a, 0xf7, 0x69, 0x92 ++}; ++static const u8 enc_assoc002[] __initconst = { }; ++static const u8 enc_nonce002[] __initconst = { ++ 0xca, 0xbf, 0x33, 0x71, 0x32, 0x45, 0x77, 0x8e ++}; ++static const u8 enc_key002[] __initconst = { ++ 0x4c, 0xf5, 0x96, 0x83, 0x38, 0xe6, 0xae, 0x7f, ++ 0x2d, 0x29, 0x25, 0x76, 0xd5, 0x75, 0x27, 0x86, ++ 0x91, 0x9a, 0x27, 0x7a, 0xfb, 0x46, 0xc5, 0xef, ++ 0x94, 0x81, 0x79, 0x57, 0x14, 0x59, 0x40, 0x68 ++}; ++ ++static const u8 enc_input003[] __initconst = { }; ++static const u8 enc_output003[] __initconst = { ++ 0xdd, 0x6b, 0x3b, 0x82, 0xce, 0x5a, 0xbd, 0xd6, ++ 0xa9, 0x35, 0x83, 0xd8, 0x8c, 0x3d, 0x85, 0x77 ++}; ++static const u8 enc_assoc003[] __initconst = { ++ 0x33, 0x10, 0x41, 0x12, 0x1f, 0xf3, 0xd2, 0x6b ++}; ++static const u8 enc_nonce003[] __initconst = { ++ 0x3d, 0x86, 0xb5, 0x6b, 0xc8, 0xa3, 0x1f, 0x1d ++}; ++static const u8 enc_key003[] __initconst = { ++ 0x2d, 0xb0, 0x5d, 0x40, 0xc8, 0xed, 0x44, 0x88, ++ 0x34, 0xd1, 0x13, 0xaf, 0x57, 0xa1, 0xeb, 0x3a, ++ 0x2a, 0x80, 0x51, 0x36, 0xec, 0x5b, 0xbc, 0x08, ++ 0x93, 0x84, 0x21, 0xb5, 0x13, 0x88, 0x3c, 0x0d ++}; ++ ++static const u8 enc_input004[] __initconst = { ++ 0xa4 ++}; ++static const u8 enc_output004[] __initconst = { ++ 0xb7, 0x1b, 0xb0, 0x73, 0x59, 0xb0, 0x84, 0xb2, ++ 0x6d, 0x8e, 0xab, 0x94, 0x31, 0xa1, 0xae, 0xac, ++ 0x89 ++}; ++static const u8 enc_assoc004[] __initconst = { ++ 0x6a, 0xe2, 0xad, 0x3f, 0x88, 0x39, 0x5a, 0x40 ++}; ++static const u8 enc_nonce004[] __initconst = { ++ 0xd2, 0x32, 0x1f, 0x29, 0x28, 0xc6, 0xc4, 0xc4 ++}; ++static const u8 enc_key004[] __initconst = { ++ 0x4b, 0x28, 0x4b, 0xa3, 0x7b, 0xbe, 0xe9, 0xf8, ++ 0x31, 0x80, 0x82, 0xd7, 0xd8, 0xe8, 0xb5, 0xa1, ++ 0xe2, 0x18, 0x18, 0x8a, 0x9c, 0xfa, 0xa3, 0x3d, ++ 0x25, 0x71, 0x3e, 0x40, 0xbc, 0x54, 0x7a, 0x3e ++}; ++ ++static const u8 enc_input005[] __initconst = { ++ 0x2d ++}; ++static const u8 enc_output005[] __initconst = { ++ 0xbf, 0xe1, 0x5b, 0x0b, 0xdb, 0x6b, 0xf5, 0x5e, ++ 0x6c, 0x5d, 0x84, 0x44, 0x39, 0x81, 0xc1, 0x9c, ++ 0xac ++}; ++static const u8 enc_assoc005[] __initconst = { }; ++static const u8 enc_nonce005[] __initconst = { ++ 0x20, 0x1c, 0xaa, 0x5f, 0x9c, 0xbf, 0x92, 0x30 ++}; ++static const u8 enc_key005[] __initconst = { ++ 0x66, 0xca, 0x9c, 0x23, 0x2a, 0x4b, 0x4b, 0x31, ++ 0x0e, 0x92, 0x89, 0x8b, 0xf4, 0x93, 0xc7, 0x87, ++ 0x98, 0xa3, 0xd8, 0x39, 0xf8, 0xf4, 0xa7, 0x01, ++ 0xc0, 0x2e, 0x0a, 0xa6, 0x7e, 0x5a, 0x78, 0x87 ++}; ++ ++static const u8 enc_input006[] __initconst = { ++ 0x33, 0x2f, 0x94, 0xc1, 0xa4, 0xef, 0xcc, 0x2a, ++ 0x5b, 0xa6, 0xe5, 0x8f, 0x1d, 0x40, 0xf0, 0x92, ++ 0x3c, 0xd9, 0x24, 0x11, 0xa9, 0x71, 0xf9, 0x37, ++ 0x14, 0x99, 0xfa, 0xbe, 0xe6, 0x80, 0xde, 0x50, ++ 0xc9, 0x96, 0xd4, 0xb0, 0xec, 0x9e, 0x17, 0xec, ++ 0xd2, 0x5e, 0x72, 0x99, 0xfc, 0x0a, 0xe1, 0xcb, ++ 0x48, 0xd2, 0x85, 0xdd, 0x2f, 0x90, 0xe0, 0x66, ++ 0x3b, 0xe6, 0x20, 0x74, 0xbe, 0x23, 0x8f, 0xcb, ++ 0xb4, 0xe4, 0xda, 0x48, 0x40, 0xa6, 0xd1, 0x1b, ++ 0xc7, 0x42, 0xce, 0x2f, 0x0c, 0xa6, 0x85, 0x6e, ++ 0x87, 0x37, 0x03, 0xb1, 0x7c, 0x25, 0x96, 0xa3, ++ 0x05, 0xd8, 0xb0, 0xf4, 0xed, 0xea, 0xc2, 0xf0, ++ 0x31, 0x98, 0x6c, 0xd1, 0x14, 0x25, 0xc0, 0xcb, ++ 0x01, 0x74, 0xd0, 0x82, 0xf4, 0x36, 0xf5, 0x41, ++ 0xd5, 0xdc, 0xca, 0xc5, 0xbb, 0x98, 0xfe, 0xfc, ++ 0x69, 0x21, 0x70, 0xd8, 0xa4, 0x4b, 0xc8, 0xde, ++ 0x8f ++}; ++static const u8 enc_output006[] __initconst = { ++ 0x8b, 0x06, 0xd3, 0x31, 0xb0, 0x93, 0x45, 0xb1, ++ 0x75, 0x6e, 0x26, 0xf9, 0x67, 0xbc, 0x90, 0x15, ++ 0x81, 0x2c, 0xb5, 0xf0, 0xc6, 0x2b, 0xc7, 0x8c, ++ 0x56, 0xd1, 0xbf, 0x69, 0x6c, 0x07, 0xa0, 0xda, ++ 0x65, 0x27, 0xc9, 0x90, 0x3d, 0xef, 0x4b, 0x11, ++ 0x0f, 0x19, 0x07, 0xfd, 0x29, 0x92, 0xd9, 0xc8, ++ 0xf7, 0x99, 0x2e, 0x4a, 0xd0, 0xb8, 0x2c, 0xdc, ++ 0x93, 0xf5, 0x9e, 0x33, 0x78, 0xd1, 0x37, 0xc3, ++ 0x66, 0xd7, 0x5e, 0xbc, 0x44, 0xbf, 0x53, 0xa5, ++ 0xbc, 0xc4, 0xcb, 0x7b, 0x3a, 0x8e, 0x7f, 0x02, ++ 0xbd, 0xbb, 0xe7, 0xca, 0xa6, 0x6c, 0x6b, 0x93, ++ 0x21, 0x93, 0x10, 0x61, 0xe7, 0x69, 0xd0, 0x78, ++ 0xf3, 0x07, 0x5a, 0x1a, 0x8f, 0x73, 0xaa, 0xb1, ++ 0x4e, 0xd3, 0xda, 0x4f, 0xf3, 0x32, 0xe1, 0x66, ++ 0x3e, 0x6c, 0xc6, 0x13, 0xba, 0x06, 0x5b, 0xfc, ++ 0x6a, 0xe5, 0x6f, 0x60, 0xfb, 0x07, 0x40, 0xb0, ++ 0x8c, 0x9d, 0x84, 0x43, 0x6b, 0xc1, 0xf7, 0x8d, ++ 0x8d, 0x31, 0xf7, 0x7a, 0x39, 0x4d, 0x8f, 0x9a, ++ 0xeb ++}; ++static const u8 enc_assoc006[] __initconst = { ++ 0x70, 0xd3, 0x33, 0xf3, 0x8b, 0x18, 0x0b ++}; ++static const u8 enc_nonce006[] __initconst = { ++ 0xdf, 0x51, 0x84, 0x82, 0x42, 0x0c, 0x75, 0x9c ++}; ++static const u8 enc_key006[] __initconst = { ++ 0x68, 0x7b, 0x8d, 0x8e, 0xe3, 0xc4, 0xdd, 0xae, ++ 0xdf, 0x72, 0x7f, 0x53, 0x72, 0x25, 0x1e, 0x78, ++ 0x91, 0xcb, 0x69, 0x76, 0x1f, 0x49, 0x93, 0xf9, ++ 0x6f, 0x21, 0xcc, 0x39, 0x9c, 0xad, 0xb1, 0x01 ++}; ++ ++static const u8 enc_input007[] __initconst = { ++ 0x9b, 0x18, 0xdb, 0xdd, 0x9a, 0x0f, 0x3e, 0xa5, ++ 0x15, 0x17, 0xde, 0xdf, 0x08, 0x9d, 0x65, 0x0a, ++ 0x67, 0x30, 0x12, 0xe2, 0x34, 0x77, 0x4b, 0xc1, ++ 0xd9, 0xc6, 0x1f, 0xab, 0xc6, 0x18, 0x50, 0x17, ++ 0xa7, 0x9d, 0x3c, 0xa6, 0xc5, 0x35, 0x8c, 0x1c, ++ 0xc0, 0xa1, 0x7c, 0x9f, 0x03, 0x89, 0xca, 0xe1, ++ 0xe6, 0xe9, 0xd4, 0xd3, 0x88, 0xdb, 0xb4, 0x51, ++ 0x9d, 0xec, 0xb4, 0xfc, 0x52, 0xee, 0x6d, 0xf1, ++ 0x75, 0x42, 0xc6, 0xfd, 0xbd, 0x7a, 0x8e, 0x86, ++ 0xfc, 0x44, 0xb3, 0x4f, 0xf3, 0xea, 0x67, 0x5a, ++ 0x41, 0x13, 0xba, 0xb0, 0xdc, 0xe1, 0xd3, 0x2a, ++ 0x7c, 0x22, 0xb3, 0xca, 0xac, 0x6a, 0x37, 0x98, ++ 0x3e, 0x1d, 0x40, 0x97, 0xf7, 0x9b, 0x1d, 0x36, ++ 0x6b, 0xb3, 0x28, 0xbd, 0x60, 0x82, 0x47, 0x34, ++ 0xaa, 0x2f, 0x7d, 0xe9, 0xa8, 0x70, 0x81, 0x57, ++ 0xd4, 0xb9, 0x77, 0x0a, 0x9d, 0x29, 0xa7, 0x84, ++ 0x52, 0x4f, 0xc2, 0x4a, 0x40, 0x3b, 0x3c, 0xd4, ++ 0xc9, 0x2a, 0xdb, 0x4a, 0x53, 0xc4, 0xbe, 0x80, ++ 0xe9, 0x51, 0x7f, 0x8f, 0xc7, 0xa2, 0xce, 0x82, ++ 0x5c, 0x91, 0x1e, 0x74, 0xd9, 0xd0, 0xbd, 0xd5, ++ 0xf3, 0xfd, 0xda, 0x4d, 0x25, 0xb4, 0xbb, 0x2d, ++ 0xac, 0x2f, 0x3d, 0x71, 0x85, 0x7b, 0xcf, 0x3c, ++ 0x7b, 0x3e, 0x0e, 0x22, 0x78, 0x0c, 0x29, 0xbf, ++ 0xe4, 0xf4, 0x57, 0xb3, 0xcb, 0x49, 0xa0, 0xfc, ++ 0x1e, 0x05, 0x4e, 0x16, 0xbc, 0xd5, 0xa8, 0xa3, ++ 0xee, 0x05, 0x35, 0xc6, 0x7c, 0xab, 0x60, 0x14, ++ 0x55, 0x1a, 0x8e, 0xc5, 0x88, 0x5d, 0xd5, 0x81, ++ 0xc2, 0x81, 0xa5, 0xc4, 0x60, 0xdb, 0xaf, 0x77, ++ 0x91, 0xe1, 0xce, 0xa2, 0x7e, 0x7f, 0x42, 0xe3, ++ 0xb0, 0x13, 0x1c, 0x1f, 0x25, 0x60, 0x21, 0xe2, ++ 0x40, 0x5f, 0x99, 0xb7, 0x73, 0xec, 0x9b, 0x2b, ++ 0xf0, 0x65, 0x11, 0xc8, 0xd0, 0x0a, 0x9f, 0xd3 ++}; ++static const u8 enc_output007[] __initconst = { ++ 0x85, 0x04, 0xc2, 0xed, 0x8d, 0xfd, 0x97, 0x5c, ++ 0xd2, 0xb7, 0xe2, 0xc1, 0x6b, 0xa3, 0xba, 0xf8, ++ 0xc9, 0x50, 0xc3, 0xc6, 0xa5, 0xe3, 0xa4, 0x7c, ++ 0xc3, 0x23, 0x49, 0x5e, 0xa9, 0xb9, 0x32, 0xeb, ++ 0x8a, 0x7c, 0xca, 0xe5, 0xec, 0xfb, 0x7c, 0xc0, ++ 0xcb, 0x7d, 0xdc, 0x2c, 0x9d, 0x92, 0x55, 0x21, ++ 0x0a, 0xc8, 0x43, 0x63, 0x59, 0x0a, 0x31, 0x70, ++ 0x82, 0x67, 0x41, 0x03, 0xf8, 0xdf, 0xf2, 0xac, ++ 0xa7, 0x02, 0xd4, 0xd5, 0x8a, 0x2d, 0xc8, 0x99, ++ 0x19, 0x66, 0xd0, 0xf6, 0x88, 0x2c, 0x77, 0xd9, ++ 0xd4, 0x0d, 0x6c, 0xbd, 0x98, 0xde, 0xe7, 0x7f, ++ 0xad, 0x7e, 0x8a, 0xfb, 0xe9, 0x4b, 0xe5, 0xf7, ++ 0xe5, 0x50, 0xa0, 0x90, 0x3f, 0xd6, 0x22, 0x53, ++ 0xe3, 0xfe, 0x1b, 0xcc, 0x79, 0x3b, 0xec, 0x12, ++ 0x47, 0x52, 0xa7, 0xd6, 0x04, 0xe3, 0x52, 0xe6, ++ 0x93, 0x90, 0x91, 0x32, 0x73, 0x79, 0xb8, 0xd0, ++ 0x31, 0xde, 0x1f, 0x9f, 0x2f, 0x05, 0x38, 0x54, ++ 0x2f, 0x35, 0x04, 0x39, 0xe0, 0xa7, 0xba, 0xc6, ++ 0x52, 0xf6, 0x37, 0x65, 0x4c, 0x07, 0xa9, 0x7e, ++ 0xb3, 0x21, 0x6f, 0x74, 0x8c, 0xc9, 0xde, 0xdb, ++ 0x65, 0x1b, 0x9b, 0xaa, 0x60, 0xb1, 0x03, 0x30, ++ 0x6b, 0xb2, 0x03, 0xc4, 0x1c, 0x04, 0xf8, 0x0f, ++ 0x64, 0xaf, 0x46, 0xe4, 0x65, 0x99, 0x49, 0xe2, ++ 0xea, 0xce, 0x78, 0x00, 0xd8, 0x8b, 0xd5, 0x2e, ++ 0xcf, 0xfc, 0x40, 0x49, 0xe8, 0x58, 0xdc, 0x34, ++ 0x9c, 0x8c, 0x61, 0xbf, 0x0a, 0x8e, 0xec, 0x39, ++ 0xa9, 0x30, 0x05, 0x5a, 0xd2, 0x56, 0x01, 0xc7, ++ 0xda, 0x8f, 0x4e, 0xbb, 0x43, 0xa3, 0x3a, 0xf9, ++ 0x15, 0x2a, 0xd0, 0xa0, 0x7a, 0x87, 0x34, 0x82, ++ 0xfe, 0x8a, 0xd1, 0x2d, 0x5e, 0xc7, 0xbf, 0x04, ++ 0x53, 0x5f, 0x3b, 0x36, 0xd4, 0x25, 0x5c, 0x34, ++ 0x7a, 0x8d, 0xd5, 0x05, 0xce, 0x72, 0xca, 0xef, ++ 0x7a, 0x4b, 0xbc, 0xb0, 0x10, 0x5c, 0x96, 0x42, ++ 0x3a, 0x00, 0x98, 0xcd, 0x15, 0xe8, 0xb7, 0x53 ++}; ++static const u8 enc_assoc007[] __initconst = { }; ++static const u8 enc_nonce007[] __initconst = { ++ 0xde, 0x7b, 0xef, 0xc3, 0x65, 0x1b, 0x68, 0xb0 ++}; ++static const u8 enc_key007[] __initconst = { ++ 0x8d, 0xb8, 0x91, 0x48, 0xf0, 0xe7, 0x0a, 0xbd, ++ 0xf9, 0x3f, 0xcd, 0xd9, 0xa0, 0x1e, 0x42, 0x4c, ++ 0xe7, 0xde, 0x25, 0x3d, 0xa3, 0xd7, 0x05, 0x80, ++ 0x8d, 0xf2, 0x82, 0xac, 0x44, 0x16, 0x51, 0x01 ++}; ++ ++static const u8 enc_input008[] __initconst = { ++ 0xc3, 0x09, 0x94, 0x62, 0xe6, 0x46, 0x2e, 0x10, ++ 0xbe, 0x00, 0xe4, 0xfc, 0xf3, 0x40, 0xa3, 0xe2, ++ 0x0f, 0xc2, 0x8b, 0x28, 0xdc, 0xba, 0xb4, 0x3c, ++ 0xe4, 0x21, 0x58, 0x61, 0xcd, 0x8b, 0xcd, 0xfb, ++ 0xac, 0x94, 0xa1, 0x45, 0xf5, 0x1c, 0xe1, 0x12, ++ 0xe0, 0x3b, 0x67, 0x21, 0x54, 0x5e, 0x8c, 0xaa, ++ 0xcf, 0xdb, 0xb4, 0x51, 0xd4, 0x13, 0xda, 0xe6, ++ 0x83, 0x89, 0xb6, 0x92, 0xe9, 0x21, 0x76, 0xa4, ++ 0x93, 0x7d, 0x0e, 0xfd, 0x96, 0x36, 0x03, 0x91, ++ 0x43, 0x5c, 0x92, 0x49, 0x62, 0x61, 0x7b, 0xeb, ++ 0x43, 0x89, 0xb8, 0x12, 0x20, 0x43, 0xd4, 0x47, ++ 0x06, 0x84, 0xee, 0x47, 0xe9, 0x8a, 0x73, 0x15, ++ 0x0f, 0x72, 0xcf, 0xed, 0xce, 0x96, 0xb2, 0x7f, ++ 0x21, 0x45, 0x76, 0xeb, 0x26, 0x28, 0x83, 0x6a, ++ 0xad, 0xaa, 0xa6, 0x81, 0xd8, 0x55, 0xb1, 0xa3, ++ 0x85, 0xb3, 0x0c, 0xdf, 0xf1, 0x69, 0x2d, 0x97, ++ 0x05, 0x2a, 0xbc, 0x7c, 0x7b, 0x25, 0xf8, 0x80, ++ 0x9d, 0x39, 0x25, 0xf3, 0x62, 0xf0, 0x66, 0x5e, ++ 0xf4, 0xa0, 0xcf, 0xd8, 0xfd, 0x4f, 0xb1, 0x1f, ++ 0x60, 0x3a, 0x08, 0x47, 0xaf, 0xe1, 0xf6, 0x10, ++ 0x77, 0x09, 0xa7, 0x27, 0x8f, 0x9a, 0x97, 0x5a, ++ 0x26, 0xfa, 0xfe, 0x41, 0x32, 0x83, 0x10, 0xe0, ++ 0x1d, 0xbf, 0x64, 0x0d, 0xf4, 0x1c, 0x32, 0x35, ++ 0xe5, 0x1b, 0x36, 0xef, 0xd4, 0x4a, 0x93, 0x4d, ++ 0x00, 0x7c, 0xec, 0x02, 0x07, 0x8b, 0x5d, 0x7d, ++ 0x1b, 0x0e, 0xd1, 0xa6, 0xa5, 0x5d, 0x7d, 0x57, ++ 0x88, 0xa8, 0xcc, 0x81, 0xb4, 0x86, 0x4e, 0xb4, ++ 0x40, 0xe9, 0x1d, 0xc3, 0xb1, 0x24, 0x3e, 0x7f, ++ 0xcc, 0x8a, 0x24, 0x9b, 0xdf, 0x6d, 0xf0, 0x39, ++ 0x69, 0x3e, 0x4c, 0xc0, 0x96, 0xe4, 0x13, 0xda, ++ 0x90, 0xda, 0xf4, 0x95, 0x66, 0x8b, 0x17, 0x17, ++ 0xfe, 0x39, 0x43, 0x25, 0xaa, 0xda, 0xa0, 0x43, ++ 0x3c, 0xb1, 0x41, 0x02, 0xa3, 0xf0, 0xa7, 0x19, ++ 0x59, 0xbc, 0x1d, 0x7d, 0x6c, 0x6d, 0x91, 0x09, ++ 0x5c, 0xb7, 0x5b, 0x01, 0xd1, 0x6f, 0x17, 0x21, ++ 0x97, 0xbf, 0x89, 0x71, 0xa5, 0xb0, 0x6e, 0x07, ++ 0x45, 0xfd, 0x9d, 0xea, 0x07, 0xf6, 0x7a, 0x9f, ++ 0x10, 0x18, 0x22, 0x30, 0x73, 0xac, 0xd4, 0x6b, ++ 0x72, 0x44, 0xed, 0xd9, 0x19, 0x9b, 0x2d, 0x4a, ++ 0x41, 0xdd, 0xd1, 0x85, 0x5e, 0x37, 0x19, 0xed, ++ 0xd2, 0x15, 0x8f, 0x5e, 0x91, 0xdb, 0x33, 0xf2, ++ 0xe4, 0xdb, 0xff, 0x98, 0xfb, 0xa3, 0xb5, 0xca, ++ 0x21, 0x69, 0x08, 0xe7, 0x8a, 0xdf, 0x90, 0xff, ++ 0x3e, 0xe9, 0x20, 0x86, 0x3c, 0xe9, 0xfc, 0x0b, ++ 0xfe, 0x5c, 0x61, 0xaa, 0x13, 0x92, 0x7f, 0x7b, ++ 0xec, 0xe0, 0x6d, 0xa8, 0x23, 0x22, 0xf6, 0x6b, ++ 0x77, 0xc4, 0xfe, 0x40, 0x07, 0x3b, 0xb6, 0xf6, ++ 0x8e, 0x5f, 0xd4, 0xb9, 0xb7, 0x0f, 0x21, 0x04, ++ 0xef, 0x83, 0x63, 0x91, 0x69, 0x40, 0xa3, 0x48, ++ 0x5c, 0xd2, 0x60, 0xf9, 0x4f, 0x6c, 0x47, 0x8b, ++ 0x3b, 0xb1, 0x9f, 0x8e, 0xee, 0x16, 0x8a, 0x13, ++ 0xfc, 0x46, 0x17, 0xc3, 0xc3, 0x32, 0x56, 0xf8, ++ 0x3c, 0x85, 0x3a, 0xb6, 0x3e, 0xaa, 0x89, 0x4f, ++ 0xb3, 0xdf, 0x38, 0xfd, 0xf1, 0xe4, 0x3a, 0xc0, ++ 0xe6, 0x58, 0xb5, 0x8f, 0xc5, 0x29, 0xa2, 0x92, ++ 0x4a, 0xb6, 0xa0, 0x34, 0x7f, 0xab, 0xb5, 0x8a, ++ 0x90, 0xa1, 0xdb, 0x4d, 0xca, 0xb6, 0x2c, 0x41, ++ 0x3c, 0xf7, 0x2b, 0x21, 0xc3, 0xfd, 0xf4, 0x17, ++ 0x5c, 0xb5, 0x33, 0x17, 0x68, 0x2b, 0x08, 0x30, ++ 0xf3, 0xf7, 0x30, 0x3c, 0x96, 0xe6, 0x6a, 0x20, ++ 0x97, 0xe7, 0x4d, 0x10, 0x5f, 0x47, 0x5f, 0x49, ++ 0x96, 0x09, 0xf0, 0x27, 0x91, 0xc8, 0xf8, 0x5a, ++ 0x2e, 0x79, 0xb5, 0xe2, 0xb8, 0xe8, 0xb9, 0x7b, ++ 0xd5, 0x10, 0xcb, 0xff, 0x5d, 0x14, 0x73, 0xf3 ++}; ++static const u8 enc_output008[] __initconst = { ++ 0x14, 0xf6, 0x41, 0x37, 0xa6, 0xd4, 0x27, 0xcd, ++ 0xdb, 0x06, 0x3e, 0x9a, 0x4e, 0xab, 0xd5, 0xb1, ++ 0x1e, 0x6b, 0xd2, 0xbc, 0x11, 0xf4, 0x28, 0x93, ++ 0x63, 0x54, 0xef, 0xbb, 0x5e, 0x1d, 0x3a, 0x1d, ++ 0x37, 0x3c, 0x0a, 0x6c, 0x1e, 0xc2, 0xd1, 0x2c, ++ 0xb5, 0xa3, 0xb5, 0x7b, 0xb8, 0x8f, 0x25, 0xa6, ++ 0x1b, 0x61, 0x1c, 0xec, 0x28, 0x58, 0x26, 0xa4, ++ 0xa8, 0x33, 0x28, 0x25, 0x5c, 0x45, 0x05, 0xe5, ++ 0x6c, 0x99, 0xe5, 0x45, 0xc4, 0xa2, 0x03, 0x84, ++ 0x03, 0x73, 0x1e, 0x8c, 0x49, 0xac, 0x20, 0xdd, ++ 0x8d, 0xb3, 0xc4, 0xf5, 0xe7, 0x4f, 0xf1, 0xed, ++ 0xa1, 0x98, 0xde, 0xa4, 0x96, 0xdd, 0x2f, 0xab, ++ 0xab, 0x97, 0xcf, 0x3e, 0xd2, 0x9e, 0xb8, 0x13, ++ 0x07, 0x28, 0x29, 0x19, 0xaf, 0xfd, 0xf2, 0x49, ++ 0x43, 0xea, 0x49, 0x26, 0x91, 0xc1, 0x07, 0xd6, ++ 0xbb, 0x81, 0x75, 0x35, 0x0d, 0x24, 0x7f, 0xc8, ++ 0xda, 0xd4, 0xb7, 0xeb, 0xe8, 0x5c, 0x09, 0xa2, ++ 0x2f, 0xdc, 0x28, 0x7d, 0x3a, 0x03, 0xfa, 0x94, ++ 0xb5, 0x1d, 0x17, 0x99, 0x36, 0xc3, 0x1c, 0x18, ++ 0x34, 0xe3, 0x9f, 0xf5, 0x55, 0x7c, 0xb0, 0x60, ++ 0x9d, 0xff, 0xac, 0xd4, 0x61, 0xf2, 0xad, 0xf8, ++ 0xce, 0xc7, 0xbe, 0x5c, 0xd2, 0x95, 0xa8, 0x4b, ++ 0x77, 0x13, 0x19, 0x59, 0x26, 0xc9, 0xb7, 0x8f, ++ 0x6a, 0xcb, 0x2d, 0x37, 0x91, 0xea, 0x92, 0x9c, ++ 0x94, 0x5b, 0xda, 0x0b, 0xce, 0xfe, 0x30, 0x20, ++ 0xf8, 0x51, 0xad, 0xf2, 0xbe, 0xe7, 0xc7, 0xff, ++ 0xb3, 0x33, 0x91, 0x6a, 0xc9, 0x1a, 0x41, 0xc9, ++ 0x0f, 0xf3, 0x10, 0x0e, 0xfd, 0x53, 0xff, 0x6c, ++ 0x16, 0x52, 0xd9, 0xf3, 0xf7, 0x98, 0x2e, 0xc9, ++ 0x07, 0x31, 0x2c, 0x0c, 0x72, 0xd7, 0xc5, 0xc6, ++ 0x08, 0x2a, 0x7b, 0xda, 0xbd, 0x7e, 0x02, 0xea, ++ 0x1a, 0xbb, 0xf2, 0x04, 0x27, 0x61, 0x28, 0x8e, ++ 0xf5, 0x04, 0x03, 0x1f, 0x4c, 0x07, 0x55, 0x82, ++ 0xec, 0x1e, 0xd7, 0x8b, 0x2f, 0x65, 0x56, 0xd1, ++ 0xd9, 0x1e, 0x3c, 0xe9, 0x1f, 0x5e, 0x98, 0x70, ++ 0x38, 0x4a, 0x8c, 0x49, 0xc5, 0x43, 0xa0, 0xa1, ++ 0x8b, 0x74, 0x9d, 0x4c, 0x62, 0x0d, 0x10, 0x0c, ++ 0xf4, 0x6c, 0x8f, 0xe0, 0xaa, 0x9a, 0x8d, 0xb7, ++ 0xe0, 0xbe, 0x4c, 0x87, 0xf1, 0x98, 0x2f, 0xcc, ++ 0xed, 0xc0, 0x52, 0x29, 0xdc, 0x83, 0xf8, 0xfc, ++ 0x2c, 0x0e, 0xa8, 0x51, 0x4d, 0x80, 0x0d, 0xa3, ++ 0xfe, 0xd8, 0x37, 0xe7, 0x41, 0x24, 0xfc, 0xfb, ++ 0x75, 0xe3, 0x71, 0x7b, 0x57, 0x45, 0xf5, 0x97, ++ 0x73, 0x65, 0x63, 0x14, 0x74, 0xb8, 0x82, 0x9f, ++ 0xf8, 0x60, 0x2f, 0x8a, 0xf2, 0x4e, 0xf1, 0x39, ++ 0xda, 0x33, 0x91, 0xf8, 0x36, 0xe0, 0x8d, 0x3f, ++ 0x1f, 0x3b, 0x56, 0xdc, 0xa0, 0x8f, 0x3c, 0x9d, ++ 0x71, 0x52, 0xa7, 0xb8, 0xc0, 0xa5, 0xc6, 0xa2, ++ 0x73, 0xda, 0xf4, 0x4b, 0x74, 0x5b, 0x00, 0x3d, ++ 0x99, 0xd7, 0x96, 0xba, 0xe6, 0xe1, 0xa6, 0x96, ++ 0x38, 0xad, 0xb3, 0xc0, 0xd2, 0xba, 0x91, 0x6b, ++ 0xf9, 0x19, 0xdd, 0x3b, 0xbe, 0xbe, 0x9c, 0x20, ++ 0x50, 0xba, 0xa1, 0xd0, 0xce, 0x11, 0xbd, 0x95, ++ 0xd8, 0xd1, 0xdd, 0x33, 0x85, 0x74, 0xdc, 0xdb, ++ 0x66, 0x76, 0x44, 0xdc, 0x03, 0x74, 0x48, 0x35, ++ 0x98, 0xb1, 0x18, 0x47, 0x94, 0x7d, 0xff, 0x62, ++ 0xe4, 0x58, 0x78, 0xab, 0xed, 0x95, 0x36, 0xd9, ++ 0x84, 0x91, 0x82, 0x64, 0x41, 0xbb, 0x58, 0xe6, ++ 0x1c, 0x20, 0x6d, 0x15, 0x6b, 0x13, 0x96, 0xe8, ++ 0x35, 0x7f, 0xdc, 0x40, 0x2c, 0xe9, 0xbc, 0x8a, ++ 0x4f, 0x92, 0xec, 0x06, 0x2d, 0x50, 0xdf, 0x93, ++ 0x5d, 0x65, 0x5a, 0xa8, 0xfc, 0x20, 0x50, 0x14, ++ 0xa9, 0x8a, 0x7e, 0x1d, 0x08, 0x1f, 0xe2, 0x99, ++ 0xd0, 0xbe, 0xfb, 0x3a, 0x21, 0x9d, 0xad, 0x86, ++ 0x54, 0xfd, 0x0d, 0x98, 0x1c, 0x5a, 0x6f, 0x1f, ++ 0x9a, 0x40, 0xcd, 0xa2, 0xff, 0x6a, 0xf1, 0x54 ++}; ++static const u8 enc_assoc008[] __initconst = { }; ++static const u8 enc_nonce008[] __initconst = { ++ 0x0e, 0x0d, 0x57, 0xbb, 0x7b, 0x40, 0x54, 0x02 ++}; ++static const u8 enc_key008[] __initconst = { ++ 0xf2, 0xaa, 0x4f, 0x99, 0xfd, 0x3e, 0xa8, 0x53, ++ 0xc1, 0x44, 0xe9, 0x81, 0x18, 0xdc, 0xf5, 0xf0, ++ 0x3e, 0x44, 0x15, 0x59, 0xe0, 0xc5, 0x44, 0x86, ++ 0xc3, 0x91, 0xa8, 0x75, 0xc0, 0x12, 0x46, 0xba ++}; ++ ++static const u8 enc_input009[] __initconst = { ++ 0xe6, 0xc3, 0xdb, 0x63, 0x55, 0x15, 0xe3, 0x5b, ++ 0xb7, 0x4b, 0x27, 0x8b, 0x5a, 0xdd, 0xc2, 0xe8, ++ 0x3a, 0x6b, 0xd7, 0x81, 0x96, 0x35, 0x97, 0xca, ++ 0xd7, 0x68, 0xe8, 0xef, 0xce, 0xab, 0xda, 0x09, ++ 0x6e, 0xd6, 0x8e, 0xcb, 0x55, 0xb5, 0xe1, 0xe5, ++ 0x57, 0xfd, 0xc4, 0xe3, 0xe0, 0x18, 0x4f, 0x85, ++ 0xf5, 0x3f, 0x7e, 0x4b, 0x88, 0xc9, 0x52, 0x44, ++ 0x0f, 0xea, 0xaf, 0x1f, 0x71, 0x48, 0x9f, 0x97, ++ 0x6d, 0xb9, 0x6f, 0x00, 0xa6, 0xde, 0x2b, 0x77, ++ 0x8b, 0x15, 0xad, 0x10, 0xa0, 0x2b, 0x7b, 0x41, ++ 0x90, 0x03, 0x2d, 0x69, 0xae, 0xcc, 0x77, 0x7c, ++ 0xa5, 0x9d, 0x29, 0x22, 0xc2, 0xea, 0xb4, 0x00, ++ 0x1a, 0xd2, 0x7a, 0x98, 0x8a, 0xf9, 0xf7, 0x82, ++ 0xb0, 0xab, 0xd8, 0xa6, 0x94, 0x8d, 0x58, 0x2f, ++ 0x01, 0x9e, 0x00, 0x20, 0xfc, 0x49, 0xdc, 0x0e, ++ 0x03, 0xe8, 0x45, 0x10, 0xd6, 0xa8, 0xda, 0x55, ++ 0x10, 0x9a, 0xdf, 0x67, 0x22, 0x8b, 0x43, 0xab, ++ 0x00, 0xbb, 0x02, 0xc8, 0xdd, 0x7b, 0x97, 0x17, ++ 0xd7, 0x1d, 0x9e, 0x02, 0x5e, 0x48, 0xde, 0x8e, ++ 0xcf, 0x99, 0x07, 0x95, 0x92, 0x3c, 0x5f, 0x9f, ++ 0xc5, 0x8a, 0xc0, 0x23, 0xaa, 0xd5, 0x8c, 0x82, ++ 0x6e, 0x16, 0x92, 0xb1, 0x12, 0x17, 0x07, 0xc3, ++ 0xfb, 0x36, 0xf5, 0x6c, 0x35, 0xd6, 0x06, 0x1f, ++ 0x9f, 0xa7, 0x94, 0xa2, 0x38, 0x63, 0x9c, 0xb0, ++ 0x71, 0xb3, 0xa5, 0xd2, 0xd8, 0xba, 0x9f, 0x08, ++ 0x01, 0xb3, 0xff, 0x04, 0x97, 0x73, 0x45, 0x1b, ++ 0xd5, 0xa9, 0x9c, 0x80, 0xaf, 0x04, 0x9a, 0x85, ++ 0xdb, 0x32, 0x5b, 0x5d, 0x1a, 0xc1, 0x36, 0x28, ++ 0x10, 0x79, 0xf1, 0x3c, 0xbf, 0x1a, 0x41, 0x5c, ++ 0x4e, 0xdf, 0xb2, 0x7c, 0x79, 0x3b, 0x7a, 0x62, ++ 0x3d, 0x4b, 0xc9, 0x9b, 0x2a, 0x2e, 0x7c, 0xa2, ++ 0xb1, 0x11, 0x98, 0xa7, 0x34, 0x1a, 0x00, 0xf3, ++ 0xd1, 0xbc, 0x18, 0x22, 0xba, 0x02, 0x56, 0x62, ++ 0x31, 0x10, 0x11, 0x6d, 0xe0, 0x54, 0x9d, 0x40, ++ 0x1f, 0x26, 0x80, 0x41, 0xca, 0x3f, 0x68, 0x0f, ++ 0x32, 0x1d, 0x0a, 0x8e, 0x79, 0xd8, 0xa4, 0x1b, ++ 0x29, 0x1c, 0x90, 0x8e, 0xc5, 0xe3, 0xb4, 0x91, ++ 0x37, 0x9a, 0x97, 0x86, 0x99, 0xd5, 0x09, 0xc5, ++ 0xbb, 0xa3, 0x3f, 0x21, 0x29, 0x82, 0x14, 0x5c, ++ 0xab, 0x25, 0xfb, 0xf2, 0x4f, 0x58, 0x26, 0xd4, ++ 0x83, 0xaa, 0x66, 0x89, 0x67, 0x7e, 0xc0, 0x49, ++ 0xe1, 0x11, 0x10, 0x7f, 0x7a, 0xda, 0x29, 0x04, ++ 0xff, 0xf0, 0xcb, 0x09, 0x7c, 0x9d, 0xfa, 0x03, ++ 0x6f, 0x81, 0x09, 0x31, 0x60, 0xfb, 0x08, 0xfa, ++ 0x74, 0xd3, 0x64, 0x44, 0x7c, 0x55, 0x85, 0xec, ++ 0x9c, 0x6e, 0x25, 0xb7, 0x6c, 0xc5, 0x37, 0xb6, ++ 0x83, 0x87, 0x72, 0x95, 0x8b, 0x9d, 0xe1, 0x69, ++ 0x5c, 0x31, 0x95, 0x42, 0xa6, 0x2c, 0xd1, 0x36, ++ 0x47, 0x1f, 0xec, 0x54, 0xab, 0xa2, 0x1c, 0xd8, ++ 0x00, 0xcc, 0xbc, 0x0d, 0x65, 0xe2, 0x67, 0xbf, ++ 0xbc, 0xea, 0xee, 0x9e, 0xe4, 0x36, 0x95, 0xbe, ++ 0x73, 0xd9, 0xa6, 0xd9, 0x0f, 0xa0, 0xcc, 0x82, ++ 0x76, 0x26, 0xad, 0x5b, 0x58, 0x6c, 0x4e, 0xab, ++ 0x29, 0x64, 0xd3, 0xd9, 0xa9, 0x08, 0x8c, 0x1d, ++ 0xa1, 0x4f, 0x80, 0xd8, 0x3f, 0x94, 0xfb, 0xd3, ++ 0x7b, 0xfc, 0xd1, 0x2b, 0xc3, 0x21, 0xeb, 0xe5, ++ 0x1c, 0x84, 0x23, 0x7f, 0x4b, 0xfa, 0xdb, 0x34, ++ 0x18, 0xa2, 0xc2, 0xe5, 0x13, 0xfe, 0x6c, 0x49, ++ 0x81, 0xd2, 0x73, 0xe7, 0xe2, 0xd7, 0xe4, 0x4f, ++ 0x4b, 0x08, 0x6e, 0xb1, 0x12, 0x22, 0x10, 0x9d, ++ 0xac, 0x51, 0x1e, 0x17, 0xd9, 0x8a, 0x0b, 0x42, ++ 0x88, 0x16, 0x81, 0x37, 0x7c, 0x6a, 0xf7, 0xef, ++ 0x2d, 0xe3, 0xd9, 0xf8, 0x5f, 0xe0, 0x53, 0x27, ++ 0x74, 0xb9, 0xe2, 0xd6, 0x1c, 0x80, 0x2c, 0x52, ++ 0x65 ++}; ++static const u8 enc_output009[] __initconst = { ++ 0xfd, 0x81, 0x8d, 0xd0, 0x3d, 0xb4, 0xd5, 0xdf, ++ 0xd3, 0x42, 0x47, 0x5a, 0x6d, 0x19, 0x27, 0x66, ++ 0x4b, 0x2e, 0x0c, 0x27, 0x9c, 0x96, 0x4c, 0x72, ++ 0x02, 0xa3, 0x65, 0xc3, 0xb3, 0x6f, 0x2e, 0xbd, ++ 0x63, 0x8a, 0x4a, 0x5d, 0x29, 0xa2, 0xd0, 0x28, ++ 0x48, 0xc5, 0x3d, 0x98, 0xa3, 0xbc, 0xe0, 0xbe, ++ 0x3b, 0x3f, 0xe6, 0x8a, 0xa4, 0x7f, 0x53, 0x06, ++ 0xfa, 0x7f, 0x27, 0x76, 0x72, 0x31, 0xa1, 0xf5, ++ 0xd6, 0x0c, 0x52, 0x47, 0xba, 0xcd, 0x4f, 0xd7, ++ 0xeb, 0x05, 0x48, 0x0d, 0x7c, 0x35, 0x4a, 0x09, ++ 0xc9, 0x76, 0x71, 0x02, 0xa3, 0xfb, 0xb7, 0x1a, ++ 0x65, 0xb7, 0xed, 0x98, 0xc6, 0x30, 0x8a, 0x00, ++ 0xae, 0xa1, 0x31, 0xe5, 0xb5, 0x9e, 0x6d, 0x62, ++ 0xda, 0xda, 0x07, 0x0f, 0x38, 0x38, 0xd3, 0xcb, ++ 0xc1, 0xb0, 0xad, 0xec, 0x72, 0xec, 0xb1, 0xa2, ++ 0x7b, 0x59, 0xf3, 0x3d, 0x2b, 0xef, 0xcd, 0x28, ++ 0x5b, 0x83, 0xcc, 0x18, 0x91, 0x88, 0xb0, 0x2e, ++ 0xf9, 0x29, 0x31, 0x18, 0xf9, 0x4e, 0xe9, 0x0a, ++ 0x91, 0x92, 0x9f, 0xae, 0x2d, 0xad, 0xf4, 0xe6, ++ 0x1a, 0xe2, 0xa4, 0xee, 0x47, 0x15, 0xbf, 0x83, ++ 0x6e, 0xd7, 0x72, 0x12, 0x3b, 0x2d, 0x24, 0xe9, ++ 0xb2, 0x55, 0xcb, 0x3c, 0x10, 0xf0, 0x24, 0x8a, ++ 0x4a, 0x02, 0xea, 0x90, 0x25, 0xf0, 0xb4, 0x79, ++ 0x3a, 0xef, 0x6e, 0xf5, 0x52, 0xdf, 0xb0, 0x0a, ++ 0xcd, 0x24, 0x1c, 0xd3, 0x2e, 0x22, 0x74, 0xea, ++ 0x21, 0x6f, 0xe9, 0xbd, 0xc8, 0x3e, 0x36, 0x5b, ++ 0x19, 0xf1, 0xca, 0x99, 0x0a, 0xb4, 0xa7, 0x52, ++ 0x1a, 0x4e, 0xf2, 0xad, 0x8d, 0x56, 0x85, 0xbb, ++ 0x64, 0x89, 0xba, 0x26, 0xf9, 0xc7, 0xe1, 0x89, ++ 0x19, 0x22, 0x77, 0xc3, 0xa8, 0xfc, 0xff, 0xad, ++ 0xfe, 0xb9, 0x48, 0xae, 0x12, 0x30, 0x9f, 0x19, ++ 0xfb, 0x1b, 0xef, 0x14, 0x87, 0x8a, 0x78, 0x71, ++ 0xf3, 0xf4, 0xb7, 0x00, 0x9c, 0x1d, 0xb5, 0x3d, ++ 0x49, 0x00, 0x0c, 0x06, 0xd4, 0x50, 0xf9, 0x54, ++ 0x45, 0xb2, 0x5b, 0x43, 0xdb, 0x6d, 0xcf, 0x1a, ++ 0xe9, 0x7a, 0x7a, 0xcf, 0xfc, 0x8a, 0x4e, 0x4d, ++ 0x0b, 0x07, 0x63, 0x28, 0xd8, 0xe7, 0x08, 0x95, ++ 0xdf, 0xa6, 0x72, 0x93, 0x2e, 0xbb, 0xa0, 0x42, ++ 0x89, 0x16, 0xf1, 0xd9, 0x0c, 0xf9, 0xa1, 0x16, ++ 0xfd, 0xd9, 0x03, 0xb4, 0x3b, 0x8a, 0xf5, 0xf6, ++ 0xe7, 0x6b, 0x2e, 0x8e, 0x4c, 0x3d, 0xe2, 0xaf, ++ 0x08, 0x45, 0x03, 0xff, 0x09, 0xb6, 0xeb, 0x2d, ++ 0xc6, 0x1b, 0x88, 0x94, 0xac, 0x3e, 0xf1, 0x9f, ++ 0x0e, 0x0e, 0x2b, 0xd5, 0x00, 0x4d, 0x3f, 0x3b, ++ 0x53, 0xae, 0xaf, 0x1c, 0x33, 0x5f, 0x55, 0x6e, ++ 0x8d, 0xaf, 0x05, 0x7a, 0x10, 0x34, 0xc9, 0xf4, ++ 0x66, 0xcb, 0x62, 0x12, 0xa6, 0xee, 0xe8, 0x1c, ++ 0x5d, 0x12, 0x86, 0xdb, 0x6f, 0x1c, 0x33, 0xc4, ++ 0x1c, 0xda, 0x82, 0x2d, 0x3b, 0x59, 0xfe, 0xb1, ++ 0xa4, 0x59, 0x41, 0x86, 0xd0, 0xef, 0xae, 0xfb, ++ 0xda, 0x6d, 0x11, 0xb8, 0xca, 0xe9, 0x6e, 0xff, ++ 0xf7, 0xa9, 0xd9, 0x70, 0x30, 0xfc, 0x53, 0xe2, ++ 0xd7, 0xa2, 0x4e, 0xc7, 0x91, 0xd9, 0x07, 0x06, ++ 0xaa, 0xdd, 0xb0, 0x59, 0x28, 0x1d, 0x00, 0x66, ++ 0xc5, 0x54, 0xc2, 0xfc, 0x06, 0xda, 0x05, 0x90, ++ 0x52, 0x1d, 0x37, 0x66, 0xee, 0xf0, 0xb2, 0x55, ++ 0x8a, 0x5d, 0xd2, 0x38, 0x86, 0x94, 0x9b, 0xfc, ++ 0x10, 0x4c, 0xa1, 0xb9, 0x64, 0x3e, 0x44, 0xb8, ++ 0x5f, 0xb0, 0x0c, 0xec, 0xe0, 0xc9, 0xe5, 0x62, ++ 0x75, 0x3f, 0x09, 0xd5, 0xf5, 0xd9, 0x26, 0xba, ++ 0x9e, 0xd2, 0xf4, 0xb9, 0x48, 0x0a, 0xbc, 0xa2, ++ 0xd6, 0x7c, 0x36, 0x11, 0x7d, 0x26, 0x81, 0x89, ++ 0xcf, 0xa4, 0xad, 0x73, 0x0e, 0xee, 0xcc, 0x06, ++ 0xa9, 0xdb, 0xb1, 0xfd, 0xfb, 0x09, 0x7f, 0x90, ++ 0x42, 0x37, 0x2f, 0xe1, 0x9c, 0x0f, 0x6f, 0xcf, ++ 0x43, 0xb5, 0xd9, 0x90, 0xe1, 0x85, 0xf5, 0xa8, ++ 0xae ++}; ++static const u8 enc_assoc009[] __initconst = { ++ 0x5a, 0x27, 0xff, 0xeb, 0xdf, 0x84, 0xb2, 0x9e, ++ 0xef ++}; ++static const u8 enc_nonce009[] __initconst = { ++ 0xef, 0x2d, 0x63, 0xee, 0x6b, 0x80, 0x8b, 0x78 ++}; ++static const u8 enc_key009[] __initconst = { ++ 0xea, 0xbc, 0x56, 0x99, 0xe3, 0x50, 0xff, 0xc5, ++ 0xcc, 0x1a, 0xd7, 0xc1, 0x57, 0x72, 0xea, 0x86, ++ 0x5b, 0x89, 0x88, 0x61, 0x3d, 0x2f, 0x9b, 0xb2, ++ 0xe7, 0x9c, 0xec, 0x74, 0x6e, 0x3e, 0xf4, 0x3b ++}; ++ ++static const u8 enc_input010[] __initconst = { ++ 0x42, 0x93, 0xe4, 0xeb, 0x97, 0xb0, 0x57, 0xbf, ++ 0x1a, 0x8b, 0x1f, 0xe4, 0x5f, 0x36, 0x20, 0x3c, ++ 0xef, 0x0a, 0xa9, 0x48, 0x5f, 0x5f, 0x37, 0x22, ++ 0x3a, 0xde, 0xe3, 0xae, 0xbe, 0xad, 0x07, 0xcc, ++ 0xb1, 0xf6, 0xf5, 0xf9, 0x56, 0xdd, 0xe7, 0x16, ++ 0x1e, 0x7f, 0xdf, 0x7a, 0x9e, 0x75, 0xb7, 0xc7, ++ 0xbe, 0xbe, 0x8a, 0x36, 0x04, 0xc0, 0x10, 0xf4, ++ 0x95, 0x20, 0x03, 0xec, 0xdc, 0x05, 0xa1, 0x7d, ++ 0xc4, 0xa9, 0x2c, 0x82, 0xd0, 0xbc, 0x8b, 0xc5, ++ 0xc7, 0x45, 0x50, 0xf6, 0xa2, 0x1a, 0xb5, 0x46, ++ 0x3b, 0x73, 0x02, 0xa6, 0x83, 0x4b, 0x73, 0x82, ++ 0x58, 0x5e, 0x3b, 0x65, 0x2f, 0x0e, 0xfd, 0x2b, ++ 0x59, 0x16, 0xce, 0xa1, 0x60, 0x9c, 0xe8, 0x3a, ++ 0x99, 0xed, 0x8d, 0x5a, 0xcf, 0xf6, 0x83, 0xaf, ++ 0xba, 0xd7, 0x73, 0x73, 0x40, 0x97, 0x3d, 0xca, ++ 0xef, 0x07, 0x57, 0xe6, 0xd9, 0x70, 0x0e, 0x95, ++ 0xae, 0xa6, 0x8d, 0x04, 0xcc, 0xee, 0xf7, 0x09, ++ 0x31, 0x77, 0x12, 0xa3, 0x23, 0x97, 0x62, 0xb3, ++ 0x7b, 0x32, 0xfb, 0x80, 0x14, 0x48, 0x81, 0xc3, ++ 0xe5, 0xea, 0x91, 0x39, 0x52, 0x81, 0xa2, 0x4f, ++ 0xe4, 0xb3, 0x09, 0xff, 0xde, 0x5e, 0xe9, 0x58, ++ 0x84, 0x6e, 0xf9, 0x3d, 0xdf, 0x25, 0xea, 0xad, ++ 0xae, 0xe6, 0x9a, 0xd1, 0x89, 0x55, 0xd3, 0xde, ++ 0x6c, 0x52, 0xdb, 0x70, 0xfe, 0x37, 0xce, 0x44, ++ 0x0a, 0xa8, 0x25, 0x5f, 0x92, 0xc1, 0x33, 0x4a, ++ 0x4f, 0x9b, 0x62, 0x35, 0xff, 0xce, 0xc0, 0xa9, ++ 0x60, 0xce, 0x52, 0x00, 0x97, 0x51, 0x35, 0x26, ++ 0x2e, 0xb9, 0x36, 0xa9, 0x87, 0x6e, 0x1e, 0xcc, ++ 0x91, 0x78, 0x53, 0x98, 0x86, 0x5b, 0x9c, 0x74, ++ 0x7d, 0x88, 0x33, 0xe1, 0xdf, 0x37, 0x69, 0x2b, ++ 0xbb, 0xf1, 0x4d, 0xf4, 0xd1, 0xf1, 0x39, 0x93, ++ 0x17, 0x51, 0x19, 0xe3, 0x19, 0x1e, 0x76, 0x37, ++ 0x25, 0xfb, 0x09, 0x27, 0x6a, 0xab, 0x67, 0x6f, ++ 0x14, 0x12, 0x64, 0xe7, 0xc4, 0x07, 0xdf, 0x4d, ++ 0x17, 0xbb, 0x6d, 0xe0, 0xe9, 0xb9, 0xab, 0xca, ++ 0x10, 0x68, 0xaf, 0x7e, 0xb7, 0x33, 0x54, 0x73, ++ 0x07, 0x6e, 0xf7, 0x81, 0x97, 0x9c, 0x05, 0x6f, ++ 0x84, 0x5f, 0xd2, 0x42, 0xfb, 0x38, 0xcf, 0xd1, ++ 0x2f, 0x14, 0x30, 0x88, 0x98, 0x4d, 0x5a, 0xa9, ++ 0x76, 0xd5, 0x4f, 0x3e, 0x70, 0x6c, 0x85, 0x76, ++ 0xd7, 0x01, 0xa0, 0x1a, 0xc8, 0x4e, 0xaa, 0xac, ++ 0x78, 0xfe, 0x46, 0xde, 0x6a, 0x05, 0x46, 0xa7, ++ 0x43, 0x0c, 0xb9, 0xde, 0xb9, 0x68, 0xfb, 0xce, ++ 0x42, 0x99, 0x07, 0x4d, 0x0b, 0x3b, 0x5a, 0x30, ++ 0x35, 0xa8, 0xf9, 0x3a, 0x73, 0xef, 0x0f, 0xdb, ++ 0x1e, 0x16, 0x42, 0xc4, 0xba, 0xae, 0x58, 0xaa, ++ 0xf8, 0xe5, 0x75, 0x2f, 0x1b, 0x15, 0x5c, 0xfd, ++ 0x0a, 0x97, 0xd0, 0xe4, 0x37, 0x83, 0x61, 0x5f, ++ 0x43, 0xa6, 0xc7, 0x3f, 0x38, 0x59, 0xe6, 0xeb, ++ 0xa3, 0x90, 0xc3, 0xaa, 0xaa, 0x5a, 0xd3, 0x34, ++ 0xd4, 0x17, 0xc8, 0x65, 0x3e, 0x57, 0xbc, 0x5e, ++ 0xdd, 0x9e, 0xb7, 0xf0, 0x2e, 0x5b, 0xb2, 0x1f, ++ 0x8a, 0x08, 0x0d, 0x45, 0x91, 0x0b, 0x29, 0x53, ++ 0x4f, 0x4c, 0x5a, 0x73, 0x56, 0xfe, 0xaf, 0x41, ++ 0x01, 0x39, 0x0a, 0x24, 0x3c, 0x7e, 0xbe, 0x4e, ++ 0x53, 0xf3, 0xeb, 0x06, 0x66, 0x51, 0x28, 0x1d, ++ 0xbd, 0x41, 0x0a, 0x01, 0xab, 0x16, 0x47, 0x27, ++ 0x47, 0x47, 0xf7, 0xcb, 0x46, 0x0a, 0x70, 0x9e, ++ 0x01, 0x9c, 0x09, 0xe1, 0x2a, 0x00, 0x1a, 0xd8, ++ 0xd4, 0x79, 0x9d, 0x80, 0x15, 0x8e, 0x53, 0x2a, ++ 0x65, 0x83, 0x78, 0x3e, 0x03, 0x00, 0x07, 0x12, ++ 0x1f, 0x33, 0x3e, 0x7b, 0x13, 0x37, 0xf1, 0xc3, ++ 0xef, 0xb7, 0xc1, 0x20, 0x3c, 0x3e, 0x67, 0x66, ++ 0x5d, 0x88, 0xa7, 0x7d, 0x33, 0x50, 0x77, 0xb0, ++ 0x28, 0x8e, 0xe7, 0x2c, 0x2e, 0x7a, 0xf4, 0x3c, ++ 0x8d, 0x74, 0x83, 0xaf, 0x8e, 0x87, 0x0f, 0xe4, ++ 0x50, 0xff, 0x84, 0x5c, 0x47, 0x0c, 0x6a, 0x49, ++ 0xbf, 0x42, 0x86, 0x77, 0x15, 0x48, 0xa5, 0x90, ++ 0x5d, 0x93, 0xd6, 0x2a, 0x11, 0xd5, 0xd5, 0x11, ++ 0xaa, 0xce, 0xe7, 0x6f, 0xa5, 0xb0, 0x09, 0x2c, ++ 0x8d, 0xd3, 0x92, 0xf0, 0x5a, 0x2a, 0xda, 0x5b, ++ 0x1e, 0xd5, 0x9a, 0xc4, 0xc4, 0xf3, 0x49, 0x74, ++ 0x41, 0xca, 0xe8, 0xc1, 0xf8, 0x44, 0xd6, 0x3c, ++ 0xae, 0x6c, 0x1d, 0x9a, 0x30, 0x04, 0x4d, 0x27, ++ 0x0e, 0xb1, 0x5f, 0x59, 0xa2, 0x24, 0xe8, 0xe1, ++ 0x98, 0xc5, 0x6a, 0x4c, 0xfe, 0x41, 0xd2, 0x27, ++ 0x42, 0x52, 0xe1, 0xe9, 0x7d, 0x62, 0xe4, 0x88, ++ 0x0f, 0xad, 0xb2, 0x70, 0xcb, 0x9d, 0x4c, 0x27, ++ 0x2e, 0x76, 0x1e, 0x1a, 0x63, 0x65, 0xf5, 0x3b, ++ 0xf8, 0x57, 0x69, 0xeb, 0x5b, 0x38, 0x26, 0x39, ++ 0x33, 0x25, 0x45, 0x3e, 0x91, 0xb8, 0xd8, 0xc7, ++ 0xd5, 0x42, 0xc0, 0x22, 0x31, 0x74, 0xf4, 0xbc, ++ 0x0c, 0x23, 0xf1, 0xca, 0xc1, 0x8d, 0xd7, 0xbe, ++ 0xc9, 0x62, 0xe4, 0x08, 0x1a, 0xcf, 0x36, 0xd5, ++ 0xfe, 0x55, 0x21, 0x59, 0x91, 0x87, 0x87, 0xdf, ++ 0x06, 0xdb, 0xdf, 0x96, 0x45, 0x58, 0xda, 0x05, ++ 0xcd, 0x50, 0x4d, 0xd2, 0x7d, 0x05, 0x18, 0x73, ++ 0x6a, 0x8d, 0x11, 0x85, 0xa6, 0x88, 0xe8, 0xda, ++ 0xe6, 0x30, 0x33, 0xa4, 0x89, 0x31, 0x75, 0xbe, ++ 0x69, 0x43, 0x84, 0x43, 0x50, 0x87, 0xdd, 0x71, ++ 0x36, 0x83, 0xc3, 0x78, 0x74, 0x24, 0x0a, 0xed, ++ 0x7b, 0xdb, 0xa4, 0x24, 0x0b, 0xb9, 0x7e, 0x5d, ++ 0xff, 0xde, 0xb1, 0xef, 0x61, 0x5a, 0x45, 0x33, ++ 0xf6, 0x17, 0x07, 0x08, 0x98, 0x83, 0x92, 0x0f, ++ 0x23, 0x6d, 0xe6, 0xaa, 0x17, 0x54, 0xad, 0x6a, ++ 0xc8, 0xdb, 0x26, 0xbe, 0xb8, 0xb6, 0x08, 0xfa, ++ 0x68, 0xf1, 0xd7, 0x79, 0x6f, 0x18, 0xb4, 0x9e, ++ 0x2d, 0x3f, 0x1b, 0x64, 0xaf, 0x8d, 0x06, 0x0e, ++ 0x49, 0x28, 0xe0, 0x5d, 0x45, 0x68, 0x13, 0x87, ++ 0xfa, 0xde, 0x40, 0x7b, 0xd2, 0xc3, 0x94, 0xd5, ++ 0xe1, 0xd9, 0xc2, 0xaf, 0x55, 0x89, 0xeb, 0xb4, ++ 0x12, 0x59, 0xa8, 0xd4, 0xc5, 0x29, 0x66, 0x38, ++ 0xe6, 0xac, 0x22, 0x22, 0xd9, 0x64, 0x9b, 0x34, ++ 0x0a, 0x32, 0x9f, 0xc2, 0xbf, 0x17, 0x6c, 0x3f, ++ 0x71, 0x7a, 0x38, 0x6b, 0x98, 0xfb, 0x49, 0x36, ++ 0x89, 0xc9, 0xe2, 0xd6, 0xc7, 0x5d, 0xd0, 0x69, ++ 0x5f, 0x23, 0x35, 0xc9, 0x30, 0xe2, 0xfd, 0x44, ++ 0x58, 0x39, 0xd7, 0x97, 0xfb, 0x5c, 0x00, 0xd5, ++ 0x4f, 0x7a, 0x1a, 0x95, 0x8b, 0x62, 0x4b, 0xce, ++ 0xe5, 0x91, 0x21, 0x7b, 0x30, 0x00, 0xd6, 0xdd, ++ 0x6d, 0x02, 0x86, 0x49, 0x0f, 0x3c, 0x1a, 0x27, ++ 0x3c, 0xd3, 0x0e, 0x71, 0xf2, 0xff, 0xf5, 0x2f, ++ 0x87, 0xac, 0x67, 0x59, 0x81, 0xa3, 0xf7, 0xf8, ++ 0xd6, 0x11, 0x0c, 0x84, 0xa9, 0x03, 0xee, 0x2a, ++ 0xc4, 0xf3, 0x22, 0xab, 0x7c, 0xe2, 0x25, 0xf5, ++ 0x67, 0xa3, 0xe4, 0x11, 0xe0, 0x59, 0xb3, 0xca, ++ 0x87, 0xa0, 0xae, 0xc9, 0xa6, 0x62, 0x1b, 0x6e, ++ 0x4d, 0x02, 0x6b, 0x07, 0x9d, 0xfd, 0xd0, 0x92, ++ 0x06, 0xe1, 0xb2, 0x9a, 0x4a, 0x1f, 0x1f, 0x13, ++ 0x49, 0x99, 0x97, 0x08, 0xde, 0x7f, 0x98, 0xaf, ++ 0x51, 0x98, 0xee, 0x2c, 0xcb, 0xf0, 0x0b, 0xc6, ++ 0xb6, 0xb7, 0x2d, 0x9a, 0xb1, 0xac, 0xa6, 0xe3, ++ 0x15, 0x77, 0x9d, 0x6b, 0x1a, 0xe4, 0xfc, 0x8b, ++ 0xf2, 0x17, 0x59, 0x08, 0x04, 0x58, 0x81, 0x9d, ++ 0x1b, 0x1b, 0x69, 0x55, 0xc2, 0xb4, 0x3c, 0x1f, ++ 0x50, 0xf1, 0x7f, 0x77, 0x90, 0x4c, 0x66, 0x40, ++ 0x5a, 0xc0, 0x33, 0x1f, 0xcb, 0x05, 0x6d, 0x5c, ++ 0x06, 0x87, 0x52, 0xa2, 0x8f, 0x26, 0xd5, 0x4f ++}; ++static const u8 enc_output010[] __initconst = { ++ 0xe5, 0x26, 0xa4, 0x3d, 0xbd, 0x33, 0xd0, 0x4b, ++ 0x6f, 0x05, 0xa7, 0x6e, 0x12, 0x7a, 0xd2, 0x74, ++ 0xa6, 0xdd, 0xbd, 0x95, 0xeb, 0xf9, 0xa4, 0xf1, ++ 0x59, 0x93, 0x91, 0x70, 0xd9, 0xfe, 0x9a, 0xcd, ++ 0x53, 0x1f, 0x3a, 0xab, 0xa6, 0x7c, 0x9f, 0xa6, ++ 0x9e, 0xbd, 0x99, 0xd9, 0xb5, 0x97, 0x44, 0xd5, ++ 0x14, 0x48, 0x4d, 0x9d, 0xc0, 0xd0, 0x05, 0x96, ++ 0xeb, 0x4c, 0x78, 0x55, 0x09, 0x08, 0x01, 0x02, ++ 0x30, 0x90, 0x7b, 0x96, 0x7a, 0x7b, 0x5f, 0x30, ++ 0x41, 0x24, 0xce, 0x68, 0x61, 0x49, 0x86, 0x57, ++ 0x82, 0xdd, 0x53, 0x1c, 0x51, 0x28, 0x2b, 0x53, ++ 0x6e, 0x2d, 0xc2, 0x20, 0x4c, 0xdd, 0x8f, 0x65, ++ 0x10, 0x20, 0x50, 0xdd, 0x9d, 0x50, 0xe5, 0x71, ++ 0x40, 0x53, 0x69, 0xfc, 0x77, 0x48, 0x11, 0xb9, ++ 0xde, 0xa4, 0x8d, 0x58, 0xe4, 0xa6, 0x1a, 0x18, ++ 0x47, 0x81, 0x7e, 0xfc, 0xdd, 0xf6, 0xef, 0xce, ++ 0x2f, 0x43, 0x68, 0xd6, 0x06, 0xe2, 0x74, 0x6a, ++ 0xad, 0x90, 0xf5, 0x37, 0xf3, 0x3d, 0x82, 0x69, ++ 0x40, 0xe9, 0x6b, 0xa7, 0x3d, 0xa8, 0x1e, 0xd2, ++ 0x02, 0x7c, 0xb7, 0x9b, 0xe4, 0xda, 0x8f, 0x95, ++ 0x06, 0xc5, 0xdf, 0x73, 0xa3, 0x20, 0x9a, 0x49, ++ 0xde, 0x9c, 0xbc, 0xee, 0x14, 0x3f, 0x81, 0x5e, ++ 0xf8, 0x3b, 0x59, 0x3c, 0xe1, 0x68, 0x12, 0x5a, ++ 0x3a, 0x76, 0x3a, 0x3f, 0xf7, 0x87, 0x33, 0x0a, ++ 0x01, 0xb8, 0xd4, 0xed, 0xb6, 0xbe, 0x94, 0x5e, ++ 0x70, 0x40, 0x56, 0x67, 0x1f, 0x50, 0x44, 0x19, ++ 0xce, 0x82, 0x70, 0x10, 0x87, 0x13, 0x20, 0x0b, ++ 0x4c, 0x5a, 0xb6, 0xf6, 0xa7, 0xae, 0x81, 0x75, ++ 0x01, 0x81, 0xe6, 0x4b, 0x57, 0x7c, 0xdd, 0x6d, ++ 0xf8, 0x1c, 0x29, 0x32, 0xf7, 0xda, 0x3c, 0x2d, ++ 0xf8, 0x9b, 0x25, 0x6e, 0x00, 0xb4, 0xf7, 0x2f, ++ 0xf7, 0x04, 0xf7, 0xa1, 0x56, 0xac, 0x4f, 0x1a, ++ 0x64, 0xb8, 0x47, 0x55, 0x18, 0x7b, 0x07, 0x4d, ++ 0xbd, 0x47, 0x24, 0x80, 0x5d, 0xa2, 0x70, 0xc5, ++ 0xdd, 0x8e, 0x82, 0xd4, 0xeb, 0xec, 0xb2, 0x0c, ++ 0x39, 0xd2, 0x97, 0xc1, 0xcb, 0xeb, 0xf4, 0x77, ++ 0x59, 0xb4, 0x87, 0xef, 0xcb, 0x43, 0x2d, 0x46, ++ 0x54, 0xd1, 0xa7, 0xd7, 0x15, 0x99, 0x0a, 0x43, ++ 0xa1, 0xe0, 0x99, 0x33, 0x71, 0xc1, 0xed, 0xfe, ++ 0x72, 0x46, 0x33, 0x8e, 0x91, 0x08, 0x9f, 0xc8, ++ 0x2e, 0xca, 0xfa, 0xdc, 0x59, 0xd5, 0xc3, 0x76, ++ 0x84, 0x9f, 0xa3, 0x37, 0x68, 0xc3, 0xf0, 0x47, ++ 0x2c, 0x68, 0xdb, 0x5e, 0xc3, 0x49, 0x4c, 0xe8, ++ 0x92, 0x85, 0xe2, 0x23, 0xd3, 0x3f, 0xad, 0x32, ++ 0xe5, 0x2b, 0x82, 0xd7, 0x8f, 0x99, 0x0a, 0x59, ++ 0x5c, 0x45, 0xd9, 0xb4, 0x51, 0x52, 0xc2, 0xae, ++ 0xbf, 0x80, 0xcf, 0xc9, 0xc9, 0x51, 0x24, 0x2a, ++ 0x3b, 0x3a, 0x4d, 0xae, 0xeb, 0xbd, 0x22, 0xc3, ++ 0x0e, 0x0f, 0x59, 0x25, 0x92, 0x17, 0xe9, 0x74, ++ 0xc7, 0x8b, 0x70, 0x70, 0x36, 0x55, 0x95, 0x75, ++ 0x4b, 0xad, 0x61, 0x2b, 0x09, 0xbc, 0x82, 0xf2, ++ 0x6e, 0x94, 0x43, 0xae, 0xc3, 0xd5, 0xcd, 0x8e, ++ 0xfe, 0x5b, 0x9a, 0x88, 0x43, 0x01, 0x75, 0xb2, ++ 0x23, 0x09, 0xf7, 0x89, 0x83, 0xe7, 0xfa, 0xf9, ++ 0xb4, 0x9b, 0xf8, 0xef, 0xbd, 0x1c, 0x92, 0xc1, ++ 0xda, 0x7e, 0xfe, 0x05, 0xba, 0x5a, 0xcd, 0x07, ++ 0x6a, 0x78, 0x9e, 0x5d, 0xfb, 0x11, 0x2f, 0x79, ++ 0x38, 0xb6, 0xc2, 0x5b, 0x6b, 0x51, 0xb4, 0x71, ++ 0xdd, 0xf7, 0x2a, 0xe4, 0xf4, 0x72, 0x76, 0xad, ++ 0xc2, 0xdd, 0x64, 0x5d, 0x79, 0xb6, 0xf5, 0x7a, ++ 0x77, 0x20, 0x05, 0x3d, 0x30, 0x06, 0xd4, 0x4c, ++ 0x0a, 0x2c, 0x98, 0x5a, 0xb9, 0xd4, 0x98, 0xa9, ++ 0x3f, 0xc6, 0x12, 0xea, 0x3b, 0x4b, 0xc5, 0x79, ++ 0x64, 0x63, 0x6b, 0x09, 0x54, 0x3b, 0x14, 0x27, ++ 0xba, 0x99, 0x80, 0xc8, 0x72, 0xa8, 0x12, 0x90, ++ 0x29, 0xba, 0x40, 0x54, 0x97, 0x2b, 0x7b, 0xfe, ++ 0xeb, 0xcd, 0x01, 0x05, 0x44, 0x72, 0xdb, 0x99, ++ 0xe4, 0x61, 0xc9, 0x69, 0xd6, 0xb9, 0x28, 0xd1, ++ 0x05, 0x3e, 0xf9, 0x0b, 0x49, 0x0a, 0x49, 0xe9, ++ 0x8d, 0x0e, 0xa7, 0x4a, 0x0f, 0xaf, 0x32, 0xd0, ++ 0xe0, 0xb2, 0x3a, 0x55, 0x58, 0xfe, 0x5c, 0x28, ++ 0x70, 0x51, 0x23, 0xb0, 0x7b, 0x6a, 0x5f, 0x1e, ++ 0xb8, 0x17, 0xd7, 0x94, 0x15, 0x8f, 0xee, 0x20, ++ 0xc7, 0x42, 0x25, 0x3e, 0x9a, 0x14, 0xd7, 0x60, ++ 0x72, 0x39, 0x47, 0x48, 0xa9, 0xfe, 0xdd, 0x47, ++ 0x0a, 0xb1, 0xe6, 0x60, 0x28, 0x8c, 0x11, 0x68, ++ 0xe1, 0xff, 0xd7, 0xce, 0xc8, 0xbe, 0xb3, 0xfe, ++ 0x27, 0x30, 0x09, 0x70, 0xd7, 0xfa, 0x02, 0x33, ++ 0x3a, 0x61, 0x2e, 0xc7, 0xff, 0xa4, 0x2a, 0xa8, ++ 0x6e, 0xb4, 0x79, 0x35, 0x6d, 0x4c, 0x1e, 0x38, ++ 0xf8, 0xee, 0xd4, 0x84, 0x4e, 0x6e, 0x28, 0xa7, ++ 0xce, 0xc8, 0xc1, 0xcf, 0x80, 0x05, 0xf3, 0x04, ++ 0xef, 0xc8, 0x18, 0x28, 0x2e, 0x8d, 0x5e, 0x0c, ++ 0xdf, 0xb8, 0x5f, 0x96, 0xe8, 0xc6, 0x9c, 0x2f, ++ 0xe5, 0xa6, 0x44, 0xd7, 0xe7, 0x99, 0x44, 0x0c, ++ 0xec, 0xd7, 0x05, 0x60, 0x97, 0xbb, 0x74, 0x77, ++ 0x58, 0xd5, 0xbb, 0x48, 0xde, 0x5a, 0xb2, 0x54, ++ 0x7f, 0x0e, 0x46, 0x70, 0x6a, 0x6f, 0x78, 0xa5, ++ 0x08, 0x89, 0x05, 0x4e, 0x7e, 0xa0, 0x69, 0xb4, ++ 0x40, 0x60, 0x55, 0x77, 0x75, 0x9b, 0x19, 0xf2, ++ 0xd5, 0x13, 0x80, 0x77, 0xf9, 0x4b, 0x3f, 0x1e, ++ 0xee, 0xe6, 0x76, 0x84, 0x7b, 0x8c, 0xe5, 0x27, ++ 0xa8, 0x0a, 0x91, 0x01, 0x68, 0x71, 0x8a, 0x3f, ++ 0x06, 0xab, 0xf6, 0xa9, 0xa5, 0xe6, 0x72, 0x92, ++ 0xe4, 0x67, 0xe2, 0xa2, 0x46, 0x35, 0x84, 0x55, ++ 0x7d, 0xca, 0xa8, 0x85, 0xd0, 0xf1, 0x3f, 0xbe, ++ 0xd7, 0x34, 0x64, 0xfc, 0xae, 0xe3, 0xe4, 0x04, ++ 0x9f, 0x66, 0x02, 0xb9, 0x88, 0x10, 0xd9, 0xc4, ++ 0x4c, 0x31, 0x43, 0x7a, 0x93, 0xe2, 0x9b, 0x56, ++ 0x43, 0x84, 0xdc, 0xdc, 0xde, 0x1d, 0xa4, 0x02, ++ 0x0e, 0xc2, 0xef, 0xc3, 0xf8, 0x78, 0xd1, 0xb2, ++ 0x6b, 0x63, 0x18, 0xc9, 0xa9, 0xe5, 0x72, 0xd8, ++ 0xf3, 0xb9, 0xd1, 0x8a, 0xc7, 0x1a, 0x02, 0x27, ++ 0x20, 0x77, 0x10, 0xe5, 0xc8, 0xd4, 0x4a, 0x47, ++ 0xe5, 0xdf, 0x5f, 0x01, 0xaa, 0xb0, 0xd4, 0x10, ++ 0xbb, 0x69, 0xe3, 0x36, 0xc8, 0xe1, 0x3d, 0x43, ++ 0xfb, 0x86, 0xcd, 0xcc, 0xbf, 0xf4, 0x88, 0xe0, ++ 0x20, 0xca, 0xb7, 0x1b, 0xf1, 0x2f, 0x5c, 0xee, ++ 0xd4, 0xd3, 0xa3, 0xcc, 0xa4, 0x1e, 0x1c, 0x47, ++ 0xfb, 0xbf, 0xfc, 0xa2, 0x41, 0x55, 0x9d, 0xf6, ++ 0x5a, 0x5e, 0x65, 0x32, 0x34, 0x7b, 0x52, 0x8d, ++ 0xd5, 0xd0, 0x20, 0x60, 0x03, 0xab, 0x3f, 0x8c, ++ 0xd4, 0x21, 0xea, 0x2a, 0xd9, 0xc4, 0xd0, 0xd3, ++ 0x65, 0xd8, 0x7a, 0x13, 0x28, 0x62, 0x32, 0x4b, ++ 0x2c, 0x87, 0x93, 0xa8, 0xb4, 0x52, 0x45, 0x09, ++ 0x44, 0xec, 0xec, 0xc3, 0x17, 0xdb, 0x9a, 0x4d, ++ 0x5c, 0xa9, 0x11, 0xd4, 0x7d, 0xaf, 0x9e, 0xf1, ++ 0x2d, 0xb2, 0x66, 0xc5, 0x1d, 0xed, 0xb7, 0xcd, ++ 0x0b, 0x25, 0x5e, 0x30, 0x47, 0x3f, 0x40, 0xf4, ++ 0xa1, 0xa0, 0x00, 0x94, 0x10, 0xc5, 0x6a, 0x63, ++ 0x1a, 0xd5, 0x88, 0x92, 0x8e, 0x82, 0x39, 0x87, ++ 0x3c, 0x78, 0x65, 0x58, 0x42, 0x75, 0x5b, 0xdd, ++ 0x77, 0x3e, 0x09, 0x4e, 0x76, 0x5b, 0xe6, 0x0e, ++ 0x4d, 0x38, 0xb2, 0xc0, 0xb8, 0x95, 0x01, 0x7a, ++ 0x10, 0xe0, 0xfb, 0x07, 0xf2, 0xab, 0x2d, 0x8c, ++ 0x32, 0xed, 0x2b, 0xc0, 0x46, 0xc2, 0xf5, 0x38, ++ 0x83, 0xf0, 0x17, 0xec, 0xc1, 0x20, 0x6a, 0x9a, ++ 0x0b, 0x00, 0xa0, 0x98, 0x22, 0x50, 0x23, 0xd5, ++ 0x80, 0x6b, 0xf6, 0x1f, 0xc3, 0xcc, 0x97, 0xc9, ++ 0x24, 0x9f, 0xf3, 0xaf, 0x43, 0x14, 0xd5, 0xa0 ++}; ++static const u8 enc_assoc010[] __initconst = { ++ 0xd2, 0xa1, 0x70, 0xdb, 0x7a, 0xf8, 0xfa, 0x27, ++ 0xba, 0x73, 0x0f, 0xbf, 0x3d, 0x1e, 0x82, 0xb2 ++}; ++static const u8 enc_nonce010[] __initconst = { ++ 0xdb, 0x92, 0x0f, 0x7f, 0x17, 0x54, 0x0c, 0x30 ++}; ++static const u8 enc_key010[] __initconst = { ++ 0x47, 0x11, 0xeb, 0x86, 0x2b, 0x2c, 0xab, 0x44, ++ 0x34, 0xda, 0x7f, 0x57, 0x03, 0x39, 0x0c, 0xaf, ++ 0x2c, 0x14, 0xfd, 0x65, 0x23, 0xe9, 0x8e, 0x74, ++ 0xd5, 0x08, 0x68, 0x08, 0xe7, 0xb4, 0x72, 0xd7 ++}; ++ ++static const u8 enc_input011[] __initconst = { ++ 0x7a, 0x57, 0xf2, 0xc7, 0x06, 0x3f, 0x50, 0x7b, ++ 0x36, 0x1a, 0x66, 0x5c, 0xb9, 0x0e, 0x5e, 0x3b, ++ 0x45, 0x60, 0xbe, 0x9a, 0x31, 0x9f, 0xff, 0x5d, ++ 0x66, 0x34, 0xb4, 0xdc, 0xfb, 0x9d, 0x8e, 0xee, ++ 0x6a, 0x33, 0xa4, 0x07, 0x3c, 0xf9, 0x4c, 0x30, ++ 0xa1, 0x24, 0x52, 0xf9, 0x50, 0x46, 0x88, 0x20, ++ 0x02, 0x32, 0x3a, 0x0e, 0x99, 0x63, 0xaf, 0x1f, ++ 0x15, 0x28, 0x2a, 0x05, 0xff, 0x57, 0x59, 0x5e, ++ 0x18, 0xa1, 0x1f, 0xd0, 0x92, 0x5c, 0x88, 0x66, ++ 0x1b, 0x00, 0x64, 0xa5, 0x93, 0x8d, 0x06, 0x46, ++ 0xb0, 0x64, 0x8b, 0x8b, 0xef, 0x99, 0x05, 0x35, ++ 0x85, 0xb3, 0xf3, 0x33, 0xbb, 0xec, 0x66, 0xb6, ++ 0x3d, 0x57, 0x42, 0xe3, 0xb4, 0xc6, 0xaa, 0xb0, ++ 0x41, 0x2a, 0xb9, 0x59, 0xa9, 0xf6, 0x3e, 0x15, ++ 0x26, 0x12, 0x03, 0x21, 0x4c, 0x74, 0x43, 0x13, ++ 0x2a, 0x03, 0x27, 0x09, 0xb4, 0xfb, 0xe7, 0xb7, ++ 0x40, 0xff, 0x5e, 0xce, 0x48, 0x9a, 0x60, 0xe3, ++ 0x8b, 0x80, 0x8c, 0x38, 0x2d, 0xcb, 0x93, 0x37, ++ 0x74, 0x05, 0x52, 0x6f, 0x73, 0x3e, 0xc3, 0xbc, ++ 0xca, 0x72, 0x0a, 0xeb, 0xf1, 0x3b, 0xa0, 0x95, ++ 0xdc, 0x8a, 0xc4, 0xa9, 0xdc, 0xca, 0x44, 0xd8, ++ 0x08, 0x63, 0x6a, 0x36, 0xd3, 0x3c, 0xb8, 0xac, ++ 0x46, 0x7d, 0xfd, 0xaa, 0xeb, 0x3e, 0x0f, 0x45, ++ 0x8f, 0x49, 0xda, 0x2b, 0xf2, 0x12, 0xbd, 0xaf, ++ 0x67, 0x8a, 0x63, 0x48, 0x4b, 0x55, 0x5f, 0x6d, ++ 0x8c, 0xb9, 0x76, 0x34, 0x84, 0xae, 0xc2, 0xfc, ++ 0x52, 0x64, 0x82, 0xf7, 0xb0, 0x06, 0xf0, 0x45, ++ 0x73, 0x12, 0x50, 0x30, 0x72, 0xea, 0x78, 0x9a, ++ 0xa8, 0xaf, 0xb5, 0xe3, 0xbb, 0x77, 0x52, 0xec, ++ 0x59, 0x84, 0xbf, 0x6b, 0x8f, 0xce, 0x86, 0x5e, ++ 0x1f, 0x23, 0xe9, 0xfb, 0x08, 0x86, 0xf7, 0x10, ++ 0xb9, 0xf2, 0x44, 0x96, 0x44, 0x63, 0xa9, 0xa8, ++ 0x78, 0x00, 0x23, 0xd6, 0xc7, 0xe7, 0x6e, 0x66, ++ 0x4f, 0xcc, 0xee, 0x15, 0xb3, 0xbd, 0x1d, 0xa0, ++ 0xe5, 0x9c, 0x1b, 0x24, 0x2c, 0x4d, 0x3c, 0x62, ++ 0x35, 0x9c, 0x88, 0x59, 0x09, 0xdd, 0x82, 0x1b, ++ 0xcf, 0x0a, 0x83, 0x6b, 0x3f, 0xae, 0x03, 0xc4, ++ 0xb4, 0xdd, 0x7e, 0x5b, 0x28, 0x76, 0x25, 0x96, ++ 0xd9, 0xc9, 0x9d, 0x5f, 0x86, 0xfa, 0xf6, 0xd7, ++ 0xd2, 0xe6, 0x76, 0x1d, 0x0f, 0xa1, 0xdc, 0x74, ++ 0x05, 0x1b, 0x1d, 0xe0, 0xcd, 0x16, 0xb0, 0xa8, ++ 0x8a, 0x34, 0x7b, 0x15, 0x11, 0x77, 0xe5, 0x7b, ++ 0x7e, 0x20, 0xf7, 0xda, 0x38, 0xda, 0xce, 0x70, ++ 0xe9, 0xf5, 0x6c, 0xd9, 0xbe, 0x0c, 0x4c, 0x95, ++ 0x4c, 0xc2, 0x9b, 0x34, 0x55, 0x55, 0xe1, 0xf3, ++ 0x46, 0x8e, 0x48, 0x74, 0x14, 0x4f, 0x9d, 0xc9, ++ 0xf5, 0xe8, 0x1a, 0xf0, 0x11, 0x4a, 0xc1, 0x8d, ++ 0xe0, 0x93, 0xa0, 0xbe, 0x09, 0x1c, 0x2b, 0x4e, ++ 0x0f, 0xb2, 0x87, 0x8b, 0x84, 0xfe, 0x92, 0x32, ++ 0x14, 0xd7, 0x93, 0xdf, 0xe7, 0x44, 0xbc, 0xc5, ++ 0xae, 0x53, 0x69, 0xd8, 0xb3, 0x79, 0x37, 0x80, ++ 0xe3, 0x17, 0x5c, 0xec, 0x53, 0x00, 0x9a, 0xe3, ++ 0x8e, 0xdc, 0x38, 0xb8, 0x66, 0xf0, 0xd3, 0xad, ++ 0x1d, 0x02, 0x96, 0x86, 0x3e, 0x9d, 0x3b, 0x5d, ++ 0xa5, 0x7f, 0x21, 0x10, 0xf1, 0x1f, 0x13, 0x20, ++ 0xf9, 0x57, 0x87, 0x20, 0xf5, 0x5f, 0xf1, 0x17, ++ 0x48, 0x0a, 0x51, 0x5a, 0xcd, 0x19, 0x03, 0xa6, ++ 0x5a, 0xd1, 0x12, 0x97, 0xe9, 0x48, 0xe2, 0x1d, ++ 0x83, 0x75, 0x50, 0xd9, 0x75, 0x7d, 0x6a, 0x82, ++ 0xa1, 0xf9, 0x4e, 0x54, 0x87, 0x89, 0xc9, 0x0c, ++ 0xb7, 0x5b, 0x6a, 0x91, 0xc1, 0x9c, 0xb2, 0xa9, ++ 0xdc, 0x9a, 0xa4, 0x49, 0x0a, 0x6d, 0x0d, 0xbb, ++ 0xde, 0x86, 0x44, 0xdd, 0x5d, 0x89, 0x2b, 0x96, ++ 0x0f, 0x23, 0x95, 0xad, 0xcc, 0xa2, 0xb3, 0xb9, ++ 0x7e, 0x74, 0x38, 0xba, 0x9f, 0x73, 0xae, 0x5f, ++ 0xf8, 0x68, 0xa2, 0xe0, 0xa9, 0xce, 0xbd, 0x40, ++ 0xd4, 0x4c, 0x6b, 0xd2, 0x56, 0x62, 0xb0, 0xcc, ++ 0x63, 0x7e, 0x5b, 0xd3, 0xae, 0xd1, 0x75, 0xce, ++ 0xbb, 0xb4, 0x5b, 0xa8, 0xf8, 0xb4, 0xac, 0x71, ++ 0x75, 0xaa, 0xc9, 0x9f, 0xbb, 0x6c, 0xad, 0x0f, ++ 0x55, 0x5d, 0xe8, 0x85, 0x7d, 0xf9, 0x21, 0x35, ++ 0xea, 0x92, 0x85, 0x2b, 0x00, 0xec, 0x84, 0x90, ++ 0x0a, 0x63, 0x96, 0xe4, 0x6b, 0xa9, 0x77, 0xb8, ++ 0x91, 0xf8, 0x46, 0x15, 0x72, 0x63, 0x70, 0x01, ++ 0x40, 0xa3, 0xa5, 0x76, 0x62, 0x2b, 0xbf, 0xf1, ++ 0xe5, 0x8d, 0x9f, 0xa3, 0xfa, 0x9b, 0x03, 0xbe, ++ 0xfe, 0x65, 0x6f, 0xa2, 0x29, 0x0d, 0x54, 0xb4, ++ 0x71, 0xce, 0xa9, 0xd6, 0x3d, 0x88, 0xf9, 0xaf, ++ 0x6b, 0xa8, 0x9e, 0xf4, 0x16, 0x96, 0x36, 0xb9, ++ 0x00, 0xdc, 0x10, 0xab, 0xb5, 0x08, 0x31, 0x1f, ++ 0x00, 0xb1, 0x3c, 0xd9, 0x38, 0x3e, 0xc6, 0x04, ++ 0xa7, 0x4e, 0xe8, 0xae, 0xed, 0x98, 0xc2, 0xf7, ++ 0xb9, 0x00, 0x5f, 0x8c, 0x60, 0xd1, 0xe5, 0x15, ++ 0xf7, 0xae, 0x1e, 0x84, 0x88, 0xd1, 0xf6, 0xbc, ++ 0x3a, 0x89, 0x35, 0x22, 0x83, 0x7c, 0xca, 0xf0, ++ 0x33, 0x82, 0x4c, 0x79, 0x3c, 0xfd, 0xb1, 0xae, ++ 0x52, 0x62, 0x55, 0xd2, 0x41, 0x60, 0xc6, 0xbb, ++ 0xfa, 0x0e, 0x59, 0xd6, 0xa8, 0xfe, 0x5d, 0xed, ++ 0x47, 0x3d, 0xe0, 0xea, 0x1f, 0x6e, 0x43, 0x51, ++ 0xec, 0x10, 0x52, 0x56, 0x77, 0x42, 0x6b, 0x52, ++ 0x87, 0xd8, 0xec, 0xe0, 0xaa, 0x76, 0xa5, 0x84, ++ 0x2a, 0x22, 0x24, 0xfd, 0x92, 0x40, 0x88, 0xd5, ++ 0x85, 0x1c, 0x1f, 0x6b, 0x47, 0xa0, 0xc4, 0xe4, ++ 0xef, 0xf4, 0xea, 0xd7, 0x59, 0xac, 0x2a, 0x9e, ++ 0x8c, 0xfa, 0x1f, 0x42, 0x08, 0xfe, 0x4f, 0x74, ++ 0xa0, 0x26, 0xf5, 0xb3, 0x84, 0xf6, 0x58, 0x5f, ++ 0x26, 0x66, 0x3e, 0xd7, 0xe4, 0x22, 0x91, 0x13, ++ 0xc8, 0xac, 0x25, 0x96, 0x23, 0xd8, 0x09, 0xea, ++ 0x45, 0x75, 0x23, 0xb8, 0x5f, 0xc2, 0x90, 0x8b, ++ 0x09, 0xc4, 0xfc, 0x47, 0x6c, 0x6d, 0x0a, 0xef, ++ 0x69, 0xa4, 0x38, 0x19, 0xcf, 0x7d, 0xf9, 0x09, ++ 0x73, 0x9b, 0x60, 0x5a, 0xf7, 0x37, 0xb5, 0xfe, ++ 0x9f, 0xe3, 0x2b, 0x4c, 0x0d, 0x6e, 0x19, 0xf1, ++ 0xd6, 0xc0, 0x70, 0xf3, 0x9d, 0x22, 0x3c, 0xf9, ++ 0x49, 0xce, 0x30, 0x8e, 0x44, 0xb5, 0x76, 0x15, ++ 0x8f, 0x52, 0xfd, 0xa5, 0x04, 0xb8, 0x55, 0x6a, ++ 0x36, 0x59, 0x7c, 0xc4, 0x48, 0xb8, 0xd7, 0xab, ++ 0x05, 0x66, 0xe9, 0x5e, 0x21, 0x6f, 0x6b, 0x36, ++ 0x29, 0xbb, 0xe9, 0xe3, 0xa2, 0x9a, 0xa8, 0xcd, ++ 0x55, 0x25, 0x11, 0xba, 0x5a, 0x58, 0xa0, 0xde, ++ 0xae, 0x19, 0x2a, 0x48, 0x5a, 0xff, 0x36, 0xcd, ++ 0x6d, 0x16, 0x7a, 0x73, 0x38, 0x46, 0xe5, 0x47, ++ 0x59, 0xc8, 0xa2, 0xf6, 0xe2, 0x6c, 0x83, 0xc5, ++ 0x36, 0x2c, 0x83, 0x7d, 0xb4, 0x01, 0x05, 0x69, ++ 0xe7, 0xaf, 0x5c, 0xc4, 0x64, 0x82, 0x12, 0x21, ++ 0xef, 0xf7, 0xd1, 0x7d, 0xb8, 0x8d, 0x8c, 0x98, ++ 0x7c, 0x5f, 0x7d, 0x92, 0x88, 0xb9, 0x94, 0x07, ++ 0x9c, 0xd8, 0xe9, 0x9c, 0x17, 0x38, 0xe3, 0x57, ++ 0x6c, 0xe0, 0xdc, 0xa5, 0x92, 0x42, 0xb3, 0xbd, ++ 0x50, 0xa2, 0x7e, 0xb5, 0xb1, 0x52, 0x72, 0x03, ++ 0x97, 0xd8, 0xaa, 0x9a, 0x1e, 0x75, 0x41, 0x11, ++ 0xa3, 0x4f, 0xcc, 0xd4, 0xe3, 0x73, 0xad, 0x96, ++ 0xdc, 0x47, 0x41, 0x9f, 0xb0, 0xbe, 0x79, 0x91, ++ 0xf5, 0xb6, 0x18, 0xfe, 0xc2, 0x83, 0x18, 0x7d, ++ 0x73, 0xd9, 0x4f, 0x83, 0x84, 0x03, 0xb3, 0xf0, ++ 0x77, 0x66, 0x3d, 0x83, 0x63, 0x2e, 0x2c, 0xf9, ++ 0xdd, 0xa6, 0x1f, 0x89, 0x82, 0xb8, 0x23, 0x42, ++ 0xeb, 0xe2, 0xca, 0x70, 0x82, 0x61, 0x41, 0x0a, ++ 0x6d, 0x5f, 0x75, 0xc5, 0xe2, 0xc4, 0x91, 0x18, ++ 0x44, 0x22, 0xfa, 0x34, 0x10, 0xf5, 0x20, 0xdc, ++ 0xb7, 0xdd, 0x2a, 0x20, 0x77, 0xf5, 0xf9, 0xce, ++ 0xdb, 0xa0, 0x0a, 0x52, 0x2a, 0x4e, 0xdd, 0xcc, ++ 0x97, 0xdf, 0x05, 0xe4, 0x5e, 0xb7, 0xaa, 0xf0, ++ 0xe2, 0x80, 0xff, 0xba, 0x1a, 0x0f, 0xac, 0xdf, ++ 0x02, 0x32, 0xe6, 0xf7, 0xc7, 0x17, 0x13, 0xb7, ++ 0xfc, 0x98, 0x48, 0x8c, 0x0d, 0x82, 0xc9, 0x80, ++ 0x7a, 0xe2, 0x0a, 0xc5, 0xb4, 0xde, 0x7c, 0x3c, ++ 0x79, 0x81, 0x0e, 0x28, 0x65, 0x79, 0x67, 0x82, ++ 0x69, 0x44, 0x66, 0x09, 0xf7, 0x16, 0x1a, 0xf9, ++ 0x7d, 0x80, 0xa1, 0x79, 0x14, 0xa9, 0xc8, 0x20, ++ 0xfb, 0xa2, 0x46, 0xbe, 0x08, 0x35, 0x17, 0x58, ++ 0xc1, 0x1a, 0xda, 0x2a, 0x6b, 0x2e, 0x1e, 0xe6, ++ 0x27, 0x55, 0x7b, 0x19, 0xe2, 0xfb, 0x64, 0xfc, ++ 0x5e, 0x15, 0x54, 0x3c, 0xe7, 0xc2, 0x11, 0x50, ++ 0x30, 0xb8, 0x72, 0x03, 0x0b, 0x1a, 0x9f, 0x86, ++ 0x27, 0x11, 0x5c, 0x06, 0x2b, 0xbd, 0x75, 0x1a, ++ 0x0a, 0xda, 0x01, 0xfa, 0x5c, 0x4a, 0xc1, 0x80, ++ 0x3a, 0x6e, 0x30, 0xc8, 0x2c, 0xeb, 0x56, 0xec, ++ 0x89, 0xfa, 0x35, 0x7b, 0xb2, 0xf0, 0x97, 0x08, ++ 0x86, 0x53, 0xbe, 0xbd, 0x40, 0x41, 0x38, 0x1c, ++ 0xb4, 0x8b, 0x79, 0x2e, 0x18, 0x96, 0x94, 0xde, ++ 0xe8, 0xca, 0xe5, 0x9f, 0x92, 0x9f, 0x15, 0x5d, ++ 0x56, 0x60, 0x5c, 0x09, 0xf9, 0x16, 0xf4, 0x17, ++ 0x0f, 0xf6, 0x4c, 0xda, 0xe6, 0x67, 0x89, 0x9f, ++ 0xca, 0x6c, 0xe7, 0x9b, 0x04, 0x62, 0x0e, 0x26, ++ 0xa6, 0x52, 0xbd, 0x29, 0xff, 0xc7, 0xa4, 0x96, ++ 0xe6, 0x6a, 0x02, 0xa5, 0x2e, 0x7b, 0xfe, 0x97, ++ 0x68, 0x3e, 0x2e, 0x5f, 0x3b, 0x0f, 0x36, 0xd6, ++ 0x98, 0x19, 0x59, 0x48, 0xd2, 0xc6, 0xe1, 0x55, ++ 0x1a, 0x6e, 0xd6, 0xed, 0x2c, 0xba, 0xc3, 0x9e, ++ 0x64, 0xc9, 0x95, 0x86, 0x35, 0x5e, 0x3e, 0x88, ++ 0x69, 0x99, 0x4b, 0xee, 0xbe, 0x9a, 0x99, 0xb5, ++ 0x6e, 0x58, 0xae, 0xdd, 0x22, 0xdb, 0xdd, 0x6b, ++ 0xfc, 0xaf, 0x90, 0xa3, 0x3d, 0xa4, 0xc1, 0x15, ++ 0x92, 0x18, 0x8d, 0xd2, 0x4b, 0x7b, 0x06, 0xd1, ++ 0x37, 0xb5, 0xe2, 0x7c, 0x2c, 0xf0, 0x25, 0xe4, ++ 0x94, 0x2a, 0xbd, 0xe3, 0x82, 0x70, 0x78, 0xa3, ++ 0x82, 0x10, 0x5a, 0x90, 0xd7, 0xa4, 0xfa, 0xaf, ++ 0x1a, 0x88, 0x59, 0xdc, 0x74, 0x12, 0xb4, 0x8e, ++ 0xd7, 0x19, 0x46, 0xf4, 0x84, 0x69, 0x9f, 0xbb, ++ 0x70, 0xa8, 0x4c, 0x52, 0x81, 0xa9, 0xff, 0x76, ++ 0x1c, 0xae, 0xd8, 0x11, 0x3d, 0x7f, 0x7d, 0xc5, ++ 0x12, 0x59, 0x28, 0x18, 0xc2, 0xa2, 0xb7, 0x1c, ++ 0x88, 0xf8, 0xd6, 0x1b, 0xa6, 0x7d, 0x9e, 0xde, ++ 0x29, 0xf8, 0xed, 0xff, 0xeb, 0x92, 0x24, 0x4f, ++ 0x05, 0xaa, 0xd9, 0x49, 0xba, 0x87, 0x59, 0x51, ++ 0xc9, 0x20, 0x5c, 0x9b, 0x74, 0xcf, 0x03, 0xd9, ++ 0x2d, 0x34, 0xc7, 0x5b, 0xa5, 0x40, 0xb2, 0x99, ++ 0xf5, 0xcb, 0xb4, 0xf6, 0xb7, 0x72, 0x4a, 0xd6, ++ 0xbd, 0xb0, 0xf3, 0x93, 0xe0, 0x1b, 0xa8, 0x04, ++ 0x1e, 0x35, 0xd4, 0x80, 0x20, 0xf4, 0x9c, 0x31, ++ 0x6b, 0x45, 0xb9, 0x15, 0xb0, 0x5e, 0xdd, 0x0a, ++ 0x33, 0x9c, 0x83, 0xcd, 0x58, 0x89, 0x50, 0x56, ++ 0xbb, 0x81, 0x00, 0x91, 0x32, 0xf3, 0x1b, 0x3e, ++ 0xcf, 0x45, 0xe1, 0xf9, 0xe1, 0x2c, 0x26, 0x78, ++ 0x93, 0x9a, 0x60, 0x46, 0xc9, 0xb5, 0x5e, 0x6a, ++ 0x28, 0x92, 0x87, 0x3f, 0x63, 0x7b, 0xdb, 0xf7, ++ 0xd0, 0x13, 0x9d, 0x32, 0x40, 0x5e, 0xcf, 0xfb, ++ 0x79, 0x68, 0x47, 0x4c, 0xfd, 0x01, 0x17, 0xe6, ++ 0x97, 0x93, 0x78, 0xbb, 0xa6, 0x27, 0xa3, 0xe8, ++ 0x1a, 0xe8, 0x94, 0x55, 0x7d, 0x08, 0xe5, 0xdc, ++ 0x66, 0xa3, 0x69, 0xc8, 0xca, 0xc5, 0xa1, 0x84, ++ 0x55, 0xde, 0x08, 0x91, 0x16, 0x3a, 0x0c, 0x86, ++ 0xab, 0x27, 0x2b, 0x64, 0x34, 0x02, 0x6c, 0x76, ++ 0x8b, 0xc6, 0xaf, 0xcc, 0xe1, 0xd6, 0x8c, 0x2a, ++ 0x18, 0x3d, 0xa6, 0x1b, 0x37, 0x75, 0x45, 0x73, ++ 0xc2, 0x75, 0xd7, 0x53, 0x78, 0x3a, 0xd6, 0xe8, ++ 0x29, 0xd2, 0x4a, 0xa8, 0x1e, 0x82, 0xf6, 0xb6, ++ 0x81, 0xde, 0x21, 0xed, 0x2b, 0x56, 0xbb, 0xf2, ++ 0xd0, 0x57, 0xc1, 0x7c, 0xd2, 0x6a, 0xd2, 0x56, ++ 0xf5, 0x13, 0x5f, 0x1c, 0x6a, 0x0b, 0x74, 0xfb, ++ 0xe9, 0xfe, 0x9e, 0xea, 0x95, 0xb2, 0x46, 0xab, ++ 0x0a, 0xfc, 0xfd, 0xf3, 0xbb, 0x04, 0x2b, 0x76, ++ 0x1b, 0xa4, 0x74, 0xb0, 0xc1, 0x78, 0xc3, 0x69, ++ 0xe2, 0xb0, 0x01, 0xe1, 0xde, 0x32, 0x4c, 0x8d, ++ 0x1a, 0xb3, 0x38, 0x08, 0xd5, 0xfc, 0x1f, 0xdc, ++ 0x0e, 0x2c, 0x9c, 0xb1, 0xa1, 0x63, 0x17, 0x22, ++ 0xf5, 0x6c, 0x93, 0x70, 0x74, 0x00, 0xf8, 0x39, ++ 0x01, 0x94, 0xd1, 0x32, 0x23, 0x56, 0x5d, 0xa6, ++ 0x02, 0x76, 0x76, 0x93, 0xce, 0x2f, 0x19, 0xe9, ++ 0x17, 0x52, 0xae, 0x6e, 0x2c, 0x6d, 0x61, 0x7f, ++ 0x3b, 0xaa, 0xe0, 0x52, 0x85, 0xc5, 0x65, 0xc1, ++ 0xbb, 0x8e, 0x5b, 0x21, 0xd5, 0xc9, 0x78, 0x83, ++ 0x07, 0x97, 0x4c, 0x62, 0x61, 0x41, 0xd4, 0xfc, ++ 0xc9, 0x39, 0xe3, 0x9b, 0xd0, 0xcc, 0x75, 0xc4, ++ 0x97, 0xe6, 0xdd, 0x2a, 0x5f, 0xa6, 0xe8, 0x59, ++ 0x6c, 0x98, 0xb9, 0x02, 0xe2, 0xa2, 0xd6, 0x68, ++ 0xee, 0x3b, 0x1d, 0xe3, 0x4d, 0x5b, 0x30, 0xef, ++ 0x03, 0xf2, 0xeb, 0x18, 0x57, 0x36, 0xe8, 0xa1, ++ 0xf4, 0x47, 0xfb, 0xcb, 0x8f, 0xcb, 0xc8, 0xf3, ++ 0x4f, 0x74, 0x9d, 0x9d, 0xb1, 0x8d, 0x14, 0x44, ++ 0xd9, 0x19, 0xb4, 0x54, 0x4f, 0x75, 0x19, 0x09, ++ 0xa0, 0x75, 0xbc, 0x3b, 0x82, 0xc6, 0x3f, 0xb8, ++ 0x83, 0x19, 0x6e, 0xd6, 0x37, 0xfe, 0x6e, 0x8a, ++ 0x4e, 0xe0, 0x4a, 0xab, 0x7b, 0xc8, 0xb4, 0x1d, ++ 0xf4, 0xed, 0x27, 0x03, 0x65, 0xa2, 0xa1, 0xae, ++ 0x11, 0xe7, 0x98, 0x78, 0x48, 0x91, 0xd2, 0xd2, ++ 0xd4, 0x23, 0x78, 0x50, 0xb1, 0x5b, 0x85, 0x10, ++ 0x8d, 0xca, 0x5f, 0x0f, 0x71, 0xae, 0x72, 0x9a, ++ 0xf6, 0x25, 0x19, 0x60, 0x06, 0xf7, 0x10, 0x34, ++ 0x18, 0x0d, 0xc9, 0x9f, 0x7b, 0x0c, 0x9b, 0x8f, ++ 0x91, 0x1b, 0x9f, 0xcd, 0x10, 0xee, 0x75, 0xf9, ++ 0x97, 0x66, 0xfc, 0x4d, 0x33, 0x6e, 0x28, 0x2b, ++ 0x92, 0x85, 0x4f, 0xab, 0x43, 0x8d, 0x8f, 0x7d, ++ 0x86, 0xa7, 0xc7, 0xd8, 0xd3, 0x0b, 0x8b, 0x57, ++ 0xb6, 0x1d, 0x95, 0x0d, 0xe9, 0xbc, 0xd9, 0x03, ++ 0xd9, 0x10, 0x19, 0xc3, 0x46, 0x63, 0x55, 0x87, ++ 0x61, 0x79, 0x6c, 0x95, 0x0e, 0x9c, 0xdd, 0xca, ++ 0xc3, 0xf3, 0x64, 0xf0, 0x7d, 0x76, 0xb7, 0x53, ++ 0x67, 0x2b, 0x1e, 0x44, 0x56, 0x81, 0xea, 0x8f, ++ 0x5c, 0x42, 0x16, 0xb8, 0x28, 0xeb, 0x1b, 0x61, ++ 0x10, 0x1e, 0xbf, 0xec, 0xa8 ++}; ++static const u8 enc_output011[] __initconst = { ++ 0x6a, 0xfc, 0x4b, 0x25, 0xdf, 0xc0, 0xe4, 0xe8, ++ 0x17, 0x4d, 0x4c, 0xc9, 0x7e, 0xde, 0x3a, 0xcc, ++ 0x3c, 0xba, 0x6a, 0x77, 0x47, 0xdb, 0xe3, 0x74, ++ 0x7a, 0x4d, 0x5f, 0x8d, 0x37, 0x55, 0x80, 0x73, ++ 0x90, 0x66, 0x5d, 0x3a, 0x7d, 0x5d, 0x86, 0x5e, ++ 0x8d, 0xfd, 0x83, 0xff, 0x4e, 0x74, 0x6f, 0xf9, ++ 0xe6, 0x70, 0x17, 0x70, 0x3e, 0x96, 0xa7, 0x7e, ++ 0xcb, 0xab, 0x8f, 0x58, 0x24, 0x9b, 0x01, 0xfd, ++ 0xcb, 0xe6, 0x4d, 0x9b, 0xf0, 0x88, 0x94, 0x57, ++ 0x66, 0xef, 0x72, 0x4c, 0x42, 0x6e, 0x16, 0x19, ++ 0x15, 0xea, 0x70, 0x5b, 0xac, 0x13, 0xdb, 0x9f, ++ 0x18, 0xe2, 0x3c, 0x26, 0x97, 0xbc, 0xdc, 0x45, ++ 0x8c, 0x6c, 0x24, 0x69, 0x9c, 0xf7, 0x65, 0x1e, ++ 0x18, 0x59, 0x31, 0x7c, 0xe4, 0x73, 0xbc, 0x39, ++ 0x62, 0xc6, 0x5c, 0x9f, 0xbf, 0xfa, 0x90, 0x03, ++ 0xc9, 0x72, 0x26, 0xb6, 0x1b, 0xc2, 0xb7, 0x3f, ++ 0xf2, 0x13, 0x77, 0xf2, 0x8d, 0xb9, 0x47, 0xd0, ++ 0x53, 0xdd, 0xc8, 0x91, 0x83, 0x8b, 0xb1, 0xce, ++ 0xa3, 0xfe, 0xcd, 0xd9, 0xdd, 0x92, 0x7b, 0xdb, ++ 0xb8, 0xfb, 0xc9, 0x2d, 0x01, 0x59, 0x39, 0x52, ++ 0xad, 0x1b, 0xec, 0xcf, 0xd7, 0x70, 0x13, 0x21, ++ 0xf5, 0x47, 0xaa, 0x18, 0x21, 0x5c, 0xc9, 0x9a, ++ 0xd2, 0x6b, 0x05, 0x9c, 0x01, 0xa1, 0xda, 0x35, ++ 0x5d, 0xb3, 0x70, 0xe6, 0xa9, 0x80, 0x8b, 0x91, ++ 0xb7, 0xb3, 0x5f, 0x24, 0x9a, 0xb7, 0xd1, 0x6b, ++ 0xa1, 0x1c, 0x50, 0xba, 0x49, 0xe0, 0xee, 0x2e, ++ 0x75, 0xac, 0x69, 0xc0, 0xeb, 0x03, 0xdd, 0x19, ++ 0xe5, 0xf6, 0x06, 0xdd, 0xc3, 0xd7, 0x2b, 0x07, ++ 0x07, 0x30, 0xa7, 0x19, 0x0c, 0xbf, 0xe6, 0x18, ++ 0xcc, 0xb1, 0x01, 0x11, 0x85, 0x77, 0x1d, 0x96, ++ 0xa7, 0xa3, 0x00, 0x84, 0x02, 0xa2, 0x83, 0x68, ++ 0xda, 0x17, 0x27, 0xc8, 0x7f, 0x23, 0xb7, 0xf4, ++ 0x13, 0x85, 0xcf, 0xdd, 0x7a, 0x7d, 0x24, 0x57, ++ 0xfe, 0x05, 0x93, 0xf5, 0x74, 0xce, 0xed, 0x0c, ++ 0x20, 0x98, 0x8d, 0x92, 0x30, 0xa1, 0x29, 0x23, ++ 0x1a, 0xa0, 0x4f, 0x69, 0x56, 0x4c, 0xe1, 0xc8, ++ 0xce, 0xf6, 0x9a, 0x0c, 0xa4, 0xfa, 0x04, 0xf6, ++ 0x62, 0x95, 0xf2, 0xfa, 0xc7, 0x40, 0x68, 0x40, ++ 0x8f, 0x41, 0xda, 0xb4, 0x26, 0x6f, 0x70, 0xab, ++ 0x40, 0x61, 0xa4, 0x0e, 0x75, 0xfb, 0x86, 0xeb, ++ 0x9d, 0x9a, 0x1f, 0xec, 0x76, 0x99, 0xe7, 0xea, ++ 0xaa, 0x1e, 0x2d, 0xb5, 0xd4, 0xa6, 0x1a, 0xb8, ++ 0x61, 0x0a, 0x1d, 0x16, 0x5b, 0x98, 0xc2, 0x31, ++ 0x40, 0xe7, 0x23, 0x1d, 0x66, 0x99, 0xc8, 0xc0, ++ 0xd7, 0xce, 0xf3, 0x57, 0x40, 0x04, 0x3f, 0xfc, ++ 0xea, 0xb3, 0xfc, 0xd2, 0xd3, 0x99, 0xa4, 0x94, ++ 0x69, 0xa0, 0xef, 0xd1, 0x85, 0xb3, 0xa6, 0xb1, ++ 0x28, 0xbf, 0x94, 0x67, 0x22, 0xc3, 0x36, 0x46, ++ 0xf8, 0xd2, 0x0f, 0x5f, 0xf4, 0x59, 0x80, 0xe6, ++ 0x2d, 0x43, 0x08, 0x7d, 0x19, 0x09, 0x97, 0xa7, ++ 0x4c, 0x3d, 0x8d, 0xba, 0x65, 0x62, 0xa3, 0x71, ++ 0x33, 0x29, 0x62, 0xdb, 0xc1, 0x33, 0x34, 0x1a, ++ 0x63, 0x33, 0x16, 0xb6, 0x64, 0x7e, 0xab, 0x33, ++ 0xf0, 0xe6, 0x26, 0x68, 0xba, 0x1d, 0x2e, 0x38, ++ 0x08, 0xe6, 0x02, 0xd3, 0x25, 0x2c, 0x47, 0x23, ++ 0x58, 0x34, 0x0f, 0x9d, 0x63, 0x4f, 0x63, 0xbb, ++ 0x7f, 0x3b, 0x34, 0x38, 0xa7, 0xb5, 0x8d, 0x65, ++ 0xd9, 0x9f, 0x79, 0x55, 0x3e, 0x4d, 0xe7, 0x73, ++ 0xd8, 0xf6, 0x98, 0x97, 0x84, 0x60, 0x9c, 0xc8, ++ 0xa9, 0x3c, 0xf6, 0xdc, 0x12, 0x5c, 0xe1, 0xbb, ++ 0x0b, 0x8b, 0x98, 0x9c, 0x9d, 0x26, 0x7c, 0x4a, ++ 0xe6, 0x46, 0x36, 0x58, 0x21, 0x4a, 0xee, 0xca, ++ 0xd7, 0x3b, 0xc2, 0x6c, 0x49, 0x2f, 0xe5, 0xd5, ++ 0x03, 0x59, 0x84, 0x53, 0xcb, 0xfe, 0x92, 0x71, ++ 0x2e, 0x7c, 0x21, 0xcc, 0x99, 0x85, 0x7f, 0xb8, ++ 0x74, 0x90, 0x13, 0x42, 0x3f, 0xe0, 0x6b, 0x1d, ++ 0xf2, 0x4d, 0x54, 0xd4, 0xfc, 0x3a, 0x05, 0xe6, ++ 0x74, 0xaf, 0xa6, 0xa0, 0x2a, 0x20, 0x23, 0x5d, ++ 0x34, 0x5c, 0xd9, 0x3e, 0x4e, 0xfa, 0x93, 0xe7, ++ 0xaa, 0xe9, 0x6f, 0x08, 0x43, 0x67, 0x41, 0xc5, ++ 0xad, 0xfb, 0x31, 0x95, 0x82, 0x73, 0x32, 0xd8, ++ 0xa6, 0xa3, 0xed, 0x0e, 0x2d, 0xf6, 0x5f, 0xfd, ++ 0x80, 0xa6, 0x7a, 0xe0, 0xdf, 0x78, 0x15, 0x29, ++ 0x74, 0x33, 0xd0, 0x9e, 0x83, 0x86, 0x72, 0x22, ++ 0x57, 0x29, 0xb9, 0x9e, 0x5d, 0xd3, 0x1a, 0xb5, ++ 0x96, 0x72, 0x41, 0x3d, 0xf1, 0x64, 0x43, 0x67, ++ 0xee, 0xaa, 0x5c, 0xd3, 0x9a, 0x96, 0x13, 0x11, ++ 0x5d, 0xf3, 0x0c, 0x87, 0x82, 0x1e, 0x41, 0x9e, ++ 0xd0, 0x27, 0xd7, 0x54, 0x3b, 0x67, 0x73, 0x09, ++ 0x91, 0xe9, 0xd5, 0x36, 0xa7, 0xb5, 0x55, 0xe4, ++ 0xf3, 0x21, 0x51, 0x49, 0x22, 0x07, 0x55, 0x4f, ++ 0x44, 0x4b, 0xd2, 0x15, 0x93, 0x17, 0x2a, 0xfa, ++ 0x4d, 0x4a, 0x57, 0xdb, 0x4c, 0xa6, 0xeb, 0xec, ++ 0x53, 0x25, 0x6c, 0x21, 0xed, 0x00, 0x4c, 0x3b, ++ 0xca, 0x14, 0x57, 0xa9, 0xd6, 0x6a, 0xcd, 0x8d, ++ 0x5e, 0x74, 0xac, 0x72, 0xc1, 0x97, 0xe5, 0x1b, ++ 0x45, 0x4e, 0xda, 0xfc, 0xcc, 0x40, 0xe8, 0x48, ++ 0x88, 0x0b, 0xa3, 0xe3, 0x8d, 0x83, 0x42, 0xc3, ++ 0x23, 0xfd, 0x68, 0xb5, 0x8e, 0xf1, 0x9d, 0x63, ++ 0x77, 0xe9, 0xa3, 0x8e, 0x8c, 0x26, 0x6b, 0xbd, ++ 0x72, 0x73, 0x35, 0x0c, 0x03, 0xf8, 0x43, 0x78, ++ 0x52, 0x71, 0x15, 0x1f, 0x71, 0x5d, 0x6e, 0xed, ++ 0xb9, 0xcc, 0x86, 0x30, 0xdb, 0x2b, 0xd3, 0x82, ++ 0x88, 0x23, 0x71, 0x90, 0x53, 0x5c, 0xa9, 0x2f, ++ 0x76, 0x01, 0xb7, 0x9a, 0xfe, 0x43, 0x55, 0xa3, ++ 0x04, 0x9b, 0x0e, 0xe4, 0x59, 0xdf, 0xc9, 0xe9, ++ 0xb1, 0xea, 0x29, 0x28, 0x3c, 0x5c, 0xae, 0x72, ++ 0x84, 0xb6, 0xc6, 0xeb, 0x0c, 0x27, 0x07, 0x74, ++ 0x90, 0x0d, 0x31, 0xb0, 0x00, 0x77, 0xe9, 0x40, ++ 0x70, 0x6f, 0x68, 0xa7, 0xfd, 0x06, 0xec, 0x4b, ++ 0xc0, 0xb7, 0xac, 0xbc, 0x33, 0xb7, 0x6d, 0x0a, ++ 0xbd, 0x12, 0x1b, 0x59, 0xcb, 0xdd, 0x32, 0xf5, ++ 0x1d, 0x94, 0x57, 0x76, 0x9e, 0x0c, 0x18, 0x98, ++ 0x71, 0xd7, 0x2a, 0xdb, 0x0b, 0x7b, 0xa7, 0x71, ++ 0xb7, 0x67, 0x81, 0x23, 0x96, 0xae, 0xb9, 0x7e, ++ 0x32, 0x43, 0x92, 0x8a, 0x19, 0xa0, 0xc4, 0xd4, ++ 0x3b, 0x57, 0xf9, 0x4a, 0x2c, 0xfb, 0x51, 0x46, ++ 0xbb, 0xcb, 0x5d, 0xb3, 0xef, 0x13, 0x93, 0x6e, ++ 0x68, 0x42, 0x54, 0x57, 0xd3, 0x6a, 0x3a, 0x8f, ++ 0x9d, 0x66, 0xbf, 0xbd, 0x36, 0x23, 0xf5, 0x93, ++ 0x83, 0x7b, 0x9c, 0xc0, 0xdd, 0xc5, 0x49, 0xc0, ++ 0x64, 0xed, 0x07, 0x12, 0xb3, 0xe6, 0xe4, 0xe5, ++ 0x38, 0x95, 0x23, 0xb1, 0xa0, 0x3b, 0x1a, 0x61, ++ 0xda, 0x17, 0xac, 0xc3, 0x58, 0xdd, 0x74, 0x64, ++ 0x22, 0x11, 0xe8, 0x32, 0x1d, 0x16, 0x93, 0x85, ++ 0x99, 0xa5, 0x9c, 0x34, 0x55, 0xb1, 0xe9, 0x20, ++ 0x72, 0xc9, 0x28, 0x7b, 0x79, 0x00, 0xa1, 0xa6, ++ 0xa3, 0x27, 0x40, 0x18, 0x8a, 0x54, 0xe0, 0xcc, ++ 0xe8, 0x4e, 0x8e, 0x43, 0x96, 0xe7, 0x3f, 0xc8, ++ 0xe9, 0xb2, 0xf9, 0xc9, 0xda, 0x04, 0x71, 0x50, ++ 0x47, 0xe4, 0xaa, 0xce, 0xa2, 0x30, 0xc8, 0xe4, ++ 0xac, 0xc7, 0x0d, 0x06, 0x2e, 0xe6, 0xe8, 0x80, ++ 0x36, 0x29, 0x9e, 0x01, 0xb8, 0xc3, 0xf0, 0xa0, ++ 0x5d, 0x7a, 0xca, 0x4d, 0xa0, 0x57, 0xbd, 0x2a, ++ 0x45, 0xa7, 0x7f, 0x9c, 0x93, 0x07, 0x8f, 0x35, ++ 0x67, 0x92, 0xe3, 0xe9, 0x7f, 0xa8, 0x61, 0x43, ++ 0x9e, 0x25, 0x4f, 0x33, 0x76, 0x13, 0x6e, 0x12, ++ 0xb9, 0xdd, 0xa4, 0x7c, 0x08, 0x9f, 0x7c, 0xe7, ++ 0x0a, 0x8d, 0x84, 0x06, 0xa4, 0x33, 0x17, 0x34, ++ 0x5e, 0x10, 0x7c, 0xc0, 0xa8, 0x3d, 0x1f, 0x42, ++ 0x20, 0x51, 0x65, 0x5d, 0x09, 0xc3, 0xaa, 0xc0, ++ 0xc8, 0x0d, 0xf0, 0x79, 0xbc, 0x20, 0x1b, 0x95, ++ 0xe7, 0x06, 0x7d, 0x47, 0x20, 0x03, 0x1a, 0x74, ++ 0xdd, 0xe2, 0xd4, 0xae, 0x38, 0x71, 0x9b, 0xf5, ++ 0x80, 0xec, 0x08, 0x4e, 0x56, 0xba, 0x76, 0x12, ++ 0x1a, 0xdf, 0x48, 0xf3, 0xae, 0xb3, 0xe6, 0xe6, ++ 0xbe, 0xc0, 0x91, 0x2e, 0x01, 0xb3, 0x01, 0x86, ++ 0xa2, 0xb9, 0x52, 0xd1, 0x21, 0xae, 0xd4, 0x97, ++ 0x1d, 0xef, 0x41, 0x12, 0x95, 0x3d, 0x48, 0x45, ++ 0x1c, 0x56, 0x32, 0x8f, 0xb8, 0x43, 0xbb, 0x19, ++ 0xf3, 0xca, 0xe9, 0xeb, 0x6d, 0x84, 0xbe, 0x86, ++ 0x06, 0xe2, 0x36, 0xb2, 0x62, 0x9d, 0xd3, 0x4c, ++ 0x48, 0x18, 0x54, 0x13, 0x4e, 0xcf, 0xfd, 0xba, ++ 0x84, 0xb9, 0x30, 0x53, 0xcf, 0xfb, 0xb9, 0x29, ++ 0x8f, 0xdc, 0x9f, 0xef, 0x60, 0x0b, 0x64, 0xf6, ++ 0x8b, 0xee, 0xa6, 0x91, 0xc2, 0x41, 0x6c, 0xf6, ++ 0xfa, 0x79, 0x67, 0x4b, 0xc1, 0x3f, 0xaf, 0x09, ++ 0x81, 0xd4, 0x5d, 0xcb, 0x09, 0xdf, 0x36, 0x31, ++ 0xc0, 0x14, 0x3c, 0x7c, 0x0e, 0x65, 0x95, 0x99, ++ 0x6d, 0xa3, 0xf4, 0xd7, 0x38, 0xee, 0x1a, 0x2b, ++ 0x37, 0xe2, 0xa4, 0x3b, 0x4b, 0xd0, 0x65, 0xca, ++ 0xf8, 0xc3, 0xe8, 0x15, 0x20, 0xef, 0xf2, 0x00, ++ 0xfd, 0x01, 0x09, 0xc5, 0xc8, 0x17, 0x04, 0x93, ++ 0xd0, 0x93, 0x03, 0x55, 0xc5, 0xfe, 0x32, 0xa3, ++ 0x3e, 0x28, 0x2d, 0x3b, 0x93, 0x8a, 0xcc, 0x07, ++ 0x72, 0x80, 0x8b, 0x74, 0x16, 0x24, 0xbb, 0xda, ++ 0x94, 0x39, 0x30, 0x8f, 0xb1, 0xcd, 0x4a, 0x90, ++ 0x92, 0x7c, 0x14, 0x8f, 0x95, 0x4e, 0xac, 0x9b, ++ 0xd8, 0x8f, 0x1a, 0x87, 0xa4, 0x32, 0x27, 0x8a, ++ 0xba, 0xf7, 0x41, 0xcf, 0x84, 0x37, 0x19, 0xe6, ++ 0x06, 0xf5, 0x0e, 0xcf, 0x36, 0xf5, 0x9e, 0x6c, ++ 0xde, 0xbc, 0xff, 0x64, 0x7e, 0x4e, 0x59, 0x57, ++ 0x48, 0xfe, 0x14, 0xf7, 0x9c, 0x93, 0x5d, 0x15, ++ 0xad, 0xcc, 0x11, 0xb1, 0x17, 0x18, 0xb2, 0x7e, ++ 0xcc, 0xab, 0xe9, 0xce, 0x7d, 0x77, 0x5b, 0x51, ++ 0x1b, 0x1e, 0x20, 0xa8, 0x32, 0x06, 0x0e, 0x75, ++ 0x93, 0xac, 0xdb, 0x35, 0x37, 0x1f, 0xe9, 0x19, ++ 0x1d, 0xb4, 0x71, 0x97, 0xd6, 0x4e, 0x2c, 0x08, ++ 0xa5, 0x13, 0xf9, 0x0e, 0x7e, 0x78, 0x6e, 0x14, ++ 0xe0, 0xa9, 0xb9, 0x96, 0x4c, 0x80, 0x82, 0xba, ++ 0x17, 0xb3, 0x9d, 0x69, 0xb0, 0x84, 0x46, 0xff, ++ 0xf9, 0x52, 0x79, 0x94, 0x58, 0x3a, 0x62, 0x90, ++ 0x15, 0x35, 0x71, 0x10, 0x37, 0xed, 0xa1, 0x8e, ++ 0x53, 0x6e, 0xf4, 0x26, 0x57, 0x93, 0x15, 0x93, ++ 0xf6, 0x81, 0x2c, 0x5a, 0x10, 0xda, 0x92, 0xad, ++ 0x2f, 0xdb, 0x28, 0x31, 0x2d, 0x55, 0x04, 0xd2, ++ 0x06, 0x28, 0x8c, 0x1e, 0xdc, 0xea, 0x54, 0xac, ++ 0xff, 0xb7, 0x6c, 0x30, 0x15, 0xd4, 0xb4, 0x0d, ++ 0x00, 0x93, 0x57, 0xdd, 0xd2, 0x07, 0x07, 0x06, ++ 0xd9, 0x43, 0x9b, 0xcd, 0x3a, 0xf4, 0x7d, 0x4c, ++ 0x36, 0x5d, 0x23, 0xa2, 0xcc, 0x57, 0x40, 0x91, ++ 0xe9, 0x2c, 0x2f, 0x2c, 0xd5, 0x30, 0x9b, 0x17, ++ 0xb0, 0xc9, 0xf7, 0xa7, 0x2f, 0xd1, 0x93, 0x20, ++ 0x6b, 0xc6, 0xc1, 0xe4, 0x6f, 0xcb, 0xd1, 0xe7, ++ 0x09, 0x0f, 0x9e, 0xdc, 0xaa, 0x9f, 0x2f, 0xdf, ++ 0x56, 0x9f, 0xd4, 0x33, 0x04, 0xaf, 0xd3, 0x6c, ++ 0x58, 0x61, 0xf0, 0x30, 0xec, 0xf2, 0x7f, 0xf2, ++ 0x9c, 0xdf, 0x39, 0xbb, 0x6f, 0xa2, 0x8c, 0x7e, ++ 0xc4, 0x22, 0x51, 0x71, 0xc0, 0x4d, 0x14, 0x1a, ++ 0xc4, 0xcd, 0x04, 0xd9, 0x87, 0x08, 0x50, 0x05, ++ 0xcc, 0xaf, 0xf6, 0xf0, 0x8f, 0x92, 0x54, 0x58, ++ 0xc2, 0xc7, 0x09, 0x7a, 0x59, 0x02, 0x05, 0xe8, ++ 0xb0, 0x86, 0xd9, 0xbf, 0x7b, 0x35, 0x51, 0x4d, ++ 0xaf, 0x08, 0x97, 0x2c, 0x65, 0xda, 0x2a, 0x71, ++ 0x3a, 0xa8, 0x51, 0xcc, 0xf2, 0x73, 0x27, 0xc3, ++ 0xfd, 0x62, 0xcf, 0xe3, 0xb2, 0xca, 0xcb, 0xbe, ++ 0x1a, 0x0a, 0xa1, 0x34, 0x7b, 0x77, 0xc4, 0x62, ++ 0x68, 0x78, 0x5f, 0x94, 0x07, 0x04, 0x65, 0x16, ++ 0x4b, 0x61, 0xcb, 0xff, 0x75, 0x26, 0x50, 0x66, ++ 0x1f, 0x6e, 0x93, 0xf8, 0xc5, 0x51, 0xeb, 0xa4, ++ 0x4a, 0x48, 0x68, 0x6b, 0xe2, 0x5e, 0x44, 0xb2, ++ 0x50, 0x2c, 0x6c, 0xae, 0x79, 0x4e, 0x66, 0x35, ++ 0x81, 0x50, 0xac, 0xbc, 0x3f, 0xb1, 0x0c, 0xf3, ++ 0x05, 0x3c, 0x4a, 0xa3, 0x6c, 0x2a, 0x79, 0xb4, ++ 0xb7, 0xab, 0xca, 0xc7, 0x9b, 0x8e, 0xcd, 0x5f, ++ 0x11, 0x03, 0xcb, 0x30, 0xa3, 0xab, 0xda, 0xfe, ++ 0x64, 0xb9, 0xbb, 0xd8, 0x5e, 0x3a, 0x1a, 0x56, ++ 0xe5, 0x05, 0x48, 0x90, 0x1e, 0x61, 0x69, 0x1b, ++ 0x22, 0xe6, 0x1a, 0x3c, 0x75, 0xad, 0x1f, 0x37, ++ 0x28, 0xdc, 0xe4, 0x6d, 0xbd, 0x42, 0xdc, 0xd3, ++ 0xc8, 0xb6, 0x1c, 0x48, 0xfe, 0x94, 0x77, 0x7f, ++ 0xbd, 0x62, 0xac, 0xa3, 0x47, 0x27, 0xcf, 0x5f, ++ 0xd9, 0xdb, 0xaf, 0xec, 0xf7, 0x5e, 0xc1, 0xb0, ++ 0x9d, 0x01, 0x26, 0x99, 0x7e, 0x8f, 0x03, 0x70, ++ 0xb5, 0x42, 0xbe, 0x67, 0x28, 0x1b, 0x7c, 0xbd, ++ 0x61, 0x21, 0x97, 0xcc, 0x5c, 0xe1, 0x97, 0x8f, ++ 0x8d, 0xde, 0x2b, 0xaa, 0xa7, 0x71, 0x1d, 0x1e, ++ 0x02, 0x73, 0x70, 0x58, 0x32, 0x5b, 0x1d, 0x67, ++ 0x3d, 0xe0, 0x74, 0x4f, 0x03, 0xf2, 0x70, 0x51, ++ 0x79, 0xf1, 0x61, 0x70, 0x15, 0x74, 0x9d, 0x23, ++ 0x89, 0xde, 0xac, 0xfd, 0xde, 0xd0, 0x1f, 0xc3, ++ 0x87, 0x44, 0x35, 0x4b, 0xe5, 0xb0, 0x60, 0xc5, ++ 0x22, 0xe4, 0x9e, 0xca, 0xeb, 0xd5, 0x3a, 0x09, ++ 0x45, 0xa4, 0xdb, 0xfa, 0x3f, 0xeb, 0x1b, 0xc7, ++ 0xc8, 0x14, 0x99, 0x51, 0x92, 0x10, 0xed, 0xed, ++ 0x28, 0xe0, 0xa1, 0xf8, 0x26, 0xcf, 0xcd, 0xcb, ++ 0x63, 0xa1, 0x3b, 0xe3, 0xdf, 0x7e, 0xfe, 0xa6, ++ 0xf0, 0x81, 0x9a, 0xbf, 0x55, 0xde, 0x54, 0xd5, ++ 0x56, 0x60, 0x98, 0x10, 0x68, 0xf4, 0x38, 0x96, ++ 0x8e, 0x6f, 0x1d, 0x44, 0x7f, 0xd6, 0x2f, 0xfe, ++ 0x55, 0xfb, 0x0c, 0x7e, 0x67, 0xe2, 0x61, 0x44, ++ 0xed, 0xf2, 0x35, 0x30, 0x5d, 0xe9, 0xc7, 0xd6, ++ 0x6d, 0xe0, 0xa0, 0xed, 0xf3, 0xfc, 0xd8, 0x3e, ++ 0x0a, 0x7b, 0xcd, 0xaf, 0x65, 0x68, 0x18, 0xc0, ++ 0xec, 0x04, 0x1c, 0x74, 0x6d, 0xe2, 0x6e, 0x79, ++ 0xd4, 0x11, 0x2b, 0x62, 0xd5, 0x27, 0xad, 0x4f, ++ 0x01, 0x59, 0x73, 0xcc, 0x6a, 0x53, 0xfb, 0x2d, ++ 0xd5, 0x4e, 0x99, 0x21, 0x65, 0x4d, 0xf5, 0x82, ++ 0xf7, 0xd8, 0x42, 0xce, 0x6f, 0x3d, 0x36, 0x47, ++ 0xf1, 0x05, 0x16, 0xe8, 0x1b, 0x6a, 0x8f, 0x93, ++ 0xf2, 0x8f, 0x37, 0x40, 0x12, 0x28, 0xa3, 0xe6, ++ 0xb9, 0x17, 0x4a, 0x1f, 0xb1, 0xd1, 0x66, 0x69, ++ 0x86, 0xc4, 0xfc, 0x97, 0xae, 0x3f, 0x8f, 0x1e, ++ 0x2b, 0xdf, 0xcd, 0xf9, 0x3c ++}; ++static const u8 enc_assoc011[] __initconst = { ++ 0xd6, 0x31, 0xda, 0x5d, 0x42, 0x5e, 0xd7 ++}; ++static const u8 enc_nonce011[] __initconst = { ++ 0xfd, 0x87, 0xd4, 0xd8, 0x62, 0xfd, 0xec, 0xaa ++}; ++static const u8 enc_key011[] __initconst = { ++ 0x35, 0x4e, 0xb5, 0x70, 0x50, 0x42, 0x8a, 0x85, ++ 0xf2, 0xfb, 0xed, 0x7b, 0xd0, 0x9e, 0x97, 0xca, ++ 0xfa, 0x98, 0x66, 0x63, 0xee, 0x37, 0xcc, 0x52, ++ 0xfe, 0xd1, 0xdf, 0x95, 0x15, 0x34, 0x29, 0x38 ++}; ++ ++static const u8 enc_input012[] __initconst = { ++ 0x74, 0xa6, 0x3e, 0xe4, 0xb1, 0xcb, 0xaf, 0xb0, ++ 0x40, 0xe5, 0x0f, 0x9e, 0xf1, 0xf2, 0x89, 0xb5, ++ 0x42, 0x34, 0x8a, 0xa1, 0x03, 0xb7, 0xe9, 0x57, ++ 0x46, 0xbe, 0x20, 0xe4, 0x6e, 0xb0, 0xeb, 0xff, ++ 0xea, 0x07, 0x7e, 0xef, 0xe2, 0x55, 0x9f, 0xe5, ++ 0x78, 0x3a, 0xb7, 0x83, 0xc2, 0x18, 0x40, 0x7b, ++ 0xeb, 0xcd, 0x81, 0xfb, 0x90, 0x12, 0x9e, 0x46, ++ 0xa9, 0xd6, 0x4a, 0xba, 0xb0, 0x62, 0xdb, 0x6b, ++ 0x99, 0xc4, 0xdb, 0x54, 0x4b, 0xb8, 0xa5, 0x71, ++ 0xcb, 0xcd, 0x63, 0x32, 0x55, 0xfb, 0x31, 0xf0, ++ 0x38, 0xf5, 0xbe, 0x78, 0xe4, 0x45, 0xce, 0x1b, ++ 0x6a, 0x5b, 0x0e, 0xf4, 0x16, 0xe4, 0xb1, 0x3d, ++ 0xf6, 0x63, 0x7b, 0xa7, 0x0c, 0xde, 0x6f, 0x8f, ++ 0x74, 0xdf, 0xe0, 0x1e, 0x9d, 0xce, 0x8f, 0x24, ++ 0xef, 0x23, 0x35, 0x33, 0x7b, 0x83, 0x34, 0x23, ++ 0x58, 0x74, 0x14, 0x77, 0x1f, 0xc2, 0x4f, 0x4e, ++ 0xc6, 0x89, 0xf9, 0x52, 0x09, 0x37, 0x64, 0x14, ++ 0xc4, 0x01, 0x6b, 0x9d, 0x77, 0xe8, 0x90, 0x5d, ++ 0xa8, 0x4a, 0x2a, 0xef, 0x5c, 0x7f, 0xeb, 0xbb, ++ 0xb2, 0xc6, 0x93, 0x99, 0x66, 0xdc, 0x7f, 0xd4, ++ 0x9e, 0x2a, 0xca, 0x8d, 0xdb, 0xe7, 0x20, 0xcf, ++ 0xe4, 0x73, 0xae, 0x49, 0x7d, 0x64, 0x0f, 0x0e, ++ 0x28, 0x46, 0xa9, 0xa8, 0x32, 0xe4, 0x0e, 0xf6, ++ 0x51, 0x53, 0xb8, 0x3c, 0xb1, 0xff, 0xa3, 0x33, ++ 0x41, 0x75, 0xff, 0xf1, 0x6f, 0xf1, 0xfb, 0xbb, ++ 0x83, 0x7f, 0x06, 0x9b, 0xe7, 0x1b, 0x0a, 0xe0, ++ 0x5c, 0x33, 0x60, 0x5b, 0xdb, 0x5b, 0xed, 0xfe, ++ 0xa5, 0x16, 0x19, 0x72, 0xa3, 0x64, 0x23, 0x00, ++ 0x02, 0xc7, 0xf3, 0x6a, 0x81, 0x3e, 0x44, 0x1d, ++ 0x79, 0x15, 0x5f, 0x9a, 0xde, 0xe2, 0xfd, 0x1b, ++ 0x73, 0xc1, 0xbc, 0x23, 0xba, 0x31, 0xd2, 0x50, ++ 0xd5, 0xad, 0x7f, 0x74, 0xa7, 0xc9, 0xf8, 0x3e, ++ 0x2b, 0x26, 0x10, 0xf6, 0x03, 0x36, 0x74, 0xe4, ++ 0x0e, 0x6a, 0x72, 0xb7, 0x73, 0x0a, 0x42, 0x28, ++ 0xc2, 0xad, 0x5e, 0x03, 0xbe, 0xb8, 0x0b, 0xa8, ++ 0x5b, 0xd4, 0xb8, 0xba, 0x52, 0x89, 0xb1, 0x9b, ++ 0xc1, 0xc3, 0x65, 0x87, 0xed, 0xa5, 0xf4, 0x86, ++ 0xfd, 0x41, 0x80, 0x91, 0x27, 0x59, 0x53, 0x67, ++ 0x15, 0x78, 0x54, 0x8b, 0x2d, 0x3d, 0xc7, 0xff, ++ 0x02, 0x92, 0x07, 0x5f, 0x7a, 0x4b, 0x60, 0x59, ++ 0x3c, 0x6f, 0x5c, 0xd8, 0xec, 0x95, 0xd2, 0xfe, ++ 0xa0, 0x3b, 0xd8, 0x3f, 0xd1, 0x69, 0xa6, 0xd6, ++ 0x41, 0xb2, 0xf4, 0x4d, 0x12, 0xf4, 0x58, 0x3e, ++ 0x66, 0x64, 0x80, 0x31, 0x9b, 0xa8, 0x4c, 0x8b, ++ 0x07, 0xb2, 0xec, 0x66, 0x94, 0x66, 0x47, 0x50, ++ 0x50, 0x5f, 0x18, 0x0b, 0x0e, 0xd6, 0xc0, 0x39, ++ 0x21, 0x13, 0x9e, 0x33, 0xbc, 0x79, 0x36, 0x02, ++ 0x96, 0x70, 0xf0, 0x48, 0x67, 0x2f, 0x26, 0xe9, ++ 0x6d, 0x10, 0xbb, 0xd6, 0x3f, 0xd1, 0x64, 0x7a, ++ 0x2e, 0xbe, 0x0c, 0x61, 0xf0, 0x75, 0x42, 0x38, ++ 0x23, 0xb1, 0x9e, 0x9f, 0x7c, 0x67, 0x66, 0xd9, ++ 0x58, 0x9a, 0xf1, 0xbb, 0x41, 0x2a, 0x8d, 0x65, ++ 0x84, 0x94, 0xfc, 0xdc, 0x6a, 0x50, 0x64, 0xdb, ++ 0x56, 0x33, 0x76, 0x00, 0x10, 0xed, 0xbe, 0xd2, ++ 0x12, 0xf6, 0xf6, 0x1b, 0xa2, 0x16, 0xde, 0xae, ++ 0x31, 0x95, 0xdd, 0xb1, 0x08, 0x7e, 0x4e, 0xee, ++ 0xe7, 0xf9, 0xa5, 0xfb, 0x5b, 0x61, 0x43, 0x00, ++ 0x40, 0xf6, 0x7e, 0x02, 0x04, 0x32, 0x4e, 0x0c, ++ 0xe2, 0x66, 0x0d, 0xd7, 0x07, 0x98, 0x0e, 0xf8, ++ 0x72, 0x34, 0x6d, 0x95, 0x86, 0xd7, 0xcb, 0x31, ++ 0x54, 0x47, 0xd0, 0x38, 0x29, 0x9c, 0x5a, 0x68, ++ 0xd4, 0x87, 0x76, 0xc9, 0xe7, 0x7e, 0xe3, 0xf4, ++ 0x81, 0x6d, 0x18, 0xcb, 0xc9, 0x05, 0xaf, 0xa0, ++ 0xfb, 0x66, 0xf7, 0xf1, 0x1c, 0xc6, 0x14, 0x11, ++ 0x4f, 0x2b, 0x79, 0x42, 0x8b, 0xbc, 0xac, 0xe7, ++ 0x6c, 0xfe, 0x0f, 0x58, 0xe7, 0x7c, 0x78, 0x39, ++ 0x30, 0xb0, 0x66, 0x2c, 0x9b, 0x6d, 0x3a, 0xe1, ++ 0xcf, 0xc9, 0xa4, 0x0e, 0x6d, 0x6d, 0x8a, 0xa1, ++ 0x3a, 0xe7, 0x28, 0xd4, 0x78, 0x4c, 0xa6, 0xa2, ++ 0x2a, 0xa6, 0x03, 0x30, 0xd7, 0xa8, 0x25, 0x66, ++ 0x87, 0x2f, 0x69, 0x5c, 0x4e, 0xdd, 0xa5, 0x49, ++ 0x5d, 0x37, 0x4a, 0x59, 0xc4, 0xaf, 0x1f, 0xa2, ++ 0xe4, 0xf8, 0xa6, 0x12, 0x97, 0xd5, 0x79, 0xf5, ++ 0xe2, 0x4a, 0x2b, 0x5f, 0x61, 0xe4, 0x9e, 0xe3, ++ 0xee, 0xb8, 0xa7, 0x5b, 0x2f, 0xf4, 0x9e, 0x6c, ++ 0xfb, 0xd1, 0xc6, 0x56, 0x77, 0xba, 0x75, 0xaa, ++ 0x3d, 0x1a, 0xa8, 0x0b, 0xb3, 0x68, 0x24, 0x00, ++ 0x10, 0x7f, 0xfd, 0xd7, 0xa1, 0x8d, 0x83, 0x54, ++ 0x4f, 0x1f, 0xd8, 0x2a, 0xbe, 0x8a, 0x0c, 0x87, ++ 0xab, 0xa2, 0xde, 0xc3, 0x39, 0xbf, 0x09, 0x03, ++ 0xa5, 0xf3, 0x05, 0x28, 0xe1, 0xe1, 0xee, 0x39, ++ 0x70, 0x9c, 0xd8, 0x81, 0x12, 0x1e, 0x02, 0x40, ++ 0xd2, 0x6e, 0xf0, 0xeb, 0x1b, 0x3d, 0x22, 0xc6, ++ 0xe5, 0xe3, 0xb4, 0x5a, 0x98, 0xbb, 0xf0, 0x22, ++ 0x28, 0x8d, 0xe5, 0xd3, 0x16, 0x48, 0x24, 0xa5, ++ 0xe6, 0x66, 0x0c, 0xf9, 0x08, 0xf9, 0x7e, 0x1e, ++ 0xe1, 0x28, 0x26, 0x22, 0xc7, 0xc7, 0x0a, 0x32, ++ 0x47, 0xfa, 0xa3, 0xbe, 0x3c, 0xc4, 0xc5, 0x53, ++ 0x0a, 0xd5, 0x94, 0x4a, 0xd7, 0x93, 0xd8, 0x42, ++ 0x99, 0xb9, 0x0a, 0xdb, 0x56, 0xf7, 0xb9, 0x1c, ++ 0x53, 0x4f, 0xfa, 0xd3, 0x74, 0xad, 0xd9, 0x68, ++ 0xf1, 0x1b, 0xdf, 0x61, 0xc6, 0x5e, 0xa8, 0x48, ++ 0xfc, 0xd4, 0x4a, 0x4c, 0x3c, 0x32, 0xf7, 0x1c, ++ 0x96, 0x21, 0x9b, 0xf9, 0xa3, 0xcc, 0x5a, 0xce, ++ 0xd5, 0xd7, 0x08, 0x24, 0xf6, 0x1c, 0xfd, 0xdd, ++ 0x38, 0xc2, 0x32, 0xe9, 0xb8, 0xe7, 0xb6, 0xfa, ++ 0x9d, 0x45, 0x13, 0x2c, 0x83, 0xfd, 0x4a, 0x69, ++ 0x82, 0xcd, 0xdc, 0xb3, 0x76, 0x0c, 0x9e, 0xd8, ++ 0xf4, 0x1b, 0x45, 0x15, 0xb4, 0x97, 0xe7, 0x58, ++ 0x34, 0xe2, 0x03, 0x29, 0x5a, 0xbf, 0xb6, 0xe0, ++ 0x5d, 0x13, 0xd9, 0x2b, 0xb4, 0x80, 0xb2, 0x45, ++ 0x81, 0x6a, 0x2e, 0x6c, 0x89, 0x7d, 0xee, 0xbb, ++ 0x52, 0xdd, 0x1f, 0x18, 0xe7, 0x13, 0x6b, 0x33, ++ 0x0e, 0xea, 0x36, 0x92, 0x77, 0x7b, 0x6d, 0x9c, ++ 0x5a, 0x5f, 0x45, 0x7b, 0x7b, 0x35, 0x62, 0x23, ++ 0xd1, 0xbf, 0x0f, 0xd0, 0x08, 0x1b, 0x2b, 0x80, ++ 0x6b, 0x7e, 0xf1, 0x21, 0x47, 0xb0, 0x57, 0xd1, ++ 0x98, 0x72, 0x90, 0x34, 0x1c, 0x20, 0x04, 0xff, ++ 0x3d, 0x5c, 0xee, 0x0e, 0x57, 0x5f, 0x6f, 0x24, ++ 0x4e, 0x3c, 0xea, 0xfc, 0xa5, 0xa9, 0x83, 0xc9, ++ 0x61, 0xb4, 0x51, 0x24, 0xf8, 0x27, 0x5e, 0x46, ++ 0x8c, 0xb1, 0x53, 0x02, 0x96, 0x35, 0xba, 0xb8, ++ 0x4c, 0x71, 0xd3, 0x15, 0x59, 0x35, 0x22, 0x20, ++ 0xad, 0x03, 0x9f, 0x66, 0x44, 0x3b, 0x9c, 0x35, ++ 0x37, 0x1f, 0x9b, 0xbb, 0xf3, 0xdb, 0x35, 0x63, ++ 0x30, 0x64, 0xaa, 0xa2, 0x06, 0xa8, 0x5d, 0xbb, ++ 0xe1, 0x9f, 0x70, 0xec, 0x82, 0x11, 0x06, 0x36, ++ 0xec, 0x8b, 0x69, 0x66, 0x24, 0x44, 0xc9, 0x4a, ++ 0x57, 0xbb, 0x9b, 0x78, 0x13, 0xce, 0x9c, 0x0c, ++ 0xba, 0x92, 0x93, 0x63, 0xb8, 0xe2, 0x95, 0x0f, ++ 0x0f, 0x16, 0x39, 0x52, 0xfd, 0x3a, 0x6d, 0x02, ++ 0x4b, 0xdf, 0x13, 0xd3, 0x2a, 0x22, 0xb4, 0x03, ++ 0x7c, 0x54, 0x49, 0x96, 0x68, 0x54, 0x10, 0xfa, ++ 0xef, 0xaa, 0x6c, 0xe8, 0x22, 0xdc, 0x71, 0x16, ++ 0x13, 0x1a, 0xf6, 0x28, 0xe5, 0x6d, 0x77, 0x3d, ++ 0xcd, 0x30, 0x63, 0xb1, 0x70, 0x52, 0xa1, 0xc5, ++ 0x94, 0x5f, 0xcf, 0xe8, 0xb8, 0x26, 0x98, 0xf7, ++ 0x06, 0xa0, 0x0a, 0x70, 0xfa, 0x03, 0x80, 0xac, ++ 0xc1, 0xec, 0xd6, 0x4c, 0x54, 0xd7, 0xfe, 0x47, ++ 0xb6, 0x88, 0x4a, 0xf7, 0x71, 0x24, 0xee, 0xf3, ++ 0xd2, 0xc2, 0x4a, 0x7f, 0xfe, 0x61, 0xc7, 0x35, ++ 0xc9, 0x37, 0x67, 0xcb, 0x24, 0x35, 0xda, 0x7e, ++ 0xca, 0x5f, 0xf3, 0x8d, 0xd4, 0x13, 0x8e, 0xd6, ++ 0xcb, 0x4d, 0x53, 0x8f, 0x53, 0x1f, 0xc0, 0x74, ++ 0xf7, 0x53, 0xb9, 0x5e, 0x23, 0x37, 0xba, 0x6e, ++ 0xe3, 0x9d, 0x07, 0x55, 0x25, 0x7b, 0xe6, 0x2a, ++ 0x64, 0xd1, 0x32, 0xdd, 0x54, 0x1b, 0x4b, 0xc0, ++ 0xe1, 0xd7, 0x69, 0x58, 0xf8, 0x93, 0x29, 0xc4, ++ 0xdd, 0x23, 0x2f, 0xa5, 0xfc, 0x9d, 0x7e, 0xf8, ++ 0xd4, 0x90, 0xcd, 0x82, 0x55, 0xdc, 0x16, 0x16, ++ 0x9f, 0x07, 0x52, 0x9b, 0x9d, 0x25, 0xed, 0x32, ++ 0xc5, 0x7b, 0xdf, 0xf6, 0x83, 0x46, 0x3d, 0x65, ++ 0xb7, 0xef, 0x87, 0x7a, 0x12, 0x69, 0x8f, 0x06, ++ 0x7c, 0x51, 0x15, 0x4a, 0x08, 0xe8, 0xac, 0x9a, ++ 0x0c, 0x24, 0xa7, 0x27, 0xd8, 0x46, 0x2f, 0xe7, ++ 0x01, 0x0e, 0x1c, 0xc6, 0x91, 0xb0, 0x6e, 0x85, ++ 0x65, 0xf0, 0x29, 0x0d, 0x2e, 0x6b, 0x3b, 0xfb, ++ 0x4b, 0xdf, 0xe4, 0x80, 0x93, 0x03, 0x66, 0x46, ++ 0x3e, 0x8a, 0x6e, 0xf3, 0x5e, 0x4d, 0x62, 0x0e, ++ 0x49, 0x05, 0xaf, 0xd4, 0xf8, 0x21, 0x20, 0x61, ++ 0x1d, 0x39, 0x17, 0xf4, 0x61, 0x47, 0x95, 0xfb, ++ 0x15, 0x2e, 0xb3, 0x4f, 0xd0, 0x5d, 0xf5, 0x7d, ++ 0x40, 0xda, 0x90, 0x3c, 0x6b, 0xcb, 0x17, 0x00, ++ 0x13, 0x3b, 0x64, 0x34, 0x1b, 0xf0, 0xf2, 0xe5, ++ 0x3b, 0xb2, 0xc7, 0xd3, 0x5f, 0x3a, 0x44, 0xa6, ++ 0x9b, 0xb7, 0x78, 0x0e, 0x42, 0x5d, 0x4c, 0xc1, ++ 0xe9, 0xd2, 0xcb, 0xb7, 0x78, 0xd1, 0xfe, 0x9a, ++ 0xb5, 0x07, 0xe9, 0xe0, 0xbe, 0xe2, 0x8a, 0xa7, ++ 0x01, 0x83, 0x00, 0x8c, 0x5c, 0x08, 0xe6, 0x63, ++ 0x12, 0x92, 0xb7, 0xb7, 0xa6, 0x19, 0x7d, 0x38, ++ 0x13, 0x38, 0x92, 0x87, 0x24, 0xf9, 0x48, 0xb3, ++ 0x5e, 0x87, 0x6a, 0x40, 0x39, 0x5c, 0x3f, 0xed, ++ 0x8f, 0xee, 0xdb, 0x15, 0x82, 0x06, 0xda, 0x49, ++ 0x21, 0x2b, 0xb5, 0xbf, 0x32, 0x7c, 0x9f, 0x42, ++ 0x28, 0x63, 0xcf, 0xaf, 0x1e, 0xf8, 0xc6, 0xa0, ++ 0xd1, 0x02, 0x43, 0x57, 0x62, 0xec, 0x9b, 0x0f, ++ 0x01, 0x9e, 0x71, 0xd8, 0x87, 0x9d, 0x01, 0xc1, ++ 0x58, 0x77, 0xd9, 0xaf, 0xb1, 0x10, 0x7e, 0xdd, ++ 0xa6, 0x50, 0x96, 0xe5, 0xf0, 0x72, 0x00, 0x6d, ++ 0x4b, 0xf8, 0x2a, 0x8f, 0x19, 0xf3, 0x22, 0x88, ++ 0x11, 0x4a, 0x8b, 0x7c, 0xfd, 0xb7, 0xed, 0xe1, ++ 0xf6, 0x40, 0x39, 0xe0, 0xe9, 0xf6, 0x3d, 0x25, ++ 0xe6, 0x74, 0x3c, 0x58, 0x57, 0x7f, 0xe1, 0x22, ++ 0x96, 0x47, 0x31, 0x91, 0xba, 0x70, 0x85, 0x28, ++ 0x6b, 0x9f, 0x6e, 0x25, 0xac, 0x23, 0x66, 0x2f, ++ 0x29, 0x88, 0x28, 0xce, 0x8c, 0x5c, 0x88, 0x53, ++ 0xd1, 0x3b, 0xcc, 0x6a, 0x51, 0xb2, 0xe1, 0x28, ++ 0x3f, 0x91, 0xb4, 0x0d, 0x00, 0x3a, 0xe3, 0xf8, ++ 0xc3, 0x8f, 0xd7, 0x96, 0x62, 0x0e, 0x2e, 0xfc, ++ 0xc8, 0x6c, 0x77, 0xa6, 0x1d, 0x22, 0xc1, 0xb8, ++ 0xe6, 0x61, 0xd7, 0x67, 0x36, 0x13, 0x7b, 0xbb, ++ 0x9b, 0x59, 0x09, 0xa6, 0xdf, 0xf7, 0x6b, 0xa3, ++ 0x40, 0x1a, 0xf5, 0x4f, 0xb4, 0xda, 0xd3, 0xf3, ++ 0x81, 0x93, 0xc6, 0x18, 0xd9, 0x26, 0xee, 0xac, ++ 0xf0, 0xaa, 0xdf, 0xc5, 0x9c, 0xca, 0xc2, 0xa2, ++ 0xcc, 0x7b, 0x5c, 0x24, 0xb0, 0xbc, 0xd0, 0x6a, ++ 0x4d, 0x89, 0x09, 0xb8, 0x07, 0xfe, 0x87, 0xad, ++ 0x0a, 0xea, 0xb8, 0x42, 0xf9, 0x5e, 0xb3, 0x3e, ++ 0x36, 0x4c, 0xaf, 0x75, 0x9e, 0x1c, 0xeb, 0xbd, ++ 0xbc, 0xbb, 0x80, 0x40, 0xa7, 0x3a, 0x30, 0xbf, ++ 0xa8, 0x44, 0xf4, 0xeb, 0x38, 0xad, 0x29, 0xba, ++ 0x23, 0xed, 0x41, 0x0c, 0xea, 0xd2, 0xbb, 0x41, ++ 0x18, 0xd6, 0xb9, 0xba, 0x65, 0x2b, 0xa3, 0x91, ++ 0x6d, 0x1f, 0xa9, 0xf4, 0xd1, 0x25, 0x8d, 0x4d, ++ 0x38, 0xff, 0x64, 0xa0, 0xec, 0xde, 0xa6, 0xb6, ++ 0x79, 0xab, 0x8e, 0x33, 0x6c, 0x47, 0xde, 0xaf, ++ 0x94, 0xa4, 0xa5, 0x86, 0x77, 0x55, 0x09, 0x92, ++ 0x81, 0x31, 0x76, 0xc7, 0x34, 0x22, 0x89, 0x8e, ++ 0x3d, 0x26, 0x26, 0xd7, 0xfc, 0x1e, 0x16, 0x72, ++ 0x13, 0x33, 0x63, 0xd5, 0x22, 0xbe, 0xb8, 0x04, ++ 0x34, 0x84, 0x41, 0xbb, 0x80, 0xd0, 0x9f, 0x46, ++ 0x48, 0x07, 0xa7, 0xfc, 0x2b, 0x3a, 0x75, 0x55, ++ 0x8c, 0xc7, 0x6a, 0xbd, 0x7e, 0x46, 0x08, 0x84, ++ 0x0f, 0xd5, 0x74, 0xc0, 0x82, 0x8e, 0xaa, 0x61, ++ 0x05, 0x01, 0xb2, 0x47, 0x6e, 0x20, 0x6a, 0x2d, ++ 0x58, 0x70, 0x48, 0x32, 0xa7, 0x37, 0xd2, 0xb8, ++ 0x82, 0x1a, 0x51, 0xb9, 0x61, 0xdd, 0xfd, 0x9d, ++ 0x6b, 0x0e, 0x18, 0x97, 0xf8, 0x45, 0x5f, 0x87, ++ 0x10, 0xcf, 0x34, 0x72, 0x45, 0x26, 0x49, 0x70, ++ 0xe7, 0xa3, 0x78, 0xe0, 0x52, 0x89, 0x84, 0x94, ++ 0x83, 0x82, 0xc2, 0x69, 0x8f, 0xe3, 0xe1, 0x3f, ++ 0x60, 0x74, 0x88, 0xc4, 0xf7, 0x75, 0x2c, 0xfb, ++ 0xbd, 0xb6, 0xc4, 0x7e, 0x10, 0x0a, 0x6c, 0x90, ++ 0x04, 0x9e, 0xc3, 0x3f, 0x59, 0x7c, 0xce, 0x31, ++ 0x18, 0x60, 0x57, 0x73, 0x46, 0x94, 0x7d, 0x06, ++ 0xa0, 0x6d, 0x44, 0xec, 0xa2, 0x0a, 0x9e, 0x05, ++ 0x15, 0xef, 0xca, 0x5c, 0xbf, 0x00, 0xeb, 0xf7, ++ 0x3d, 0x32, 0xd4, 0xa5, 0xef, 0x49, 0x89, 0x5e, ++ 0x46, 0xb0, 0xa6, 0x63, 0x5b, 0x8a, 0x73, 0xae, ++ 0x6f, 0xd5, 0x9d, 0xf8, 0x4f, 0x40, 0xb5, 0xb2, ++ 0x6e, 0xd3, 0xb6, 0x01, 0xa9, 0x26, 0xa2, 0x21, ++ 0xcf, 0x33, 0x7a, 0x3a, 0xa4, 0x23, 0x13, 0xb0, ++ 0x69, 0x6a, 0xee, 0xce, 0xd8, 0x9d, 0x01, 0x1d, ++ 0x50, 0xc1, 0x30, 0x6c, 0xb1, 0xcd, 0xa0, 0xf0, ++ 0xf0, 0xa2, 0x64, 0x6f, 0xbb, 0xbf, 0x5e, 0xe6, ++ 0xab, 0x87, 0xb4, 0x0f, 0x4f, 0x15, 0xaf, 0xb5, ++ 0x25, 0xa1, 0xb2, 0xd0, 0x80, 0x2c, 0xfb, 0xf9, ++ 0xfe, 0xd2, 0x33, 0xbb, 0x76, 0xfe, 0x7c, 0xa8, ++ 0x66, 0xf7, 0xe7, 0x85, 0x9f, 0x1f, 0x85, 0x57, ++ 0x88, 0xe1, 0xe9, 0x63, 0xe4, 0xd8, 0x1c, 0xa1, ++ 0xfb, 0xda, 0x44, 0x05, 0x2e, 0x1d, 0x3a, 0x1c, ++ 0xff, 0xc8, 0x3b, 0xc0, 0xfe, 0xda, 0x22, 0x0b, ++ 0x43, 0xd6, 0x88, 0x39, 0x4c, 0x4a, 0xa6, 0x69, ++ 0x18, 0x93, 0x42, 0x4e, 0xb5, 0xcc, 0x66, 0x0d, ++ 0x09, 0xf8, 0x1e, 0x7c, 0xd3, 0x3c, 0x99, 0x0d, ++ 0x50, 0x1d, 0x62, 0xe9, 0x57, 0x06, 0xbf, 0x19, ++ 0x88, 0xdd, 0xad, 0x7b, 0x4f, 0xf9, 0xc7, 0x82, ++ 0x6d, 0x8d, 0xc8, 0xc4, 0xc5, 0x78, 0x17, 0x20, ++ 0x15, 0xc5, 0x52, 0x41, 0xcf, 0x5b, 0xd6, 0x7f, ++ 0x94, 0x02, 0x41, 0xe0, 0x40, 0x22, 0x03, 0x5e, ++ 0xd1, 0x53, 0xd4, 0x86, 0xd3, 0x2c, 0x9f, 0x0f, ++ 0x96, 0xe3, 0x6b, 0x9a, 0x76, 0x32, 0x06, 0x47, ++ 0x4b, 0x11, 0xb3, 0xdd, 0x03, 0x65, 0xbd, 0x9b, ++ 0x01, 0xda, 0x9c, 0xb9, 0x7e, 0x3f, 0x6a, 0xc4, ++ 0x7b, 0xea, 0xd4, 0x3c, 0xb9, 0xfb, 0x5c, 0x6b, ++ 0x64, 0x33, 0x52, 0xba, 0x64, 0x78, 0x8f, 0xa4, ++ 0xaf, 0x7a, 0x61, 0x8d, 0xbc, 0xc5, 0x73, 0xe9, ++ 0x6b, 0x58, 0x97, 0x4b, 0xbf, 0x63, 0x22, 0xd3, ++ 0x37, 0x02, 0x54, 0xc5, 0xb9, 0x16, 0x4a, 0xf0, ++ 0x19, 0xd8, 0x94, 0x57, 0xb8, 0x8a, 0xb3, 0x16, ++ 0x3b, 0xd0, 0x84, 0x8e, 0x67, 0xa6, 0xa3, 0x7d, ++ 0x78, 0xec, 0x00 ++}; ++static const u8 enc_output012[] __initconst = { ++ 0x52, 0x34, 0xb3, 0x65, 0x3b, 0xb7, 0xe5, 0xd3, ++ 0xab, 0x49, 0x17, 0x60, 0xd2, 0x52, 0x56, 0xdf, ++ 0xdf, 0x34, 0x56, 0x82, 0xe2, 0xbe, 0xe5, 0xe1, ++ 0x28, 0xd1, 0x4e, 0x5f, 0x4f, 0x01, 0x7d, 0x3f, ++ 0x99, 0x6b, 0x30, 0x6e, 0x1a, 0x7c, 0x4c, 0x8e, ++ 0x62, 0x81, 0xae, 0x86, 0x3f, 0x6b, 0xd0, 0xb5, ++ 0xa9, 0xcf, 0x50, 0xf1, 0x02, 0x12, 0xa0, 0x0b, ++ 0x24, 0xe9, 0xe6, 0x72, 0x89, 0x2c, 0x52, 0x1b, ++ 0x34, 0x38, 0xf8, 0x75, 0x5f, 0xa0, 0x74, 0xe2, ++ 0x99, 0xdd, 0xa6, 0x4b, 0x14, 0x50, 0x4e, 0xf1, ++ 0xbe, 0xd6, 0x9e, 0xdb, 0xb2, 0x24, 0x27, 0x74, ++ 0x12, 0x4a, 0x78, 0x78, 0x17, 0xa5, 0x58, 0x8e, ++ 0x2f, 0xf9, 0xf4, 0x8d, 0xee, 0x03, 0x88, 0xae, ++ 0xb8, 0x29, 0xa1, 0x2f, 0x4b, 0xee, 0x92, 0xbd, ++ 0x87, 0xb3, 0xce, 0x34, 0x21, 0x57, 0x46, 0x04, ++ 0x49, 0x0c, 0x80, 0xf2, 0x01, 0x13, 0xa1, 0x55, ++ 0xb3, 0xff, 0x44, 0x30, 0x3c, 0x1c, 0xd0, 0xef, ++ 0xbc, 0x18, 0x74, 0x26, 0xad, 0x41, 0x5b, 0x5b, ++ 0x3e, 0x9a, 0x7a, 0x46, 0x4f, 0x16, 0xd6, 0x74, ++ 0x5a, 0xb7, 0x3a, 0x28, 0x31, 0xd8, 0xae, 0x26, ++ 0xac, 0x50, 0x53, 0x86, 0xf2, 0x56, 0xd7, 0x3f, ++ 0x29, 0xbc, 0x45, 0x68, 0x8e, 0xcb, 0x98, 0x64, ++ 0xdd, 0xc9, 0xba, 0xb8, 0x4b, 0x7b, 0x82, 0xdd, ++ 0x14, 0xa7, 0xcb, 0x71, 0x72, 0x00, 0x5c, 0xad, ++ 0x7b, 0x6a, 0x89, 0xa4, 0x3d, 0xbf, 0xb5, 0x4b, ++ 0x3e, 0x7c, 0x5a, 0xcf, 0xb8, 0xa1, 0xc5, 0x6e, ++ 0xc8, 0xb6, 0x31, 0x57, 0x7b, 0xdf, 0xa5, 0x7e, ++ 0xb1, 0xd6, 0x42, 0x2a, 0x31, 0x36, 0xd1, 0xd0, ++ 0x3f, 0x7a, 0xe5, 0x94, 0xd6, 0x36, 0xa0, 0x6f, ++ 0xb7, 0x40, 0x7d, 0x37, 0xc6, 0x55, 0x7c, 0x50, ++ 0x40, 0x6d, 0x29, 0x89, 0xe3, 0x5a, 0xae, 0x97, ++ 0xe7, 0x44, 0x49, 0x6e, 0xbd, 0x81, 0x3d, 0x03, ++ 0x93, 0x06, 0x12, 0x06, 0xe2, 0x41, 0x12, 0x4a, ++ 0xf1, 0x6a, 0xa4, 0x58, 0xa2, 0xfb, 0xd2, 0x15, ++ 0xba, 0xc9, 0x79, 0xc9, 0xce, 0x5e, 0x13, 0xbb, ++ 0xf1, 0x09, 0x04, 0xcc, 0xfd, 0xe8, 0x51, 0x34, ++ 0x6a, 0xe8, 0x61, 0x88, 0xda, 0xed, 0x01, 0x47, ++ 0x84, 0xf5, 0x73, 0x25, 0xf9, 0x1c, 0x42, 0x86, ++ 0x07, 0xf3, 0x5b, 0x1a, 0x01, 0xb3, 0xeb, 0x24, ++ 0x32, 0x8d, 0xf6, 0xed, 0x7c, 0x4b, 0xeb, 0x3c, ++ 0x36, 0x42, 0x28, 0xdf, 0xdf, 0xb6, 0xbe, 0xd9, ++ 0x8c, 0x52, 0xd3, 0x2b, 0x08, 0x90, 0x8c, 0xe7, ++ 0x98, 0x31, 0xe2, 0x32, 0x8e, 0xfc, 0x11, 0x48, ++ 0x00, 0xa8, 0x6a, 0x42, 0x4a, 0x02, 0xc6, 0x4b, ++ 0x09, 0xf1, 0xe3, 0x49, 0xf3, 0x45, 0x1f, 0x0e, ++ 0xbc, 0x56, 0xe2, 0xe4, 0xdf, 0xfb, 0xeb, 0x61, ++ 0xfa, 0x24, 0xc1, 0x63, 0x75, 0xbb, 0x47, 0x75, ++ 0xaf, 0xe1, 0x53, 0x16, 0x96, 0x21, 0x85, 0x26, ++ 0x11, 0xb3, 0x76, 0xe3, 0x23, 0xa1, 0x6b, 0x74, ++ 0x37, 0xd0, 0xde, 0x06, 0x90, 0x71, 0x5d, 0x43, ++ 0x88, 0x9b, 0x00, 0x54, 0xa6, 0x75, 0x2f, 0xa1, ++ 0xc2, 0x0b, 0x73, 0x20, 0x1d, 0xb6, 0x21, 0x79, ++ 0x57, 0x3f, 0xfa, 0x09, 0xbe, 0x8a, 0x33, 0xc3, ++ 0x52, 0xf0, 0x1d, 0x82, 0x31, 0xd1, 0x55, 0xb5, ++ 0x6c, 0x99, 0x25, 0xcf, 0x5c, 0x32, 0xce, 0xe9, ++ 0x0d, 0xfa, 0x69, 0x2c, 0xd5, 0x0d, 0xc5, 0x6d, ++ 0x86, 0xd0, 0x0c, 0x3b, 0x06, 0x50, 0x79, 0xe8, ++ 0xc3, 0xae, 0x04, 0xe6, 0xcd, 0x51, 0xe4, 0x26, ++ 0x9b, 0x4f, 0x7e, 0xa6, 0x0f, 0xab, 0xd8, 0xe5, ++ 0xde, 0xa9, 0x00, 0x95, 0xbe, 0xa3, 0x9d, 0x5d, ++ 0xb2, 0x09, 0x70, 0x18, 0x1c, 0xf0, 0xac, 0x29, ++ 0x23, 0x02, 0x29, 0x28, 0xd2, 0x74, 0x35, 0x57, ++ 0x62, 0x0f, 0x24, 0xea, 0x5e, 0x33, 0xc2, 0x92, ++ 0xf3, 0x78, 0x4d, 0x30, 0x1e, 0xa1, 0x99, 0xa9, ++ 0x82, 0xb0, 0x42, 0x31, 0x8d, 0xad, 0x8a, 0xbc, ++ 0xfc, 0xd4, 0x57, 0x47, 0x3e, 0xb4, 0x50, 0xdd, ++ 0x6e, 0x2c, 0x80, 0x4d, 0x22, 0xf1, 0xfb, 0x57, ++ 0xc4, 0xdd, 0x17, 0xe1, 0x8a, 0x36, 0x4a, 0xb3, ++ 0x37, 0xca, 0xc9, 0x4e, 0xab, 0xd5, 0x69, 0xc4, ++ 0xf4, 0xbc, 0x0b, 0x3b, 0x44, 0x4b, 0x29, 0x9c, ++ 0xee, 0xd4, 0x35, 0x22, 0x21, 0xb0, 0x1f, 0x27, ++ 0x64, 0xa8, 0x51, 0x1b, 0xf0, 0x9f, 0x19, 0x5c, ++ 0xfb, 0x5a, 0x64, 0x74, 0x70, 0x45, 0x09, 0xf5, ++ 0x64, 0xfe, 0x1a, 0x2d, 0xc9, 0x14, 0x04, 0x14, ++ 0xcf, 0xd5, 0x7d, 0x60, 0xaf, 0x94, 0x39, 0x94, ++ 0xe2, 0x7d, 0x79, 0x82, 0xd0, 0x65, 0x3b, 0x6b, ++ 0x9c, 0x19, 0x84, 0xb4, 0x6d, 0xb3, 0x0c, 0x99, ++ 0xc0, 0x56, 0xa8, 0xbd, 0x73, 0xce, 0x05, 0x84, ++ 0x3e, 0x30, 0xaa, 0xc4, 0x9b, 0x1b, 0x04, 0x2a, ++ 0x9f, 0xd7, 0x43, 0x2b, 0x23, 0xdf, 0xbf, 0xaa, ++ 0xd5, 0xc2, 0x43, 0x2d, 0x70, 0xab, 0xdc, 0x75, ++ 0xad, 0xac, 0xf7, 0xc0, 0xbe, 0x67, 0xb2, 0x74, ++ 0xed, 0x67, 0x10, 0x4a, 0x92, 0x60, 0xc1, 0x40, ++ 0x50, 0x19, 0x8a, 0x8a, 0x8c, 0x09, 0x0e, 0x72, ++ 0xe1, 0x73, 0x5e, 0xe8, 0x41, 0x85, 0x63, 0x9f, ++ 0x3f, 0xd7, 0x7d, 0xc4, 0xfb, 0x22, 0x5d, 0x92, ++ 0x6c, 0xb3, 0x1e, 0xe2, 0x50, 0x2f, 0x82, 0xa8, ++ 0x28, 0xc0, 0xb5, 0xd7, 0x5f, 0x68, 0x0d, 0x2c, ++ 0x2d, 0xaf, 0x7e, 0xfa, 0x2e, 0x08, 0x0f, 0x1f, ++ 0x70, 0x9f, 0xe9, 0x19, 0x72, 0x55, 0xf8, 0xfb, ++ 0x51, 0xd2, 0x33, 0x5d, 0xa0, 0xd3, 0x2b, 0x0a, ++ 0x6c, 0xbc, 0x4e, 0xcf, 0x36, 0x4d, 0xdc, 0x3b, ++ 0xe9, 0x3e, 0x81, 0x7c, 0x61, 0xdb, 0x20, 0x2d, ++ 0x3a, 0xc3, 0xb3, 0x0c, 0x1e, 0x00, 0xb9, 0x7c, ++ 0xf5, 0xca, 0x10, 0x5f, 0x3a, 0x71, 0xb3, 0xe4, ++ 0x20, 0xdb, 0x0c, 0x2a, 0x98, 0x63, 0x45, 0x00, ++ 0x58, 0xf6, 0x68, 0xe4, 0x0b, 0xda, 0x13, 0x3b, ++ 0x60, 0x5c, 0x76, 0xdb, 0xb9, 0x97, 0x71, 0xe4, ++ 0xd9, 0xb7, 0xdb, 0xbd, 0x68, 0xc7, 0x84, 0x84, ++ 0xaa, 0x7c, 0x68, 0x62, 0x5e, 0x16, 0xfc, 0xba, ++ 0x72, 0xaa, 0x9a, 0xa9, 0xeb, 0x7c, 0x75, 0x47, ++ 0x97, 0x7e, 0xad, 0xe2, 0xd9, 0x91, 0xe8, 0xe4, ++ 0xa5, 0x31, 0xd7, 0x01, 0x8e, 0xa2, 0x11, 0x88, ++ 0x95, 0xb9, 0xf2, 0x9b, 0xd3, 0x7f, 0x1b, 0x81, ++ 0x22, 0xf7, 0x98, 0x60, 0x0a, 0x64, 0xa6, 0xc1, ++ 0xf6, 0x49, 0xc7, 0xe3, 0x07, 0x4d, 0x94, 0x7a, ++ 0xcf, 0x6e, 0x68, 0x0c, 0x1b, 0x3f, 0x6e, 0x2e, ++ 0xee, 0x92, 0xfa, 0x52, 0xb3, 0x59, 0xf8, 0xf1, ++ 0x8f, 0x6a, 0x66, 0xa3, 0x82, 0x76, 0x4a, 0x07, ++ 0x1a, 0xc7, 0xdd, 0xf5, 0xda, 0x9c, 0x3c, 0x24, ++ 0xbf, 0xfd, 0x42, 0xa1, 0x10, 0x64, 0x6a, 0x0f, ++ 0x89, 0xee, 0x36, 0xa5, 0xce, 0x99, 0x48, 0x6a, ++ 0xf0, 0x9f, 0x9e, 0x69, 0xa4, 0x40, 0x20, 0xe9, ++ 0x16, 0x15, 0xf7, 0xdb, 0x75, 0x02, 0xcb, 0xe9, ++ 0x73, 0x8b, 0x3b, 0x49, 0x2f, 0xf0, 0xaf, 0x51, ++ 0x06, 0x5c, 0xdf, 0x27, 0x27, 0x49, 0x6a, 0xd1, ++ 0xcc, 0xc7, 0xb5, 0x63, 0xb5, 0xfc, 0xb8, 0x5c, ++ 0x87, 0x7f, 0x84, 0xb4, 0xcc, 0x14, 0xa9, 0x53, ++ 0xda, 0xa4, 0x56, 0xf8, 0xb6, 0x1b, 0xcc, 0x40, ++ 0x27, 0x52, 0x06, 0x5a, 0x13, 0x81, 0xd7, 0x3a, ++ 0xd4, 0x3b, 0xfb, 0x49, 0x65, 0x31, 0x33, 0xb2, ++ 0xfa, 0xcd, 0xad, 0x58, 0x4e, 0x2b, 0xae, 0xd2, ++ 0x20, 0xfb, 0x1a, 0x48, 0xb4, 0x3f, 0x9a, 0xd8, ++ 0x7a, 0x35, 0x4a, 0xc8, 0xee, 0x88, 0x5e, 0x07, ++ 0x66, 0x54, 0xb9, 0xec, 0x9f, 0xa3, 0xe3, 0xb9, ++ 0x37, 0xaa, 0x49, 0x76, 0x31, 0xda, 0x74, 0x2d, ++ 0x3c, 0xa4, 0x65, 0x10, 0x32, 0x38, 0xf0, 0xde, ++ 0xd3, 0x99, 0x17, 0xaa, 0x71, 0xaa, 0x8f, 0x0f, ++ 0x8c, 0xaf, 0xa2, 0xf8, 0x5d, 0x64, 0xba, 0x1d, ++ 0xa3, 0xef, 0x96, 0x73, 0xe8, 0xa1, 0x02, 0x8d, ++ 0x0c, 0x6d, 0xb8, 0x06, 0x90, 0xb8, 0x08, 0x56, ++ 0x2c, 0xa7, 0x06, 0xc9, 0xc2, 0x38, 0xdb, 0x7c, ++ 0x63, 0xb1, 0x57, 0x8e, 0xea, 0x7c, 0x79, 0xf3, ++ 0x49, 0x1d, 0xfe, 0x9f, 0xf3, 0x6e, 0xb1, 0x1d, ++ 0xba, 0x19, 0x80, 0x1a, 0x0a, 0xd3, 0xb0, 0x26, ++ 0x21, 0x40, 0xb1, 0x7c, 0xf9, 0x4d, 0x8d, 0x10, ++ 0xc1, 0x7e, 0xf4, 0xf6, 0x3c, 0xa8, 0xfd, 0x7c, ++ 0xa3, 0x92, 0xb2, 0x0f, 0xaa, 0xcc, 0xa6, 0x11, ++ 0xfe, 0x04, 0xe3, 0xd1, 0x7a, 0x32, 0x89, 0xdf, ++ 0x0d, 0xc4, 0x8f, 0x79, 0x6b, 0xca, 0x16, 0x7c, ++ 0x6e, 0xf9, 0xad, 0x0f, 0xf6, 0xfe, 0x27, 0xdb, ++ 0xc4, 0x13, 0x70, 0xf1, 0x62, 0x1a, 0x4f, 0x79, ++ 0x40, 0xc9, 0x9b, 0x8b, 0x21, 0xea, 0x84, 0xfa, ++ 0xf5, 0xf1, 0x89, 0xce, 0xb7, 0x55, 0x0a, 0x80, ++ 0x39, 0x2f, 0x55, 0x36, 0x16, 0x9c, 0x7b, 0x08, ++ 0xbd, 0x87, 0x0d, 0xa5, 0x32, 0xf1, 0x52, 0x7c, ++ 0xe8, 0x55, 0x60, 0x5b, 0xd7, 0x69, 0xe4, 0xfc, ++ 0xfa, 0x12, 0x85, 0x96, 0xea, 0x50, 0x28, 0xab, ++ 0x8a, 0xf7, 0xbb, 0x0e, 0x53, 0x74, 0xca, 0xa6, ++ 0x27, 0x09, 0xc2, 0xb5, 0xde, 0x18, 0x14, 0xd9, ++ 0xea, 0xe5, 0x29, 0x1c, 0x40, 0x56, 0xcf, 0xd7, ++ 0xae, 0x05, 0x3f, 0x65, 0xaf, 0x05, 0x73, 0xe2, ++ 0x35, 0x96, 0x27, 0x07, 0x14, 0xc0, 0xad, 0x33, ++ 0xf1, 0xdc, 0x44, 0x7a, 0x89, 0x17, 0x77, 0xd2, ++ 0x9c, 0x58, 0x60, 0xf0, 0x3f, 0x7b, 0x2d, 0x2e, ++ 0x57, 0x95, 0x54, 0x87, 0xed, 0xf2, 0xc7, 0x4c, ++ 0xf0, 0xae, 0x56, 0x29, 0x19, 0x7d, 0x66, 0x4b, ++ 0x9b, 0x83, 0x84, 0x42, 0x3b, 0x01, 0x25, 0x66, ++ 0x8e, 0x02, 0xde, 0xb9, 0x83, 0x54, 0x19, 0xf6, ++ 0x9f, 0x79, 0x0d, 0x67, 0xc5, 0x1d, 0x7a, 0x44, ++ 0x02, 0x98, 0xa7, 0x16, 0x1c, 0x29, 0x0d, 0x74, ++ 0xff, 0x85, 0x40, 0x06, 0xef, 0x2c, 0xa9, 0xc6, ++ 0xf5, 0x53, 0x07, 0x06, 0xae, 0xe4, 0xfa, 0x5f, ++ 0xd8, 0x39, 0x4d, 0xf1, 0x9b, 0x6b, 0xd9, 0x24, ++ 0x84, 0xfe, 0x03, 0x4c, 0xb2, 0x3f, 0xdf, 0xa1, ++ 0x05, 0x9e, 0x50, 0x14, 0x5a, 0xd9, 0x1a, 0xa2, ++ 0xa7, 0xfa, 0xfa, 0x17, 0xf7, 0x78, 0xd6, 0xb5, ++ 0x92, 0x61, 0x91, 0xac, 0x36, 0xfa, 0x56, 0x0d, ++ 0x38, 0x32, 0x18, 0x85, 0x08, 0x58, 0x37, 0xf0, ++ 0x4b, 0xdb, 0x59, 0xe7, 0xa4, 0x34, 0xc0, 0x1b, ++ 0x01, 0xaf, 0x2d, 0xde, 0xa1, 0xaa, 0x5d, 0xd3, ++ 0xec, 0xe1, 0xd4, 0xf7, 0xe6, 0x54, 0x68, 0xf0, ++ 0x51, 0x97, 0xa7, 0x89, 0xea, 0x24, 0xad, 0xd3, ++ 0x6e, 0x47, 0x93, 0x8b, 0x4b, 0xb4, 0xf7, 0x1c, ++ 0x42, 0x06, 0x67, 0xe8, 0x99, 0xf6, 0xf5, 0x7b, ++ 0x85, 0xb5, 0x65, 0xb5, 0xb5, 0xd2, 0x37, 0xf5, ++ 0xf3, 0x02, 0xa6, 0x4d, 0x11, 0xa7, 0xdc, 0x51, ++ 0x09, 0x7f, 0xa0, 0xd8, 0x88, 0x1c, 0x13, 0x71, ++ 0xae, 0x9c, 0xb7, 0x7b, 0x34, 0xd6, 0x4e, 0x68, ++ 0x26, 0x83, 0x51, 0xaf, 0x1d, 0xee, 0x8b, 0xbb, ++ 0x69, 0x43, 0x2b, 0x9e, 0x8a, 0xbc, 0x02, 0x0e, ++ 0xa0, 0x1b, 0xe0, 0xa8, 0x5f, 0x6f, 0xaf, 0x1b, ++ 0x8f, 0xe7, 0x64, 0x71, 0x74, 0x11, 0x7e, 0xa8, ++ 0xd8, 0xf9, 0x97, 0x06, 0xc3, 0xb6, 0xfb, 0xfb, ++ 0xb7, 0x3d, 0x35, 0x9d, 0x3b, 0x52, 0xed, 0x54, ++ 0xca, 0xf4, 0x81, 0x01, 0x2d, 0x1b, 0xc3, 0xa7, ++ 0x00, 0x3d, 0x1a, 0x39, 0x54, 0xe1, 0xf6, 0xff, ++ 0xed, 0x6f, 0x0b, 0x5a, 0x68, 0xda, 0x58, 0xdd, ++ 0xa9, 0xcf, 0x5c, 0x4a, 0xe5, 0x09, 0x4e, 0xde, ++ 0x9d, 0xbc, 0x3e, 0xee, 0x5a, 0x00, 0x3b, 0x2c, ++ 0x87, 0x10, 0x65, 0x60, 0xdd, 0xd7, 0x56, 0xd1, ++ 0x4c, 0x64, 0x45, 0xe4, 0x21, 0xec, 0x78, 0xf8, ++ 0x25, 0x7a, 0x3e, 0x16, 0x5d, 0x09, 0x53, 0x14, ++ 0xbe, 0x4f, 0xae, 0x87, 0xd8, 0xd1, 0xaa, 0x3c, ++ 0xf6, 0x3e, 0xa4, 0x70, 0x8c, 0x5e, 0x70, 0xa4, ++ 0xb3, 0x6b, 0x66, 0x73, 0xd3, 0xbf, 0x31, 0x06, ++ 0x19, 0x62, 0x93, 0x15, 0xf2, 0x86, 0xe4, 0x52, ++ 0x7e, 0x53, 0x4c, 0x12, 0x38, 0xcc, 0x34, 0x7d, ++ 0x57, 0xf6, 0x42, 0x93, 0x8a, 0xc4, 0xee, 0x5c, ++ 0x8a, 0xe1, 0x52, 0x8f, 0x56, 0x64, 0xf6, 0xa6, ++ 0xd1, 0x91, 0x57, 0x70, 0xcd, 0x11, 0x76, 0xf5, ++ 0x59, 0x60, 0x60, 0x3c, 0xc1, 0xc3, 0x0b, 0x7f, ++ 0x58, 0x1a, 0x50, 0x91, 0xf1, 0x68, 0x8f, 0x6e, ++ 0x74, 0x74, 0xa8, 0x51, 0x0b, 0xf7, 0x7a, 0x98, ++ 0x37, 0xf2, 0x0a, 0x0e, 0xa4, 0x97, 0x04, 0xb8, ++ 0x9b, 0xfd, 0xa0, 0xea, 0xf7, 0x0d, 0xe1, 0xdb, ++ 0x03, 0xf0, 0x31, 0x29, 0xf8, 0xdd, 0x6b, 0x8b, ++ 0x5d, 0xd8, 0x59, 0xa9, 0x29, 0xcf, 0x9a, 0x79, ++ 0x89, 0x19, 0x63, 0x46, 0x09, 0x79, 0x6a, 0x11, ++ 0xda, 0x63, 0x68, 0x48, 0x77, 0x23, 0xfb, 0x7d, ++ 0x3a, 0x43, 0xcb, 0x02, 0x3b, 0x7a, 0x6d, 0x10, ++ 0x2a, 0x9e, 0xac, 0xf1, 0xd4, 0x19, 0xf8, 0x23, ++ 0x64, 0x1d, 0x2c, 0x5f, 0xf2, 0xb0, 0x5c, 0x23, ++ 0x27, 0xf7, 0x27, 0x30, 0x16, 0x37, 0xb1, 0x90, ++ 0xab, 0x38, 0xfb, 0x55, 0xcd, 0x78, 0x58, 0xd4, ++ 0x7d, 0x43, 0xf6, 0x45, 0x5e, 0x55, 0x8d, 0xb1, ++ 0x02, 0x65, 0x58, 0xb4, 0x13, 0x4b, 0x36, 0xf7, ++ 0xcc, 0xfe, 0x3d, 0x0b, 0x82, 0xe2, 0x12, 0x11, ++ 0xbb, 0xe6, 0xb8, 0x3a, 0x48, 0x71, 0xc7, 0x50, ++ 0x06, 0x16, 0x3a, 0xe6, 0x7c, 0x05, 0xc7, 0xc8, ++ 0x4d, 0x2f, 0x08, 0x6a, 0x17, 0x9a, 0x95, 0x97, ++ 0x50, 0x68, 0xdc, 0x28, 0x18, 0xc4, 0x61, 0x38, ++ 0xb9, 0xe0, 0x3e, 0x78, 0xdb, 0x29, 0xe0, 0x9f, ++ 0x52, 0xdd, 0xf8, 0x4f, 0x91, 0xc1, 0xd0, 0x33, ++ 0xa1, 0x7a, 0x8e, 0x30, 0x13, 0x82, 0x07, 0x9f, ++ 0xd3, 0x31, 0x0f, 0x23, 0xbe, 0x32, 0x5a, 0x75, ++ 0xcf, 0x96, 0xb2, 0xec, 0xb5, 0x32, 0xac, 0x21, ++ 0xd1, 0x82, 0x33, 0xd3, 0x15, 0x74, 0xbd, 0x90, ++ 0xf1, 0x2c, 0xe6, 0x5f, 0x8d, 0xe3, 0x02, 0xe8, ++ 0xe9, 0xc4, 0xca, 0x96, 0xeb, 0x0e, 0xbc, 0x91, ++ 0xf4, 0xb9, 0xea, 0xd9, 0x1b, 0x75, 0xbd, 0xe1, ++ 0xac, 0x2a, 0x05, 0x37, 0x52, 0x9b, 0x1b, 0x3f, ++ 0x5a, 0xdc, 0x21, 0xc3, 0x98, 0xbb, 0xaf, 0xa3, ++ 0xf2, 0x00, 0xbf, 0x0d, 0x30, 0x89, 0x05, 0xcc, ++ 0xa5, 0x76, 0xf5, 0x06, 0xf0, 0xc6, 0x54, 0x8a, ++ 0x5d, 0xd4, 0x1e, 0xc1, 0xf2, 0xce, 0xb0, 0x62, ++ 0xc8, 0xfc, 0x59, 0x42, 0x9a, 0x90, 0x60, 0x55, ++ 0xfe, 0x88, 0xa5, 0x8b, 0xb8, 0x33, 0x0c, 0x23, ++ 0x24, 0x0d, 0x15, 0x70, 0x37, 0x1e, 0x3d, 0xf6, ++ 0xd2, 0xea, 0x92, 0x10, 0xb2, 0xc4, 0x51, 0xac, ++ 0xf2, 0xac, 0xf3, 0x6b, 0x6c, 0xaa, 0xcf, 0x12, ++ 0xc5, 0x6c, 0x90, 0x50, 0xb5, 0x0c, 0xfc, 0x1a, ++ 0x15, 0x52, 0xe9, 0x26, 0xc6, 0x52, 0xa4, 0xe7, ++ 0x81, 0x69, 0xe1, 0xe7, 0x9e, 0x30, 0x01, 0xec, ++ 0x84, 0x89, 0xb2, 0x0d, 0x66, 0xdd, 0xce, 0x28, ++ 0x5c, 0xec, 0x98, 0x46, 0x68, 0x21, 0x9f, 0x88, ++ 0x3f, 0x1f, 0x42, 0x77, 0xce, 0xd0, 0x61, 0xd4, ++ 0x20, 0xa7, 0xff, 0x53, 0xad, 0x37, 0xd0, 0x17, ++ 0x35, 0xc9, 0xfc, 0xba, 0x0a, 0x78, 0x3f, 0xf2, ++ 0xcc, 0x86, 0x89, 0xe8, 0x4b, 0x3c, 0x48, 0x33, ++ 0x09, 0x7f, 0xc6, 0xc0, 0xdd, 0xb8, 0xfd, 0x7a, ++ 0x66, 0x66, 0x65, 0xeb, 0x47, 0xa7, 0x04, 0x28, ++ 0xa3, 0x19, 0x8e, 0xa9, 0xb1, 0x13, 0x67, 0x62, ++ 0x70, 0xcf, 0xd6 ++}; ++static const u8 enc_assoc012[] __initconst = { ++ 0xb1, 0x69, 0x83, 0x87, 0x30, 0xaa, 0x5d, 0xb8, ++ 0x77, 0xe8, 0x21, 0xff, 0x06, 0x59, 0x35, 0xce, ++ 0x75, 0xfe, 0x38, 0xef, 0xb8, 0x91, 0x43, 0x8c, ++ 0xcf, 0x70, 0xdd, 0x0a, 0x68, 0xbf, 0xd4, 0xbc, ++ 0x16, 0x76, 0x99, 0x36, 0x1e, 0x58, 0x79, 0x5e, ++ 0xd4, 0x29, 0xf7, 0x33, 0x93, 0x48, 0xdb, 0x5f, ++ 0x01, 0xae, 0x9c, 0xb6, 0xe4, 0x88, 0x6d, 0x2b, ++ 0x76, 0x75, 0xe0, 0xf3, 0x74, 0xe2, 0xc9 ++}; ++static const u8 enc_nonce012[] __initconst = { ++ 0x05, 0xa3, 0x93, 0xed, 0x30, 0xc5, 0xa2, 0x06 ++}; ++static const u8 enc_key012[] __initconst = { ++ 0xb3, 0x35, 0x50, 0x03, 0x54, 0x2e, 0x40, 0x5e, ++ 0x8f, 0x59, 0x8e, 0xc5, 0x90, 0xd5, 0x27, 0x2d, ++ 0xba, 0x29, 0x2e, 0xcb, 0x1b, 0x70, 0x44, 0x1e, ++ 0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input053[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83, ++ 0x55, 0xd3, 0x04, 0x84, 0x64, 0x43, 0xfe, 0xe8, ++ 0xdf, 0x99, 0x47, 0x03, 0x03, 0xfb, 0x3b, 0x7b, ++ 0x80, 0xe0, 0x30, 0xbe, 0xeb, 0xd3, 0x29, 0xbe ++}; ++static const u8 enc_output053[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xe6, 0xd3, 0xd7, 0x32, 0x4a, 0x1c, 0xbb, 0xa7, ++ 0x77, 0xbb, 0xb0, 0xec, 0xdd, 0xa3, 0x78, 0x07 ++}; ++static const u8 enc_assoc053[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_nonce053[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key053[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input054[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83, ++ 0x55, 0xd3, 0x04, 0x84, 0x64, 0x43, 0xfe, 0xe8, ++ 0xdf, 0x99, 0x47, 0x03, 0x03, 0xfb, 0x3b, 0x7b, ++ 0x80, 0xe0, 0x30, 0xbe, 0xeb, 0xd3, 0x29, 0xbe, ++ 0xe3, 0xbc, 0xdb, 0x5b, 0x1e, 0xde, 0xfc, 0xfe, ++ 0x8b, 0xcd, 0xa1, 0xb6, 0xa1, 0x5c, 0x8c, 0x2b, ++ 0x08, 0x69, 0xff, 0xd2, 0xec, 0x5e, 0x26, 0xe5, ++ 0x53, 0xb7, 0xb2, 0x27, 0xfe, 0x87, 0xfd, 0xbd ++}; ++static const u8 enc_output054[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x06, 0x2d, 0xe6, 0x79, 0x5f, 0x27, 0x4f, 0xd2, ++ 0xa3, 0x05, 0xd7, 0x69, 0x80, 0xbc, 0x9c, 0xce ++}; ++static const u8 enc_assoc054[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_nonce054[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key054[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input055[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83, ++ 0x55, 0xd3, 0x04, 0x84, 0x64, 0x43, 0xfe, 0xe8, ++ 0xdf, 0x99, 0x47, 0x03, 0x03, 0xfb, 0x3b, 0x7b, ++ 0x80, 0xe0, 0x30, 0xbe, 0xeb, 0xd3, 0x29, 0xbe, ++ 0xe3, 0xbc, 0xdb, 0x5b, 0x1e, 0xde, 0xfc, 0xfe, ++ 0x8b, 0xcd, 0xa1, 0xb6, 0xa1, 0x5c, 0x8c, 0x2b, ++ 0x08, 0x69, 0xff, 0xd2, 0xec, 0x5e, 0x26, 0xe5, ++ 0x53, 0xb7, 0xb2, 0x27, 0xfe, 0x87, 0xfd, 0xbd, ++ 0x7a, 0xda, 0x44, 0x42, 0x42, 0x69, 0xbf, 0xfa, ++ 0x55, 0x27, 0xf2, 0x70, 0xac, 0xf6, 0x85, 0x02, ++ 0xb7, 0x4c, 0x5a, 0xe2, 0xe6, 0x0c, 0x05, 0x80, ++ 0x98, 0x1a, 0x49, 0x38, 0x45, 0x93, 0x92, 0xc4, ++ 0x9b, 0xb2, 0xf2, 0x84, 0xb6, 0x46, 0xef, 0xc7, ++ 0xf3, 0xf0, 0xb1, 0x36, 0x1d, 0xc3, 0x48, 0xed, ++ 0x77, 0xd3, 0x0b, 0xc5, 0x76, 0x92, 0xed, 0x38, ++ 0xfb, 0xac, 0x01, 0x88, 0x38, 0x04, 0x88, 0xc7 ++}; ++static const u8 enc_output055[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xd8, 0xb4, 0x79, 0x02, 0xba, 0xae, 0xaf, 0xb3, ++ 0x42, 0x03, 0x05, 0x15, 0x29, 0xaf, 0x28, 0x2e ++}; ++static const u8 enc_assoc055[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_nonce055[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key055[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input056[] __initconst = { ++ 0xda, 0x92, 0xbf, 0x77, 0x7f, 0x6b, 0xe8, 0x7c, ++ 0xaa, 0x2c, 0xfb, 0x7b, 0x9b, 0xbc, 0x01, 0x17, ++ 0x20, 0x66, 0xb8, 0xfc, 0xfc, 0x04, 0xc4, 0x84, ++ 0x7f, 0x1f, 0xcf, 0x41, 0x14, 0x2c, 0xd6, 0x41 ++}; ++static const u8 enc_output056[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xb3, 0x89, 0x1c, 0x84, 0x9c, 0xb5, 0x2c, 0x27, ++ 0x74, 0x7e, 0xdf, 0xcf, 0x31, 0x21, 0x3b, 0xb6 ++}; ++static const u8 enc_assoc056[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce056[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key056[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input057[] __initconst = { ++ 0xda, 0x92, 0xbf, 0x77, 0x7f, 0x6b, 0xe8, 0x7c, ++ 0xaa, 0x2c, 0xfb, 0x7b, 0x9b, 0xbc, 0x01, 0x17, ++ 0x20, 0x66, 0xb8, 0xfc, 0xfc, 0x04, 0xc4, 0x84, ++ 0x7f, 0x1f, 0xcf, 0x41, 0x14, 0x2c, 0xd6, 0x41, ++ 0x1c, 0x43, 0x24, 0xa4, 0xe1, 0x21, 0x03, 0x01, ++ 0x74, 0x32, 0x5e, 0x49, 0x5e, 0xa3, 0x73, 0xd4, ++ 0xf7, 0x96, 0x00, 0x2d, 0x13, 0xa1, 0xd9, 0x1a, ++ 0xac, 0x48, 0x4d, 0xd8, 0x01, 0x78, 0x02, 0x42 ++}; ++static const u8 enc_output057[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xf0, 0xc1, 0x2d, 0x26, 0xef, 0x03, 0x02, 0x9b, ++ 0x62, 0xc0, 0x08, 0xda, 0x27, 0xc5, 0xdc, 0x68 ++}; ++static const u8 enc_assoc057[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce057[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key057[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input058[] __initconst = { ++ 0xda, 0x92, 0xbf, 0x77, 0x7f, 0x6b, 0xe8, 0x7c, ++ 0xaa, 0x2c, 0xfb, 0x7b, 0x9b, 0xbc, 0x01, 0x17, ++ 0x20, 0x66, 0xb8, 0xfc, 0xfc, 0x04, 0xc4, 0x84, ++ 0x7f, 0x1f, 0xcf, 0x41, 0x14, 0x2c, 0xd6, 0x41, ++ 0x1c, 0x43, 0x24, 0xa4, 0xe1, 0x21, 0x03, 0x01, ++ 0x74, 0x32, 0x5e, 0x49, 0x5e, 0xa3, 0x73, 0xd4, ++ 0xf7, 0x96, 0x00, 0x2d, 0x13, 0xa1, 0xd9, 0x1a, ++ 0xac, 0x48, 0x4d, 0xd8, 0x01, 0x78, 0x02, 0x42, ++ 0x85, 0x25, 0xbb, 0xbd, 0xbd, 0x96, 0x40, 0x05, ++ 0xaa, 0xd8, 0x0d, 0x8f, 0x53, 0x09, 0x7a, 0xfd, ++ 0x48, 0xb3, 0xa5, 0x1d, 0x19, 0xf3, 0xfa, 0x7f, ++ 0x67, 0xe5, 0xb6, 0xc7, 0xba, 0x6c, 0x6d, 0x3b, ++ 0x64, 0x4d, 0x0d, 0x7b, 0x49, 0xb9, 0x10, 0x38, ++ 0x0c, 0x0f, 0x4e, 0xc9, 0xe2, 0x3c, 0xb7, 0x12, ++ 0x88, 0x2c, 0xf4, 0x3a, 0x89, 0x6d, 0x12, 0xc7, ++ 0x04, 0x53, 0xfe, 0x77, 0xc7, 0xfb, 0x77, 0x38 ++}; ++static const u8 enc_output058[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xee, 0x65, 0x78, 0x30, 0x01, 0xc2, 0x56, 0x91, ++ 0xfa, 0x28, 0xd0, 0xf5, 0xf1, 0xc1, 0xd7, 0x62 ++}; ++static const u8 enc_assoc058[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce058[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key058[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input059[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x08, 0x80, 0x94, 0x17, 0x03, ++ 0x55, 0xd3, 0x04, 0x04, 0x64, 0x43, 0xfe, 0x68, ++ 0xdf, 0x99, 0x47, 0x83, 0x03, 0xfb, 0x3b, 0xfb, ++ 0x80, 0xe0, 0x30, 0x3e, 0xeb, 0xd3, 0x29, 0x3e ++}; ++static const u8 enc_output059[] __initconst = { ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x79, 0xba, 0x7a, 0x29, 0xf5, 0xa7, 0xbb, 0x75, ++ 0x79, 0x7a, 0xf8, 0x7a, 0x61, 0x01, 0x29, 0xa4 ++}; ++static const u8 enc_assoc059[] __initconst = { ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 ++}; ++static const u8 enc_nonce059[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key059[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input060[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x08, 0x80, 0x94, 0x17, 0x03, ++ 0x55, 0xd3, 0x04, 0x04, 0x64, 0x43, 0xfe, 0x68, ++ 0xdf, 0x99, 0x47, 0x83, 0x03, 0xfb, 0x3b, 0xfb, ++ 0x80, 0xe0, 0x30, 0x3e, 0xeb, 0xd3, 0x29, 0x3e, ++ 0xe3, 0xbc, 0xdb, 0xdb, 0x1e, 0xde, 0xfc, 0x7e, ++ 0x8b, 0xcd, 0xa1, 0x36, 0xa1, 0x5c, 0x8c, 0xab, ++ 0x08, 0x69, 0xff, 0x52, 0xec, 0x5e, 0x26, 0x65, ++ 0x53, 0xb7, 0xb2, 0xa7, 0xfe, 0x87, 0xfd, 0x3d ++}; ++static const u8 enc_output060[] __initconst = { ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x36, 0xb1, 0x74, 0x38, 0x19, 0xe1, 0xb9, 0xba, ++ 0x15, 0x51, 0xe8, 0xed, 0x92, 0x2a, 0x95, 0x9a ++}; ++static const u8 enc_assoc060[] __initconst = { ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 ++}; ++static const u8 enc_nonce060[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key060[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input061[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x08, 0x80, 0x94, 0x17, 0x03, ++ 0x55, 0xd3, 0x04, 0x04, 0x64, 0x43, 0xfe, 0x68, ++ 0xdf, 0x99, 0x47, 0x83, 0x03, 0xfb, 0x3b, 0xfb, ++ 0x80, 0xe0, 0x30, 0x3e, 0xeb, 0xd3, 0x29, 0x3e, ++ 0xe3, 0xbc, 0xdb, 0xdb, 0x1e, 0xde, 0xfc, 0x7e, ++ 0x8b, 0xcd, 0xa1, 0x36, 0xa1, 0x5c, 0x8c, 0xab, ++ 0x08, 0x69, 0xff, 0x52, 0xec, 0x5e, 0x26, 0x65, ++ 0x53, 0xb7, 0xb2, 0xa7, 0xfe, 0x87, 0xfd, 0x3d, ++ 0x7a, 0xda, 0x44, 0xc2, 0x42, 0x69, 0xbf, 0x7a, ++ 0x55, 0x27, 0xf2, 0xf0, 0xac, 0xf6, 0x85, 0x82, ++ 0xb7, 0x4c, 0x5a, 0x62, 0xe6, 0x0c, 0x05, 0x00, ++ 0x98, 0x1a, 0x49, 0xb8, 0x45, 0x93, 0x92, 0x44, ++ 0x9b, 0xb2, 0xf2, 0x04, 0xb6, 0x46, 0xef, 0x47, ++ 0xf3, 0xf0, 0xb1, 0xb6, 0x1d, 0xc3, 0x48, 0x6d, ++ 0x77, 0xd3, 0x0b, 0x45, 0x76, 0x92, 0xed, 0xb8, ++ 0xfb, 0xac, 0x01, 0x08, 0x38, 0x04, 0x88, 0x47 ++}; ++static const u8 enc_output061[] __initconst = { ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0xfe, 0xac, 0x49, 0x55, 0x55, 0x4e, 0x80, 0x6f, ++ 0x3a, 0x19, 0x02, 0xe2, 0x44, 0x32, 0xc0, 0x8a ++}; ++static const u8 enc_assoc061[] __initconst = { ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 ++}; ++static const u8 enc_nonce061[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key061[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input062[] __initconst = { ++ 0xda, 0x92, 0xbf, 0xf7, 0x7f, 0x6b, 0xe8, 0xfc, ++ 0xaa, 0x2c, 0xfb, 0xfb, 0x9b, 0xbc, 0x01, 0x97, ++ 0x20, 0x66, 0xb8, 0x7c, 0xfc, 0x04, 0xc4, 0x04, ++ 0x7f, 0x1f, 0xcf, 0xc1, 0x14, 0x2c, 0xd6, 0xc1 ++}; ++static const u8 enc_output062[] __initconst = { ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0x20, 0xa3, 0x79, 0x8d, 0xf1, 0x29, 0x2c, 0x59, ++ 0x72, 0xbf, 0x97, 0x41, 0xae, 0xc3, 0x8a, 0x19 ++}; ++static const u8 enc_assoc062[] __initconst = { ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f ++}; ++static const u8 enc_nonce062[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key062[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input063[] __initconst = { ++ 0xda, 0x92, 0xbf, 0xf7, 0x7f, 0x6b, 0xe8, 0xfc, ++ 0xaa, 0x2c, 0xfb, 0xfb, 0x9b, 0xbc, 0x01, 0x97, ++ 0x20, 0x66, 0xb8, 0x7c, 0xfc, 0x04, 0xc4, 0x04, ++ 0x7f, 0x1f, 0xcf, 0xc1, 0x14, 0x2c, 0xd6, 0xc1, ++ 0x1c, 0x43, 0x24, 0x24, 0xe1, 0x21, 0x03, 0x81, ++ 0x74, 0x32, 0x5e, 0xc9, 0x5e, 0xa3, 0x73, 0x54, ++ 0xf7, 0x96, 0x00, 0xad, 0x13, 0xa1, 0xd9, 0x9a, ++ 0xac, 0x48, 0x4d, 0x58, 0x01, 0x78, 0x02, 0xc2 ++}; ++static const u8 enc_output063[] __initconst = { ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xc0, 0x3d, 0x9f, 0x67, 0x35, 0x4a, 0x97, 0xb2, ++ 0xf0, 0x74, 0xf7, 0x55, 0x15, 0x57, 0xe4, 0x9c ++}; ++static const u8 enc_assoc063[] __initconst = { ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f ++}; ++static const u8 enc_nonce063[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key063[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input064[] __initconst = { ++ 0xda, 0x92, 0xbf, 0xf7, 0x7f, 0x6b, 0xe8, 0xfc, ++ 0xaa, 0x2c, 0xfb, 0xfb, 0x9b, 0xbc, 0x01, 0x97, ++ 0x20, 0x66, 0xb8, 0x7c, 0xfc, 0x04, 0xc4, 0x04, ++ 0x7f, 0x1f, 0xcf, 0xc1, 0x14, 0x2c, 0xd6, 0xc1, ++ 0x1c, 0x43, 0x24, 0x24, 0xe1, 0x21, 0x03, 0x81, ++ 0x74, 0x32, 0x5e, 0xc9, 0x5e, 0xa3, 0x73, 0x54, ++ 0xf7, 0x96, 0x00, 0xad, 0x13, 0xa1, 0xd9, 0x9a, ++ 0xac, 0x48, 0x4d, 0x58, 0x01, 0x78, 0x02, 0xc2, ++ 0x85, 0x25, 0xbb, 0x3d, 0xbd, 0x96, 0x40, 0x85, ++ 0xaa, 0xd8, 0x0d, 0x0f, 0x53, 0x09, 0x7a, 0x7d, ++ 0x48, 0xb3, 0xa5, 0x9d, 0x19, 0xf3, 0xfa, 0xff, ++ 0x67, 0xe5, 0xb6, 0x47, 0xba, 0x6c, 0x6d, 0xbb, ++ 0x64, 0x4d, 0x0d, 0xfb, 0x49, 0xb9, 0x10, 0xb8, ++ 0x0c, 0x0f, 0x4e, 0x49, 0xe2, 0x3c, 0xb7, 0x92, ++ 0x88, 0x2c, 0xf4, 0xba, 0x89, 0x6d, 0x12, 0x47, ++ 0x04, 0x53, 0xfe, 0xf7, 0xc7, 0xfb, 0x77, 0xb8 ++}; ++static const u8 enc_output064[] __initconst = { ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xc8, 0x6d, 0xa8, 0xdd, 0x65, 0x22, 0x86, 0xd5, ++ 0x02, 0x13, 0xd3, 0x28, 0xd6, 0x3e, 0x40, 0x06 ++}; ++static const u8 enc_assoc064[] __initconst = { ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f ++}; ++static const u8 enc_nonce064[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key064[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input065[] __initconst = { ++ 0x5a, 0x92, 0xbf, 0x77, 0xff, 0x6b, 0xe8, 0x7c, ++ 0x2a, 0x2c, 0xfb, 0x7b, 0x1b, 0xbc, 0x01, 0x17, ++ 0xa0, 0x66, 0xb8, 0xfc, 0x7c, 0x04, 0xc4, 0x84, ++ 0xff, 0x1f, 0xcf, 0x41, 0x94, 0x2c, 0xd6, 0x41 ++}; ++static const u8 enc_output065[] __initconst = { ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0xbe, 0xde, 0x90, 0x83, 0xce, 0xb3, 0x6d, 0xdf, ++ 0xe5, 0xfa, 0x81, 0x1f, 0x95, 0x47, 0x1c, 0x67 ++}; ++static const u8 enc_assoc065[] __initconst = { ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce065[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key065[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input066[] __initconst = { ++ 0x5a, 0x92, 0xbf, 0x77, 0xff, 0x6b, 0xe8, 0x7c, ++ 0x2a, 0x2c, 0xfb, 0x7b, 0x1b, 0xbc, 0x01, 0x17, ++ 0xa0, 0x66, 0xb8, 0xfc, 0x7c, 0x04, 0xc4, 0x84, ++ 0xff, 0x1f, 0xcf, 0x41, 0x94, 0x2c, 0xd6, 0x41, ++ 0x9c, 0x43, 0x24, 0xa4, 0x61, 0x21, 0x03, 0x01, ++ 0xf4, 0x32, 0x5e, 0x49, 0xde, 0xa3, 0x73, 0xd4, ++ 0x77, 0x96, 0x00, 0x2d, 0x93, 0xa1, 0xd9, 0x1a, ++ 0x2c, 0x48, 0x4d, 0xd8, 0x81, 0x78, 0x02, 0x42 ++}; ++static const u8 enc_output066[] __initconst = { ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x30, 0x08, 0x74, 0xbb, 0x06, 0x92, 0xb6, 0x89, ++ 0xde, 0xad, 0x9a, 0xe1, 0x5b, 0x06, 0x73, 0x90 ++}; ++static const u8 enc_assoc066[] __initconst = { ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce066[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key066[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input067[] __initconst = { ++ 0x5a, 0x92, 0xbf, 0x77, 0xff, 0x6b, 0xe8, 0x7c, ++ 0x2a, 0x2c, 0xfb, 0x7b, 0x1b, 0xbc, 0x01, 0x17, ++ 0xa0, 0x66, 0xb8, 0xfc, 0x7c, 0x04, 0xc4, 0x84, ++ 0xff, 0x1f, 0xcf, 0x41, 0x94, 0x2c, 0xd6, 0x41, ++ 0x9c, 0x43, 0x24, 0xa4, 0x61, 0x21, 0x03, 0x01, ++ 0xf4, 0x32, 0x5e, 0x49, 0xde, 0xa3, 0x73, 0xd4, ++ 0x77, 0x96, 0x00, 0x2d, 0x93, 0xa1, 0xd9, 0x1a, ++ 0x2c, 0x48, 0x4d, 0xd8, 0x81, 0x78, 0x02, 0x42, ++ 0x05, 0x25, 0xbb, 0xbd, 0x3d, 0x96, 0x40, 0x05, ++ 0x2a, 0xd8, 0x0d, 0x8f, 0xd3, 0x09, 0x7a, 0xfd, ++ 0xc8, 0xb3, 0xa5, 0x1d, 0x99, 0xf3, 0xfa, 0x7f, ++ 0xe7, 0xe5, 0xb6, 0xc7, 0x3a, 0x6c, 0x6d, 0x3b, ++ 0xe4, 0x4d, 0x0d, 0x7b, 0xc9, 0xb9, 0x10, 0x38, ++ 0x8c, 0x0f, 0x4e, 0xc9, 0x62, 0x3c, 0xb7, 0x12, ++ 0x08, 0x2c, 0xf4, 0x3a, 0x09, 0x6d, 0x12, 0xc7, ++ 0x84, 0x53, 0xfe, 0x77, 0x47, 0xfb, 0x77, 0x38 ++}; ++static const u8 enc_output067[] __initconst = { ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x99, 0xca, 0xd8, 0x5f, 0x45, 0xca, 0x40, 0x94, ++ 0x2d, 0x0d, 0x4d, 0x5e, 0x95, 0x0a, 0xde, 0x22 ++}; ++static const u8 enc_assoc067[] __initconst = { ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, ++ 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce067[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key067[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input068[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x88, 0x7f, 0x6b, 0xe8, 0x7c, ++ 0x55, 0xd3, 0x04, 0x84, 0x9b, 0xbc, 0x01, 0x17, ++ 0xdf, 0x99, 0x47, 0x03, 0xfc, 0x04, 0xc4, 0x84, ++ 0x80, 0xe0, 0x30, 0xbe, 0x14, 0x2c, 0xd6, 0x41 ++}; ++static const u8 enc_output068[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x8b, 0xbe, 0x14, 0x52, 0x72, 0xe7, 0xc2, 0xd9, ++ 0xa1, 0x89, 0x1a, 0x3a, 0xb0, 0x98, 0x3d, 0x9d ++}; ++static const u8 enc_assoc068[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce068[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key068[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input069[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x88, 0x7f, 0x6b, 0xe8, 0x7c, ++ 0x55, 0xd3, 0x04, 0x84, 0x9b, 0xbc, 0x01, 0x17, ++ 0xdf, 0x99, 0x47, 0x03, 0xfc, 0x04, 0xc4, 0x84, ++ 0x80, 0xe0, 0x30, 0xbe, 0x14, 0x2c, 0xd6, 0x41, ++ 0xe3, 0xbc, 0xdb, 0x5b, 0xe1, 0x21, 0x03, 0x01, ++ 0x8b, 0xcd, 0xa1, 0xb6, 0x5e, 0xa3, 0x73, 0xd4, ++ 0x08, 0x69, 0xff, 0xd2, 0x13, 0xa1, 0xd9, 0x1a, ++ 0x53, 0xb7, 0xb2, 0x27, 0x01, 0x78, 0x02, 0x42 ++}; ++static const u8 enc_output069[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x3b, 0x41, 0x86, 0x19, 0x13, 0xa8, 0xf6, 0xde, ++ 0x7f, 0x61, 0xe2, 0x25, 0x63, 0x1b, 0xc3, 0x82 ++}; ++static const u8 enc_assoc069[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce069[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key069[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input070[] __initconst = { ++ 0x25, 0x6d, 0x40, 0x88, 0x7f, 0x6b, 0xe8, 0x7c, ++ 0x55, 0xd3, 0x04, 0x84, 0x9b, 0xbc, 0x01, 0x17, ++ 0xdf, 0x99, 0x47, 0x03, 0xfc, 0x04, 0xc4, 0x84, ++ 0x80, 0xe0, 0x30, 0xbe, 0x14, 0x2c, 0xd6, 0x41, ++ 0xe3, 0xbc, 0xdb, 0x5b, 0xe1, 0x21, 0x03, 0x01, ++ 0x8b, 0xcd, 0xa1, 0xb6, 0x5e, 0xa3, 0x73, 0xd4, ++ 0x08, 0x69, 0xff, 0xd2, 0x13, 0xa1, 0xd9, 0x1a, ++ 0x53, 0xb7, 0xb2, 0x27, 0x01, 0x78, 0x02, 0x42, ++ 0x7a, 0xda, 0x44, 0x42, 0xbd, 0x96, 0x40, 0x05, ++ 0x55, 0x27, 0xf2, 0x70, 0x53, 0x09, 0x7a, 0xfd, ++ 0xb7, 0x4c, 0x5a, 0xe2, 0x19, 0xf3, 0xfa, 0x7f, ++ 0x98, 0x1a, 0x49, 0x38, 0xba, 0x6c, 0x6d, 0x3b, ++ 0x9b, 0xb2, 0xf2, 0x84, 0x49, 0xb9, 0x10, 0x38, ++ 0xf3, 0xf0, 0xb1, 0x36, 0xe2, 0x3c, 0xb7, 0x12, ++ 0x77, 0xd3, 0x0b, 0xc5, 0x89, 0x6d, 0x12, 0xc7, ++ 0xfb, 0xac, 0x01, 0x88, 0xc7, 0xfb, 0x77, 0x38 ++}; ++static const u8 enc_output070[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x84, 0x28, 0xbc, 0xf0, 0x23, 0xec, 0x6b, 0xf3, ++ 0x1f, 0xd9, 0xef, 0xb2, 0x03, 0xff, 0x08, 0x71 ++}; ++static const u8 enc_assoc070[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce070[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key070[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input071[] __initconst = { ++ 0xda, 0x92, 0xbf, 0x77, 0x80, 0x94, 0x17, 0x83, ++ 0xaa, 0x2c, 0xfb, 0x7b, 0x64, 0x43, 0xfe, 0xe8, ++ 0x20, 0x66, 0xb8, 0xfc, 0x03, 0xfb, 0x3b, 0x7b, ++ 0x7f, 0x1f, 0xcf, 0x41, 0xeb, 0xd3, 0x29, 0xbe ++}; ++static const u8 enc_output071[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0x13, 0x9f, 0xdf, 0x64, 0x74, 0xea, 0x24, 0xf5, ++ 0x49, 0xb0, 0x75, 0x82, 0x5f, 0x2c, 0x76, 0x20 ++}; ++static const u8 enc_assoc071[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_nonce071[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key071[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input072[] __initconst = { ++ 0xda, 0x92, 0xbf, 0x77, 0x80, 0x94, 0x17, 0x83, ++ 0xaa, 0x2c, 0xfb, 0x7b, 0x64, 0x43, 0xfe, 0xe8, ++ 0x20, 0x66, 0xb8, 0xfc, 0x03, 0xfb, 0x3b, 0x7b, ++ 0x7f, 0x1f, 0xcf, 0x41, 0xeb, 0xd3, 0x29, 0xbe, ++ 0x1c, 0x43, 0x24, 0xa4, 0x1e, 0xde, 0xfc, 0xfe, ++ 0x74, 0x32, 0x5e, 0x49, 0xa1, 0x5c, 0x8c, 0x2b, ++ 0xf7, 0x96, 0x00, 0x2d, 0xec, 0x5e, 0x26, 0xe5, ++ 0xac, 0x48, 0x4d, 0xd8, 0xfe, 0x87, 0xfd, 0xbd ++}; ++static const u8 enc_output072[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xbb, 0xad, 0x8d, 0x86, 0x3b, 0x83, 0x5a, 0x8e, ++ 0x86, 0x64, 0xfd, 0x1d, 0x45, 0x66, 0xb6, 0xb4 ++}; ++static const u8 enc_assoc072[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_nonce072[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key072[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input073[] __initconst = { ++ 0xda, 0x92, 0xbf, 0x77, 0x80, 0x94, 0x17, 0x83, ++ 0xaa, 0x2c, 0xfb, 0x7b, 0x64, 0x43, 0xfe, 0xe8, ++ 0x20, 0x66, 0xb8, 0xfc, 0x03, 0xfb, 0x3b, 0x7b, ++ 0x7f, 0x1f, 0xcf, 0x41, 0xeb, 0xd3, 0x29, 0xbe, ++ 0x1c, 0x43, 0x24, 0xa4, 0x1e, 0xde, 0xfc, 0xfe, ++ 0x74, 0x32, 0x5e, 0x49, 0xa1, 0x5c, 0x8c, 0x2b, ++ 0xf7, 0x96, 0x00, 0x2d, 0xec, 0x5e, 0x26, 0xe5, ++ 0xac, 0x48, 0x4d, 0xd8, 0xfe, 0x87, 0xfd, 0xbd, ++ 0x85, 0x25, 0xbb, 0xbd, 0x42, 0x69, 0xbf, 0xfa, ++ 0xaa, 0xd8, 0x0d, 0x8f, 0xac, 0xf6, 0x85, 0x02, ++ 0x48, 0xb3, 0xa5, 0x1d, 0xe6, 0x0c, 0x05, 0x80, ++ 0x67, 0xe5, 0xb6, 0xc7, 0x45, 0x93, 0x92, 0xc4, ++ 0x64, 0x4d, 0x0d, 0x7b, 0xb6, 0x46, 0xef, 0xc7, ++ 0x0c, 0x0f, 0x4e, 0xc9, 0x1d, 0xc3, 0x48, 0xed, ++ 0x88, 0x2c, 0xf4, 0x3a, 0x76, 0x92, 0xed, 0x38, ++ 0x04, 0x53, 0xfe, 0x77, 0x38, 0x04, 0x88, 0xc7 ++}; ++static const u8 enc_output073[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0x42, 0xf2, 0x35, 0x42, 0x97, 0x84, 0x9a, 0x51, ++ 0x1d, 0x53, 0xe5, 0x57, 0x17, 0x72, 0xf7, 0x1f ++}; ++static const u8 enc_assoc073[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_nonce073[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x32, 0x00 ++}; ++static const u8 enc_key073[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input076[] __initconst = { ++ 0x1b, 0x99, 0x6f, 0x9a, 0x3c, 0xcc, 0x67, 0x85, ++ 0xde, 0x22, 0xff, 0x5b, 0x8a, 0xdd, 0x95, 0x02, ++ 0xce, 0x03, 0xa0, 0xfa, 0xf5, 0x99, 0x2a, 0x09, ++ 0x52, 0x2c, 0xdd, 0x12, 0x06, 0xd2, 0x20, 0xb8, ++ 0xf8, 0xbd, 0x07, 0xd1, 0xf1, 0xf5, 0xa1, 0xbd, ++ 0x9a, 0x71, 0xd1, 0x1c, 0x7f, 0x57, 0x9b, 0x85, ++ 0x58, 0x18, 0xc0, 0x8d, 0x4d, 0xe0, 0x36, 0x39, ++ 0x31, 0x83, 0xb7, 0xf5, 0x90, 0xb3, 0x35, 0xae, ++ 0xd8, 0xde, 0x5b, 0x57, 0xb1, 0x3c, 0x5f, 0xed, ++ 0xe2, 0x44, 0x1c, 0x3e, 0x18, 0x4a, 0xa9, 0xd4, ++ 0x6e, 0x61, 0x59, 0x85, 0x06, 0xb3, 0xe1, 0x1c, ++ 0x43, 0xc6, 0x2c, 0xbc, 0xac, 0xec, 0xed, 0x33, ++ 0x19, 0x08, 0x75, 0xb0, 0x12, 0x21, 0x8b, 0x19, ++ 0x30, 0xfb, 0x7c, 0x38, 0xec, 0x45, 0xac, 0x11, ++ 0xc3, 0x53, 0xd0, 0xcf, 0x93, 0x8d, 0xcc, 0xb9, ++ 0xef, 0xad, 0x8f, 0xed, 0xbe, 0x46, 0xda, 0xa5 ++}; ++static const u8 enc_output076[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x4b, 0x0b, 0xda, 0x8a, 0xd0, 0x43, 0x83, 0x0d, ++ 0x83, 0x19, 0xab, 0x82, 0xc5, 0x0c, 0x76, 0x63 ++}; ++static const u8 enc_assoc076[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce076[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xb4, 0xf0 ++}; ++static const u8 enc_key076[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input077[] __initconst = { ++ 0x86, 0xcb, 0xac, 0xae, 0x4d, 0x3f, 0x74, 0xae, ++ 0x01, 0x21, 0x3e, 0x05, 0x51, 0xcc, 0x15, 0x16, ++ 0x0e, 0xa1, 0xbe, 0x84, 0x08, 0xe3, 0xd5, 0xd7, ++ 0x4f, 0x01, 0x46, 0x49, 0x95, 0xa6, 0x9e, 0x61, ++ 0x76, 0xcb, 0x9e, 0x02, 0xb2, 0x24, 0x7e, 0xd2, ++ 0x99, 0x89, 0x2f, 0x91, 0x82, 0xa4, 0x5c, 0xaf, ++ 0x4c, 0x69, 0x40, 0x56, 0x11, 0x76, 0x6e, 0xdf, ++ 0xaf, 0xdc, 0x28, 0x55, 0x19, 0xea, 0x30, 0x48, ++ 0x0c, 0x44, 0xf0, 0x5e, 0x78, 0x1e, 0xac, 0xf8, ++ 0xfc, 0xec, 0xc7, 0x09, 0x0a, 0xbb, 0x28, 0xfa, ++ 0x5f, 0xd5, 0x85, 0xac, 0x8c, 0xda, 0x7e, 0x87, ++ 0x72, 0xe5, 0x94, 0xe4, 0xce, 0x6c, 0x88, 0x32, ++ 0x81, 0x93, 0x2e, 0x0f, 0x89, 0xf8, 0x77, 0xa1, ++ 0xf0, 0x4d, 0x9c, 0x32, 0xb0, 0x6c, 0xf9, 0x0b, ++ 0x0e, 0x76, 0x2b, 0x43, 0x0c, 0x4d, 0x51, 0x7c, ++ 0x97, 0x10, 0x70, 0x68, 0xf4, 0x98, 0xef, 0x7f ++}; ++static const u8 enc_output077[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x4b, 0xc9, 0x8f, 0x72, 0xc4, 0x94, 0xc2, 0xa4, ++ 0x3c, 0x2b, 0x15, 0xa1, 0x04, 0x3f, 0x1c, 0xfa ++}; ++static const u8 enc_assoc077[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce077[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xfb, 0x66 ++}; ++static const u8 enc_key077[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input078[] __initconst = { ++ 0xfa, 0xb1, 0xcd, 0xdf, 0x4f, 0xe1, 0x98, 0xef, ++ 0x63, 0xad, 0xd8, 0x81, 0xd6, 0xea, 0xd6, 0xc5, ++ 0x76, 0x37, 0xbb, 0xe9, 0x20, 0x18, 0xca, 0x7c, ++ 0x0b, 0x96, 0xfb, 0xa0, 0x87, 0x1e, 0x93, 0x2d, ++ 0xb1, 0xfb, 0xf9, 0x07, 0x61, 0xbe, 0x25, 0xdf, ++ 0x8d, 0xfa, 0xf9, 0x31, 0xce, 0x57, 0x57, 0xe6, ++ 0x17, 0xb3, 0xd7, 0xa9, 0xf0, 0xbf, 0x0f, 0xfe, ++ 0x5d, 0x59, 0x1a, 0x33, 0xc1, 0x43, 0xb8, 0xf5, ++ 0x3f, 0xd0, 0xb5, 0xa1, 0x96, 0x09, 0xfd, 0x62, ++ 0xe5, 0xc2, 0x51, 0xa4, 0x28, 0x1a, 0x20, 0x0c, ++ 0xfd, 0xc3, 0x4f, 0x28, 0x17, 0x10, 0x40, 0x6f, ++ 0x4e, 0x37, 0x62, 0x54, 0x46, 0xff, 0x6e, 0xf2, ++ 0x24, 0x91, 0x3d, 0xeb, 0x0d, 0x89, 0xaf, 0x33, ++ 0x71, 0x28, 0xe3, 0xd1, 0x55, 0xd1, 0x6d, 0x3e, ++ 0xc3, 0x24, 0x60, 0x41, 0x43, 0x21, 0x43, 0xe9, ++ 0xab, 0x3a, 0x6d, 0x2c, 0xcc, 0x2f, 0x4d, 0x62 ++}; ++static const u8 enc_output078[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xf7, 0xe9, 0xe1, 0x51, 0xb0, 0x25, 0x33, 0xc7, ++ 0x46, 0x58, 0xbf, 0xc7, 0x73, 0x7c, 0x68, 0x0d ++}; ++static const u8 enc_assoc078[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce078[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xbb, 0x90 ++}; ++static const u8 enc_key078[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input079[] __initconst = { ++ 0x22, 0x72, 0x02, 0xbe, 0x7f, 0x35, 0x15, 0xe9, ++ 0xd1, 0xc0, 0x2e, 0xea, 0x2f, 0x19, 0x50, 0xb6, ++ 0x48, 0x1b, 0x04, 0x8a, 0x4c, 0x91, 0x50, 0x6c, ++ 0xb4, 0x0d, 0x50, 0x4e, 0x6c, 0x94, 0x9f, 0x82, ++ 0xd1, 0x97, 0xc2, 0x5a, 0xd1, 0x7d, 0xc7, 0x21, ++ 0x65, 0x11, 0x25, 0x78, 0x2a, 0xc7, 0xa7, 0x12, ++ 0x47, 0xfe, 0xae, 0xf3, 0x2f, 0x1f, 0x25, 0x0c, ++ 0xe4, 0xbb, 0x8f, 0x79, 0xac, 0xaa, 0x17, 0x9d, ++ 0x45, 0xa7, 0xb0, 0x54, 0x5f, 0x09, 0x24, 0x32, ++ 0x5e, 0xfa, 0x87, 0xd5, 0xe4, 0x41, 0xd2, 0x84, ++ 0x78, 0xc6, 0x1f, 0x22, 0x23, 0xee, 0x67, 0xc3, ++ 0xb4, 0x1f, 0x43, 0x94, 0x53, 0x5e, 0x2a, 0x24, ++ 0x36, 0x9a, 0x2e, 0x16, 0x61, 0x3c, 0x45, 0x94, ++ 0x90, 0xc1, 0x4f, 0xb1, 0xd7, 0x55, 0xfe, 0x53, ++ 0xfb, 0xe1, 0xee, 0x45, 0xb1, 0xb2, 0x1f, 0x71, ++ 0x62, 0xe2, 0xfc, 0xaa, 0x74, 0x2a, 0xbe, 0xfd ++}; ++static const u8 enc_output079[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x79, 0x5b, 0xcf, 0xf6, 0x47, 0xc5, 0x53, 0xc2, ++ 0xe4, 0xeb, 0x6e, 0x0e, 0xaf, 0xd9, 0xe0, 0x4e ++}; ++static const u8 enc_assoc079[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce079[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x48, 0x4a ++}; ++static const u8 enc_key079[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input080[] __initconst = { ++ 0xfa, 0xe5, 0x83, 0x45, 0xc1, 0x6c, 0xb0, 0xf5, ++ 0xcc, 0x53, 0x7f, 0x2b, 0x1b, 0x34, 0x69, 0xc9, ++ 0x69, 0x46, 0x3b, 0x3e, 0xa7, 0x1b, 0xcf, 0x6b, ++ 0x98, 0xd6, 0x69, 0xa8, 0xe6, 0x0e, 0x04, 0xfc, ++ 0x08, 0xd5, 0xfd, 0x06, 0x9c, 0x36, 0x26, 0x38, ++ 0xe3, 0x40, 0x0e, 0xf4, 0xcb, 0x24, 0x2e, 0x27, ++ 0xe2, 0x24, 0x5e, 0x68, 0xcb, 0x9e, 0xc5, 0x83, ++ 0xda, 0x53, 0x40, 0xb1, 0x2e, 0xdf, 0x42, 0x3b, ++ 0x73, 0x26, 0xad, 0x20, 0xfe, 0xeb, 0x57, 0xda, ++ 0xca, 0x2e, 0x04, 0x67, 0xa3, 0x28, 0x99, 0xb4, ++ 0x2d, 0xf8, 0xe5, 0x6d, 0x84, 0xe0, 0x06, 0xbc, ++ 0x8a, 0x7a, 0xcc, 0x73, 0x1e, 0x7c, 0x1f, 0x6b, ++ 0xec, 0xb5, 0x71, 0x9f, 0x70, 0x77, 0xf0, 0xd4, ++ 0xf4, 0xc6, 0x1a, 0xb1, 0x1e, 0xba, 0xc1, 0x00, ++ 0x18, 0x01, 0xce, 0x33, 0xc4, 0xe4, 0xa7, 0x7d, ++ 0x83, 0x1d, 0x3c, 0xe3, 0x4e, 0x84, 0x10, 0xe1 ++}; ++static const u8 enc_output080[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x19, 0x46, 0xd6, 0x53, 0x96, 0x0f, 0x94, 0x7a, ++ 0x74, 0xd3, 0xe8, 0x09, 0x3c, 0xf4, 0x85, 0x02 ++}; ++static const u8 enc_assoc080[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce080[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x2f, 0x40 ++}; ++static const u8 enc_key080[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input081[] __initconst = { ++ 0xeb, 0xb2, 0x16, 0xdd, 0xd7, 0xca, 0x70, 0x92, ++ 0x15, 0xf5, 0x03, 0xdf, 0x9c, 0xe6, 0x3c, 0x5c, ++ 0xd2, 0x19, 0x4e, 0x7d, 0x90, 0x99, 0xe8, 0xa9, ++ 0x0b, 0x2a, 0xfa, 0xad, 0x5e, 0xba, 0x35, 0x06, ++ 0x99, 0x25, 0xa6, 0x03, 0xfd, 0xbc, 0x34, 0x1a, ++ 0xae, 0xd4, 0x15, 0x05, 0xb1, 0x09, 0x41, 0xfa, ++ 0x38, 0x56, 0xa7, 0xe2, 0x47, 0xb1, 0x04, 0x07, ++ 0x09, 0x74, 0x6c, 0xfc, 0x20, 0x96, 0xca, 0xa6, ++ 0x31, 0xb2, 0xff, 0xf4, 0x1c, 0x25, 0x05, 0x06, ++ 0xd8, 0x89, 0xc1, 0xc9, 0x06, 0x71, 0xad, 0xe8, ++ 0x53, 0xee, 0x63, 0x94, 0xc1, 0x91, 0x92, 0xa5, ++ 0xcf, 0x37, 0x10, 0xd1, 0x07, 0x30, 0x99, 0xe5, ++ 0xbc, 0x94, 0x65, 0x82, 0xfc, 0x0f, 0xab, 0x9f, ++ 0x54, 0x3c, 0x71, 0x6a, 0xe2, 0x48, 0x6a, 0x86, ++ 0x83, 0xfd, 0xca, 0x39, 0xd2, 0xe1, 0x4f, 0x23, ++ 0xd0, 0x0a, 0x58, 0x26, 0x64, 0xf4, 0xec, 0xb1 ++}; ++static const u8 enc_output081[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x36, 0xc3, 0x00, 0x29, 0x85, 0xdd, 0x21, 0xba, ++ 0xf8, 0x95, 0xd6, 0x33, 0x57, 0x3f, 0x12, 0xc0 ++}; ++static const u8 enc_assoc081[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce081[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x93, 0x35 ++}; ++static const u8 enc_key081[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input082[] __initconst = { ++ 0x40, 0x8a, 0xe6, 0xef, 0x1c, 0x7e, 0xf0, 0xfb, ++ 0x2c, 0x2d, 0x61, 0x08, 0x16, 0xfc, 0x78, 0x49, ++ 0xef, 0xa5, 0x8f, 0x78, 0x27, 0x3f, 0x5f, 0x16, ++ 0x6e, 0xa6, 0x5f, 0x81, 0xb5, 0x75, 0x74, 0x7d, ++ 0x03, 0x5b, 0x30, 0x40, 0xfe, 0xde, 0x1e, 0xb9, ++ 0x45, 0x97, 0x88, 0x66, 0x97, 0x88, 0x40, 0x8e, ++ 0x00, 0x41, 0x3b, 0x3e, 0x37, 0x6d, 0x15, 0x2d, ++ 0x20, 0x4a, 0xa2, 0xb7, 0xa8, 0x35, 0x58, 0xfc, ++ 0xd4, 0x8a, 0x0e, 0xf7, 0xa2, 0x6b, 0x1c, 0xd6, ++ 0xd3, 0x5d, 0x23, 0xb3, 0xf5, 0xdf, 0xe0, 0xca, ++ 0x77, 0xa4, 0xce, 0x32, 0xb9, 0x4a, 0xbf, 0x83, ++ 0xda, 0x2a, 0xef, 0xca, 0xf0, 0x68, 0x38, 0x08, ++ 0x79, 0xe8, 0x9f, 0xb0, 0xa3, 0x82, 0x95, 0x95, ++ 0xcf, 0x44, 0xc3, 0x85, 0x2a, 0xe2, 0xcc, 0x66, ++ 0x2b, 0x68, 0x9f, 0x93, 0x55, 0xd9, 0xc1, 0x83, ++ 0x80, 0x1f, 0x6a, 0xcc, 0x31, 0x3f, 0x89, 0x07 ++}; ++static const u8 enc_output082[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x65, 0x14, 0x51, 0x8e, 0x0a, 0x26, 0x41, 0x42, ++ 0xe0, 0xb7, 0x35, 0x1f, 0x96, 0x7f, 0xc2, 0xae ++}; ++static const u8 enc_assoc082[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce082[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xf7, 0xd5 ++}; ++static const u8 enc_key082[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input083[] __initconst = { ++ 0x0a, 0x0a, 0x24, 0x49, 0x9b, 0xca, 0xde, 0x58, ++ 0xcf, 0x15, 0x76, 0xc3, 0x12, 0xac, 0xa9, 0x84, ++ 0x71, 0x8c, 0xb4, 0xcc, 0x7e, 0x01, 0x53, 0xf5, ++ 0xa9, 0x01, 0x58, 0x10, 0x85, 0x96, 0x44, 0xdf, ++ 0xc0, 0x21, 0x17, 0x4e, 0x0b, 0x06, 0x0a, 0x39, ++ 0x74, 0x48, 0xde, 0x8b, 0x48, 0x4a, 0x86, 0x03, ++ 0xbe, 0x68, 0x0a, 0x69, 0x34, 0xc0, 0x90, 0x6f, ++ 0x30, 0xdd, 0x17, 0xea, 0xe2, 0xd4, 0xc5, 0xfa, ++ 0xa7, 0x77, 0xf8, 0xca, 0x53, 0x37, 0x0e, 0x08, ++ 0x33, 0x1b, 0x88, 0xc3, 0x42, 0xba, 0xc9, 0x59, ++ 0x78, 0x7b, 0xbb, 0x33, 0x93, 0x0e, 0x3b, 0x56, ++ 0xbe, 0x86, 0xda, 0x7f, 0x2a, 0x6e, 0xb1, 0xf9, ++ 0x40, 0x89, 0xd1, 0xd1, 0x81, 0x07, 0x4d, 0x43, ++ 0x02, 0xf8, 0xe0, 0x55, 0x2d, 0x0d, 0xe1, 0xfa, ++ 0xb3, 0x06, 0xa2, 0x1b, 0x42, 0xd4, 0xc3, 0xba, ++ 0x6e, 0x6f, 0x0c, 0xbc, 0xc8, 0x1e, 0x87, 0x7a ++}; ++static const u8 enc_output083[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x4c, 0x19, 0x4d, 0xa6, 0xa9, 0x9f, 0xd6, 0x5b, ++ 0x40, 0xe9, 0xca, 0xd7, 0x98, 0xf4, 0x4b, 0x19 ++}; ++static const u8 enc_assoc083[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce083[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xfc, 0xe4 ++}; ++static const u8 enc_key083[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input084[] __initconst = { ++ 0x4a, 0x0a, 0xaf, 0xf8, 0x49, 0x47, 0x29, 0x18, ++ 0x86, 0x91, 0x70, 0x13, 0x40, 0xf3, 0xce, 0x2b, ++ 0x8a, 0x78, 0xee, 0xd3, 0xa0, 0xf0, 0x65, 0x99, ++ 0x4b, 0x72, 0x48, 0x4e, 0x79, 0x91, 0xd2, 0x5c, ++ 0x29, 0xaa, 0x07, 0x5e, 0xb1, 0xfc, 0x16, 0xde, ++ 0x93, 0xfe, 0x06, 0x90, 0x58, 0x11, 0x2a, 0xb2, ++ 0x84, 0xa3, 0xed, 0x18, 0x78, 0x03, 0x26, 0xd1, ++ 0x25, 0x8a, 0x47, 0x22, 0x2f, 0xa6, 0x33, 0xd8, ++ 0xb2, 0x9f, 0x3b, 0xd9, 0x15, 0x0b, 0x23, 0x9b, ++ 0x15, 0x46, 0xc2, 0xbb, 0x9b, 0x9f, 0x41, 0x0f, ++ 0xeb, 0xea, 0xd3, 0x96, 0x00, 0x0e, 0xe4, 0x77, ++ 0x70, 0x15, 0x32, 0xc3, 0xd0, 0xf5, 0xfb, 0xf8, ++ 0x95, 0xd2, 0x80, 0x19, 0x6d, 0x2f, 0x73, 0x7c, ++ 0x5e, 0x9f, 0xec, 0x50, 0xd9, 0x2b, 0xb0, 0xdf, ++ 0x5d, 0x7e, 0x51, 0x3b, 0xe5, 0xb8, 0xea, 0x97, ++ 0x13, 0x10, 0xd5, 0xbf, 0x16, 0xba, 0x7a, 0xee ++}; ++static const u8 enc_output084[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xc8, 0xae, 0x77, 0x88, 0xcd, 0x28, 0x74, 0xab, ++ 0xc1, 0x38, 0x54, 0x1e, 0x11, 0xfd, 0x05, 0x87 ++}; ++static const u8 enc_assoc084[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce084[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0x84, 0x86, 0xa8 ++}; ++static const u8 enc_key084[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input085[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x78, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x9f, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x9c, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0x47, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0xd4, 0xd2, 0x06, 0x61, 0x6f, 0x92, 0x93, 0xf6, ++ 0x5b, 0x45, 0xdb, 0xbc, 0x74, 0xe7, 0xc2, 0xed, ++ 0xfb, 0xcb, 0xbf, 0x1c, 0xfb, 0x67, 0x9b, 0xb7, ++ 0x39, 0xa5, 0x86, 0x2d, 0xe2, 0xbc, 0xb9, 0x37, ++ 0xf7, 0x4d, 0x5b, 0xf8, 0x67, 0x1c, 0x5a, 0x8a, ++ 0x50, 0x92, 0xf6, 0x1d, 0x54, 0xc9, 0xaa, 0x5b ++}; ++static const u8 enc_output085[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x93, 0x3a, 0x51, 0x63, 0xc7, 0xf6, 0x23, 0x68, ++ 0x32, 0x7b, 0x3f, 0xbc, 0x10, 0x36, 0xc9, 0x43 ++}; ++static const u8 enc_assoc085[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce085[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key085[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input093[] __initconst = { ++ 0x00, 0x52, 0x35, 0xd2, 0xa9, 0x19, 0xf2, 0x8d, ++ 0x3d, 0xb7, 0x66, 0x4a, 0x34, 0xae, 0x6b, 0x44, ++ 0x4d, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x5b, 0x8b, 0x94, 0x50, 0x9e, 0x2b, 0x74, 0xa3, ++ 0x6d, 0x34, 0x6e, 0x33, 0xd5, 0x72, 0x65, 0x9b, ++ 0xa9, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0x83, 0xdc, 0xe9, 0xf3, 0x07, 0x3e, 0xfa, 0xdb, ++ 0x7d, 0x23, 0xb8, 0x7a, 0xce, 0x35, 0x16, 0x8c ++}; ++static const u8 enc_output093[] __initconst = { ++ 0x00, 0x39, 0xe2, 0xfd, 0x2f, 0xd3, 0x12, 0x14, ++ 0x9e, 0x98, 0x98, 0x80, 0x88, 0x48, 0x13, 0xe7, ++ 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x3b, 0x0e, 0x86, 0x9a, 0xaa, 0x8e, 0xa4, 0x96, ++ 0x32, 0xff, 0xff, 0x37, 0xb9, 0xe8, 0xce, 0x00, ++ 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x3b, 0x0e, 0x86, 0x9a, 0xaa, 0x8e, 0xa4, 0x96, ++ 0x32, 0xff, 0xff, 0x37, 0xb9, 0xe8, 0xce, 0x00, ++ 0xa5, 0x19, 0xac, 0x1a, 0x35, 0xb4, 0xa5, 0x77, ++ 0x87, 0x51, 0x0a, 0xf7, 0x8d, 0x8d, 0x20, 0x0a ++}; ++static const u8 enc_assoc093[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce093[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key093[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input094[] __initconst = { ++ 0xd3, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xe5, 0xda, 0x78, 0x76, 0x6f, 0xa1, 0x92, 0x90, ++ 0xc0, 0x31, 0xf7, 0x52, 0x08, 0x50, 0x67, 0x45, ++ 0xae, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x49, 0x6d, 0xde, 0xb0, 0x55, 0x09, 0xc6, 0xef, ++ 0xff, 0xab, 0x75, 0xeb, 0x2d, 0xf4, 0xab, 0x09, ++ 0x76, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x01, 0x49, 0xef, 0x50, 0x4b, 0x71, 0xb1, 0x20, ++ 0xca, 0x4f, 0xf3, 0x95, 0x19, 0xc2, 0xc2, 0x10 ++}; ++static const u8 enc_output094[] __initconst = { ++ 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x62, 0x18, 0xb2, 0x7f, 0x83, 0xb8, 0xb4, 0x66, ++ 0x02, 0xf6, 0xe1, 0xd8, 0x34, 0x20, 0x7b, 0x02, ++ 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x2a, 0x64, 0x16, 0xce, 0xdb, 0x1c, 0xdd, 0x29, ++ 0x6e, 0xf5, 0xd7, 0xd6, 0x92, 0xda, 0xff, 0x02, ++ 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x2a, 0x64, 0x16, 0xce, 0xdb, 0x1c, 0xdd, 0x29, ++ 0x6e, 0xf5, 0xd7, 0xd6, 0x92, 0xda, 0xff, 0x02, ++ 0x30, 0x2f, 0xe8, 0x2a, 0xb0, 0xa0, 0x9a, 0xf6, ++ 0x44, 0x00, 0xd0, 0x15, 0xae, 0x83, 0xd9, 0xcc ++}; ++static const u8 enc_assoc094[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce094[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key094[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input095[] __initconst = { ++ 0xe9, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x6d, 0xf1, 0x39, 0x4e, 0xdc, 0x53, 0x9b, 0x5b, ++ 0x3a, 0x09, 0x57, 0xbe, 0x0f, 0xb8, 0x59, 0x46, ++ 0x80, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0xd1, 0x76, 0x9f, 0xe8, 0x06, 0xbb, 0xfe, 0xb6, ++ 0xf5, 0x90, 0x95, 0x0f, 0x2e, 0xac, 0x9e, 0x0a, ++ 0x58, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x99, 0x52, 0xae, 0x08, 0x18, 0xc3, 0x89, 0x79, ++ 0xc0, 0x74, 0x13, 0x71, 0x1a, 0x9a, 0xf7, 0x13 ++}; ++static const u8 enc_output095[] __initconst = { ++ 0xe9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xea, 0x33, 0xf3, 0x47, 0x30, 0x4a, 0xbd, 0xad, ++ 0xf8, 0xce, 0x41, 0x34, 0x33, 0xc8, 0x45, 0x01, ++ 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xb2, 0x7f, 0x57, 0x96, 0x88, 0xae, 0xe5, 0x70, ++ 0x64, 0xce, 0x37, 0x32, 0x91, 0x82, 0xca, 0x01, ++ 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xb2, 0x7f, 0x57, 0x96, 0x88, 0xae, 0xe5, 0x70, ++ 0x64, 0xce, 0x37, 0x32, 0x91, 0x82, 0xca, 0x01, ++ 0x98, 0xa7, 0xe8, 0x36, 0xe0, 0xee, 0x4d, 0x02, ++ 0x35, 0x00, 0xd0, 0x55, 0x7e, 0xc2, 0xcb, 0xe0 ++}; ++static const u8 enc_assoc095[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce095[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key095[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input096[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x64, 0xf9, 0x0f, 0x5b, 0x26, 0x92, 0xb8, 0x60, ++ 0xd4, 0x59, 0x6f, 0xf4, 0xb3, 0x40, 0x2c, 0x5c, ++ 0x00, 0xb9, 0xbb, 0x53, 0x70, 0x7a, 0xa6, 0x67, ++ 0xd3, 0x56, 0xfe, 0x50, 0xc7, 0x19, 0x96, 0x94, ++ 0x03, 0x35, 0x61, 0xe7, 0xca, 0xca, 0x6d, 0x94, ++ 0x1d, 0xc3, 0xcd, 0x69, 0x14, 0xad, 0x69, 0x04 ++}; ++static const u8 enc_output096[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xe3, 0x3b, 0xc5, 0x52, 0xca, 0x8b, 0x9e, 0x96, ++ 0x16, 0x9e, 0x79, 0x7e, 0x8f, 0x30, 0x30, 0x1b, ++ 0x60, 0x3c, 0xa9, 0x99, 0x44, 0xdf, 0x76, 0x52, ++ 0x8c, 0x9d, 0x6f, 0x54, 0xab, 0x83, 0x3d, 0x0f, ++ 0x60, 0x3c, 0xa9, 0x99, 0x44, 0xdf, 0x76, 0x52, ++ 0x8c, 0x9d, 0x6f, 0x54, 0xab, 0x83, 0x3d, 0x0f, ++ 0x6a, 0xb8, 0xdc, 0xe2, 0xc5, 0x9d, 0xa4, 0x73, ++ 0x71, 0x30, 0xb0, 0x25, 0x2f, 0x68, 0xa8, 0xd8 ++}; ++static const u8 enc_assoc096[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce096[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key096[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input097[] __initconst = { ++ 0x68, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xb0, 0x8f, 0x25, 0x67, 0x5b, 0x9b, 0xcb, 0xf6, ++ 0xe3, 0x84, 0x07, 0xde, 0x2e, 0xc7, 0x5a, 0x47, ++ 0x9f, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x2d, 0x2a, 0xf7, 0xcd, 0x6b, 0x08, 0x05, 0x01, ++ 0xd3, 0x1b, 0xa5, 0x4f, 0xb2, 0xeb, 0x75, 0x96, ++ 0x47, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x65, 0x0e, 0xc6, 0x2d, 0x75, 0x70, 0x72, 0xce, ++ 0xe6, 0xff, 0x23, 0x31, 0x86, 0xdd, 0x1c, 0x8f ++}; ++static const u8 enc_output097[] __initconst = { ++ 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x37, 0x4d, 0xef, 0x6e, 0xb7, 0x82, 0xed, 0x00, ++ 0x21, 0x43, 0x11, 0x54, 0x12, 0xb7, 0x46, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x4e, 0x23, 0x3f, 0xb3, 0xe5, 0x1d, 0x1e, 0xc7, ++ 0x42, 0x45, 0x07, 0x72, 0x0d, 0xc5, 0x21, 0x9d, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x4e, 0x23, 0x3f, 0xb3, 0xe5, 0x1d, 0x1e, 0xc7, ++ 0x42, 0x45, 0x07, 0x72, 0x0d, 0xc5, 0x21, 0x9d, ++ 0x04, 0x4d, 0xea, 0x60, 0x88, 0x80, 0x41, 0x2b, ++ 0xfd, 0xff, 0xcf, 0x35, 0x57, 0x9e, 0x9b, 0x26 ++}; ++static const u8 enc_assoc097[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce097[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key097[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input098[] __initconst = { ++ 0x6d, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xa1, 0x61, 0xb5, 0xab, 0x04, 0x09, 0x00, 0x62, ++ 0x9e, 0xfe, 0xff, 0x78, 0xd7, 0xd8, 0x6b, 0x45, ++ 0x9f, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0xc6, 0xf8, 0x07, 0x8c, 0xc8, 0xef, 0x12, 0xa0, ++ 0xff, 0x65, 0x7d, 0x6d, 0x08, 0xdb, 0x10, 0xb8, ++ 0x47, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x8e, 0xdc, 0x36, 0x6c, 0xd6, 0x97, 0x65, 0x6f, ++ 0xca, 0x81, 0xfb, 0x13, 0x3c, 0xed, 0x79, 0xa1 ++}; ++static const u8 enc_output098[] __initconst = { ++ 0x6d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x26, 0xa3, 0x7f, 0xa2, 0xe8, 0x10, 0x26, 0x94, ++ 0x5c, 0x39, 0xe9, 0xf2, 0xeb, 0xa8, 0x77, 0x02, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xa5, 0xf1, 0xcf, 0xf2, 0x46, 0xfa, 0x09, 0x66, ++ 0x6e, 0x3b, 0xdf, 0x50, 0xb7, 0xf5, 0x44, 0xb3, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xa5, 0xf1, 0xcf, 0xf2, 0x46, 0xfa, 0x09, 0x66, ++ 0x6e, 0x3b, 0xdf, 0x50, 0xb7, 0xf5, 0x44, 0xb3, ++ 0x1e, 0x6b, 0xea, 0x63, 0x14, 0x54, 0x2e, 0x2e, ++ 0xf9, 0xff, 0xcf, 0x45, 0x0b, 0x2e, 0x98, 0x2b ++}; ++static const u8 enc_assoc098[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce098[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key098[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input099[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xfc, 0x01, 0xb8, 0x91, 0xe5, 0xf0, 0xf9, 0x12, ++ 0x8d, 0x7d, 0x1c, 0x57, 0x91, 0x92, 0xb6, 0x98, ++ 0x63, 0x41, 0x44, 0x15, 0xb6, 0x99, 0x68, 0x95, ++ 0x9a, 0x72, 0x91, 0xb7, 0xa5, 0xaf, 0x13, 0x48, ++ 0x60, 0xcd, 0x9e, 0xa1, 0x0c, 0x29, 0xa3, 0x66, ++ 0x54, 0xe7, 0xa2, 0x8e, 0x76, 0x1b, 0xec, 0xd8 ++}; ++static const u8 enc_output099[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x7b, 0xc3, 0x72, 0x98, 0x09, 0xe9, 0xdf, 0xe4, ++ 0x4f, 0xba, 0x0a, 0xdd, 0xad, 0xe2, 0xaa, 0xdf, ++ 0x03, 0xc4, 0x56, 0xdf, 0x82, 0x3c, 0xb8, 0xa0, ++ 0xc5, 0xb9, 0x00, 0xb3, 0xc9, 0x35, 0xb8, 0xd3, ++ 0x03, 0xc4, 0x56, 0xdf, 0x82, 0x3c, 0xb8, 0xa0, ++ 0xc5, 0xb9, 0x00, 0xb3, 0xc9, 0x35, 0xb8, 0xd3, ++ 0xed, 0x20, 0x17, 0xc8, 0xdb, 0xa4, 0x77, 0x56, ++ 0x29, 0x04, 0x9d, 0x78, 0x6e, 0x3b, 0xce, 0xb1 ++}; ++static const u8 enc_assoc099[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce099[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key099[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input100[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x6b, 0x6d, 0xc9, 0xd2, 0x1a, 0x81, 0x9e, 0x70, ++ 0xb5, 0x77, 0xf4, 0x41, 0x37, 0xd3, 0xd6, 0xbd, ++ 0x13, 0x35, 0xf5, 0xeb, 0x44, 0x49, 0x40, 0x77, ++ 0xb2, 0x64, 0x49, 0xa5, 0x4b, 0x6c, 0x7c, 0x75, ++ 0x10, 0xb9, 0x2f, 0x5f, 0xfe, 0xf9, 0x8b, 0x84, ++ 0x7c, 0xf1, 0x7a, 0x9c, 0x98, 0xd8, 0x83, 0xe5 ++}; ++static const u8 enc_output100[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xec, 0xaf, 0x03, 0xdb, 0xf6, 0x98, 0xb8, 0x86, ++ 0x77, 0xb0, 0xe2, 0xcb, 0x0b, 0xa3, 0xca, 0xfa, ++ 0x73, 0xb0, 0xe7, 0x21, 0x70, 0xec, 0x90, 0x42, ++ 0xed, 0xaf, 0xd8, 0xa1, 0x27, 0xf6, 0xd7, 0xee, ++ 0x73, 0xb0, 0xe7, 0x21, 0x70, 0xec, 0x90, 0x42, ++ 0xed, 0xaf, 0xd8, 0xa1, 0x27, 0xf6, 0xd7, 0xee, ++ 0x07, 0x3f, 0x17, 0xcb, 0x67, 0x78, 0x64, 0x59, ++ 0x25, 0x04, 0x9d, 0x88, 0x22, 0xcb, 0xca, 0xb6 ++}; ++static const u8 enc_assoc100[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce100[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key100[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input101[] __initconst = { ++ 0xff, 0xcb, 0x2b, 0x11, 0x06, 0xf8, 0x23, 0x4c, ++ 0x5e, 0x99, 0xd4, 0xdb, 0x4c, 0x70, 0x48, 0xde, ++ 0x32, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x16, 0xe9, 0x88, 0x4a, 0x11, 0x4f, 0x0e, 0x92, ++ 0x66, 0xce, 0xa3, 0x88, 0x5f, 0xe3, 0x6b, 0x9f, ++ 0xd6, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0xce, 0xbe, 0xf5, 0xe9, 0x88, 0x5a, 0x80, 0xea, ++ 0x76, 0xd9, 0x75, 0xc1, 0x44, 0xa4, 0x18, 0x88 ++}; ++static const u8 enc_output101[] __initconst = { ++ 0xff, 0xa0, 0xfc, 0x3e, 0x80, 0x32, 0xc3, 0xd5, ++ 0xfd, 0xb6, 0x2a, 0x11, 0xf0, 0x96, 0x30, 0x7d, ++ 0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x76, 0x6c, 0x9a, 0x80, 0x25, 0xea, 0xde, 0xa7, ++ 0x39, 0x05, 0x32, 0x8c, 0x33, 0x79, 0xc0, 0x04, ++ 0xb5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x76, 0x6c, 0x9a, 0x80, 0x25, 0xea, 0xde, 0xa7, ++ 0x39, 0x05, 0x32, 0x8c, 0x33, 0x79, 0xc0, 0x04, ++ 0x8b, 0x9b, 0xb4, 0xb4, 0x86, 0x12, 0x89, 0x65, ++ 0x8c, 0x69, 0x6a, 0x83, 0x40, 0x15, 0x04, 0x05 ++}; ++static const u8 enc_assoc101[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce101[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key101[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input102[] __initconst = { ++ 0x6f, 0x9e, 0x70, 0xed, 0x3b, 0x8b, 0xac, 0xa0, ++ 0x26, 0xe4, 0x6a, 0x5a, 0x09, 0x43, 0x15, 0x8d, ++ 0x21, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x0c, 0x61, 0x2c, 0x5e, 0x8d, 0x89, 0xa8, 0x73, ++ 0xdb, 0xca, 0xad, 0x5b, 0x73, 0x46, 0x42, 0x9b, ++ 0xc5, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0xd4, 0x36, 0x51, 0xfd, 0x14, 0x9c, 0x26, 0x0b, ++ 0xcb, 0xdd, 0x7b, 0x12, 0x68, 0x01, 0x31, 0x8c ++}; ++static const u8 enc_output102[] __initconst = { ++ 0x6f, 0xf5, 0xa7, 0xc2, 0xbd, 0x41, 0x4c, 0x39, ++ 0x85, 0xcb, 0x94, 0x90, 0xb5, 0xa5, 0x6d, 0x2e, ++ 0xa6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x6c, 0xe4, 0x3e, 0x94, 0xb9, 0x2c, 0x78, 0x46, ++ 0x84, 0x01, 0x3c, 0x5f, 0x1f, 0xdc, 0xe9, 0x00, ++ 0xa6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x6c, 0xe4, 0x3e, 0x94, 0xb9, 0x2c, 0x78, 0x46, ++ 0x84, 0x01, 0x3c, 0x5f, 0x1f, 0xdc, 0xe9, 0x00, ++ 0x8b, 0x3b, 0xbd, 0x51, 0x64, 0x44, 0x59, 0x56, ++ 0x8d, 0x81, 0xca, 0x1f, 0xa7, 0x2c, 0xe4, 0x04 ++}; ++static const u8 enc_assoc102[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce102[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key102[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input103[] __initconst = { ++ 0x41, 0x2b, 0x08, 0x0a, 0x3e, 0x19, 0xc1, 0x0d, ++ 0x44, 0xa1, 0xaf, 0x1e, 0xab, 0xde, 0xb4, 0xce, ++ 0x35, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x6b, 0x83, 0x94, 0x33, 0x09, 0x21, 0x48, 0x6c, ++ 0xa1, 0x1d, 0x29, 0x1c, 0x3e, 0x97, 0xee, 0x9a, ++ 0xd1, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0xb3, 0xd4, 0xe9, 0x90, 0x90, 0x34, 0xc6, 0x14, ++ 0xb1, 0x0a, 0xff, 0x55, 0x25, 0xd0, 0x9d, 0x8d ++}; ++static const u8 enc_output103[] __initconst = { ++ 0x41, 0x40, 0xdf, 0x25, 0xb8, 0xd3, 0x21, 0x94, ++ 0xe7, 0x8e, 0x51, 0xd4, 0x17, 0x38, 0xcc, 0x6d, ++ 0xb2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x0b, 0x06, 0x86, 0xf9, 0x3d, 0x84, 0x98, 0x59, ++ 0xfe, 0xd6, 0xb8, 0x18, 0x52, 0x0d, 0x45, 0x01, ++ 0xb2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x0b, 0x06, 0x86, 0xf9, 0x3d, 0x84, 0x98, 0x59, ++ 0xfe, 0xd6, 0xb8, 0x18, 0x52, 0x0d, 0x45, 0x01, ++ 0x86, 0xfb, 0xab, 0x2b, 0x4a, 0x94, 0xf4, 0x7a, ++ 0xa5, 0x6f, 0x0a, 0xea, 0x65, 0xd1, 0x10, 0x08 ++}; ++static const u8 enc_assoc103[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce103[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key103[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input104[] __initconst = { ++ 0xb2, 0x47, 0xa7, 0x47, 0x23, 0x49, 0x1a, 0xac, ++ 0xac, 0xaa, 0xd7, 0x09, 0xc9, 0x1e, 0x93, 0x2b, ++ 0x31, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x9a, 0xde, 0x04, 0xe7, 0x5b, 0xb7, 0x01, 0xd9, ++ 0x66, 0x06, 0x01, 0xb3, 0x47, 0x65, 0xde, 0x98, ++ 0xd5, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0x42, 0x89, 0x79, 0x44, 0xc2, 0xa2, 0x8f, 0xa1, ++ 0x76, 0x11, 0xd7, 0xfa, 0x5c, 0x22, 0xad, 0x8f ++}; ++static const u8 enc_output104[] __initconst = { ++ 0xb2, 0x2c, 0x70, 0x68, 0xa5, 0x83, 0xfa, 0x35, ++ 0x0f, 0x85, 0x29, 0xc3, 0x75, 0xf8, 0xeb, 0x88, ++ 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xfa, 0x5b, 0x16, 0x2d, 0x6f, 0x12, 0xd1, 0xec, ++ 0x39, 0xcd, 0x90, 0xb7, 0x2b, 0xff, 0x75, 0x03, ++ 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xfa, 0x5b, 0x16, 0x2d, 0x6f, 0x12, 0xd1, 0xec, ++ 0x39, 0xcd, 0x90, 0xb7, 0x2b, 0xff, 0x75, 0x03, ++ 0xa0, 0x19, 0xac, 0x2e, 0xd6, 0x67, 0xe1, 0x7d, ++ 0xa1, 0x6f, 0x0a, 0xfa, 0x19, 0x61, 0x0d, 0x0d ++}; ++static const u8 enc_assoc104[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce104[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key104[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input105[] __initconst = { ++ 0x74, 0x0f, 0x9e, 0x49, 0xf6, 0x10, 0xef, 0xa5, ++ 0x85, 0xb6, 0x59, 0xca, 0x6e, 0xd8, 0xb4, 0x99, ++ 0x2d, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x41, 0x2d, 0x96, 0xaf, 0xbe, 0x80, 0xec, 0x3e, ++ 0x79, 0xd4, 0x51, 0xb0, 0x0a, 0x2d, 0xb2, 0x9a, ++ 0xc9, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0x99, 0x7a, 0xeb, 0x0c, 0x27, 0x95, 0x62, 0x46, ++ 0x69, 0xc3, 0x87, 0xf9, 0x11, 0x6a, 0xc1, 0x8d ++}; ++static const u8 enc_output105[] __initconst = { ++ 0x74, 0x64, 0x49, 0x66, 0x70, 0xda, 0x0f, 0x3c, ++ 0x26, 0x99, 0xa7, 0x00, 0xd2, 0x3e, 0xcc, 0x3a, ++ 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x21, 0xa8, 0x84, 0x65, 0x8a, 0x25, 0x3c, 0x0b, ++ 0x26, 0x1f, 0xc0, 0xb4, 0x66, 0xb7, 0x19, 0x01, ++ 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x21, 0xa8, 0x84, 0x65, 0x8a, 0x25, 0x3c, 0x0b, ++ 0x26, 0x1f, 0xc0, 0xb4, 0x66, 0xb7, 0x19, 0x01, ++ 0x73, 0x6e, 0x18, 0x18, 0x16, 0x96, 0xa5, 0x88, ++ 0x9c, 0x31, 0x59, 0xfa, 0xab, 0xab, 0x20, 0xfd ++}; ++static const u8 enc_assoc105[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce105[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key105[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input106[] __initconst = { ++ 0xad, 0xba, 0x5d, 0x10, 0x5b, 0xc8, 0xaa, 0x06, ++ 0x2c, 0x23, 0x36, 0xcb, 0x88, 0x9d, 0xdb, 0xd5, ++ 0x37, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x17, 0x7c, 0x5f, 0xfe, 0x28, 0x75, 0xf4, 0x68, ++ 0xf6, 0xc2, 0x96, 0x57, 0x48, 0xf3, 0x59, 0x9a, ++ 0xd3, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0xcf, 0x2b, 0x22, 0x5d, 0xb1, 0x60, 0x7a, 0x10, ++ 0xe6, 0xd5, 0x40, 0x1e, 0x53, 0xb4, 0x2a, 0x8d ++}; ++static const u8 enc_output106[] __initconst = { ++ 0xad, 0xd1, 0x8a, 0x3f, 0xdd, 0x02, 0x4a, 0x9f, ++ 0x8f, 0x0c, 0xc8, 0x01, 0x34, 0x7b, 0xa3, 0x76, ++ 0xb0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x77, 0xf9, 0x4d, 0x34, 0x1c, 0xd0, 0x24, 0x5d, ++ 0xa9, 0x09, 0x07, 0x53, 0x24, 0x69, 0xf2, 0x01, ++ 0xb0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x77, 0xf9, 0x4d, 0x34, 0x1c, 0xd0, 0x24, 0x5d, ++ 0xa9, 0x09, 0x07, 0x53, 0x24, 0x69, 0xf2, 0x01, ++ 0xba, 0xd5, 0x8f, 0x10, 0xa9, 0x1e, 0x6a, 0x88, ++ 0x9a, 0xba, 0x32, 0xfd, 0x17, 0xd8, 0x33, 0x1a ++}; ++static const u8 enc_assoc106[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce106[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key106[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input107[] __initconst = { ++ 0xfe, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xc0, 0x01, 0xed, 0xc5, 0xda, 0x44, 0x2e, 0x71, ++ 0x9b, 0xce, 0x9a, 0xbe, 0x27, 0x3a, 0xf1, 0x44, ++ 0xb4, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x48, 0x02, 0x5f, 0x41, 0xfa, 0x4e, 0x33, 0x6c, ++ 0x78, 0x69, 0x57, 0xa2, 0xa7, 0xc4, 0x93, 0x0a, ++ 0x6c, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x00, 0x26, 0x6e, 0xa1, 0xe4, 0x36, 0x44, 0xa3, ++ 0x4d, 0x8d, 0xd1, 0xdc, 0x93, 0xf2, 0xfa, 0x13 ++}; ++static const u8 enc_output107[] __initconst = { ++ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x47, 0xc3, 0x27, 0xcc, 0x36, 0x5d, 0x08, 0x87, ++ 0x59, 0x09, 0x8c, 0x34, 0x1b, 0x4a, 0xed, 0x03, ++ 0xd4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x2b, 0x0b, 0x97, 0x3f, 0x74, 0x5b, 0x28, 0xaa, ++ 0xe9, 0x37, 0xf5, 0x9f, 0x18, 0xea, 0xc7, 0x01, ++ 0xd4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x2b, 0x0b, 0x97, 0x3f, 0x74, 0x5b, 0x28, 0xaa, ++ 0xe9, 0x37, 0xf5, 0x9f, 0x18, 0xea, 0xc7, 0x01, ++ 0xd6, 0x8c, 0xe1, 0x74, 0x07, 0x9a, 0xdd, 0x02, ++ 0x8d, 0xd0, 0x5c, 0xf8, 0x14, 0x63, 0x04, 0x88 ++}; ++static const u8 enc_assoc107[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce107[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key107[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input108[] __initconst = { ++ 0xb5, 0x13, 0xb0, 0x6a, 0xb9, 0xac, 0x14, 0x43, ++ 0x5a, 0xcb, 0x8a, 0xa3, 0xa3, 0x7a, 0xfd, 0xb6, ++ 0x54, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x61, 0x95, 0x01, 0x93, 0xb1, 0xbf, 0x03, 0x11, ++ 0xff, 0x11, 0x79, 0x89, 0xae, 0xd9, 0xa9, 0x99, ++ 0xb0, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0xb9, 0xc2, 0x7c, 0x30, 0x28, 0xaa, 0x8d, 0x69, ++ 0xef, 0x06, 0xaf, 0xc0, 0xb5, 0x9e, 0xda, 0x8e ++}; ++static const u8 enc_output108[] __initconst = { ++ 0xb5, 0x78, 0x67, 0x45, 0x3f, 0x66, 0xf4, 0xda, ++ 0xf9, 0xe4, 0x74, 0x69, 0x1f, 0x9c, 0x85, 0x15, ++ 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x01, 0x10, 0x13, 0x59, 0x85, 0x1a, 0xd3, 0x24, ++ 0xa0, 0xda, 0xe8, 0x8d, 0xc2, 0x43, 0x02, 0x02, ++ 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x01, 0x10, 0x13, 0x59, 0x85, 0x1a, 0xd3, 0x24, ++ 0xa0, 0xda, 0xe8, 0x8d, 0xc2, 0x43, 0x02, 0x02, ++ 0xaa, 0x48, 0xa3, 0x88, 0x7d, 0x4b, 0x05, 0x96, ++ 0x99, 0xc2, 0xfd, 0xf9, 0xc6, 0x78, 0x7e, 0x0a ++}; ++static const u8 enc_assoc108[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce108[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key108[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input109[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xd4, 0xf1, 0x09, 0xe8, 0x14, 0xce, 0xa8, 0x5a, ++ 0x08, 0xc0, 0x11, 0xd8, 0x50, 0xdd, 0x1d, 0xcb, ++ 0xcf, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x53, 0x40, 0xb8, 0x5a, 0x9a, 0xa0, 0x82, 0x96, ++ 0xb7, 0x7a, 0x5f, 0xc3, 0x96, 0x1f, 0x66, 0x0f, ++ 0x17, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x1b, 0x64, 0x89, 0xba, 0x84, 0xd8, 0xf5, 0x59, ++ 0x82, 0x9e, 0xd9, 0xbd, 0xa2, 0x29, 0x0f, 0x16 ++}; ++static const u8 enc_output109[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x53, 0x33, 0xc3, 0xe1, 0xf8, 0xd7, 0x8e, 0xac, ++ 0xca, 0x07, 0x07, 0x52, 0x6c, 0xad, 0x01, 0x8c, ++ 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x30, 0x49, 0x70, 0x24, 0x14, 0xb5, 0x99, 0x50, ++ 0x26, 0x24, 0xfd, 0xfe, 0x29, 0x31, 0x32, 0x04, ++ 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x30, 0x49, 0x70, 0x24, 0x14, 0xb5, 0x99, 0x50, ++ 0x26, 0x24, 0xfd, 0xfe, 0x29, 0x31, 0x32, 0x04, ++ 0xb9, 0x36, 0xa8, 0x17, 0xf2, 0x21, 0x1a, 0xf1, ++ 0x29, 0xe2, 0xcf, 0x16, 0x0f, 0xd4, 0x2b, 0xcb ++}; ++static const u8 enc_assoc109[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce109[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key109[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input110[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xdf, 0x4c, 0x62, 0x03, 0x2d, 0x41, 0x19, 0xb5, ++ 0x88, 0x47, 0x7e, 0x99, 0x92, 0x5a, 0x56, 0xd9, ++ 0xd6, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0xfa, 0x84, 0xf0, 0x64, 0x55, 0x36, 0x42, 0x1b, ++ 0x2b, 0xb9, 0x24, 0x6e, 0xc2, 0x19, 0xed, 0x0b, ++ 0x0e, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0xb2, 0xa0, 0xc1, 0x84, 0x4b, 0x4e, 0x35, 0xd4, ++ 0x1e, 0x5d, 0xa2, 0x10, 0xf6, 0x2f, 0x84, 0x12 ++}; ++static const u8 enc_output110[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x58, 0x8e, 0xa8, 0x0a, 0xc1, 0x58, 0x3f, 0x43, ++ 0x4a, 0x80, 0x68, 0x13, 0xae, 0x2a, 0x4a, 0x9e, ++ 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x99, 0x8d, 0x38, 0x1a, 0xdb, 0x23, 0x59, 0xdd, ++ 0xba, 0xe7, 0x86, 0x53, 0x7d, 0x37, 0xb9, 0x00, ++ 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x99, 0x8d, 0x38, 0x1a, 0xdb, 0x23, 0x59, 0xdd, ++ 0xba, 0xe7, 0x86, 0x53, 0x7d, 0x37, 0xb9, 0x00, ++ 0x9f, 0x7a, 0xc4, 0x35, 0x1f, 0x6b, 0x91, 0xe6, ++ 0x30, 0x97, 0xa7, 0x13, 0x11, 0x5d, 0x05, 0xbe ++}; ++static const u8 enc_assoc110[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce110[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key110[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input111[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x13, 0xf8, 0x0a, 0x00, 0x6d, 0xc1, 0xbb, 0xda, ++ 0xd6, 0x39, 0xa9, 0x2f, 0xc7, 0xec, 0xa6, 0x55, ++ 0xf7, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x63, 0x48, 0xb8, 0xfd, 0x29, 0xbf, 0x96, 0xd5, ++ 0x63, 0xa5, 0x17, 0xe2, 0x7d, 0x7b, 0xfc, 0x0f, ++ 0x2f, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x2b, 0x6c, 0x89, 0x1d, 0x37, 0xc7, 0xe1, 0x1a, ++ 0x56, 0x41, 0x91, 0x9c, 0x49, 0x4d, 0x95, 0x16 ++}; ++static const u8 enc_output111[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x94, 0x3a, 0xc0, 0x09, 0x81, 0xd8, 0x9d, 0x2c, ++ 0x14, 0xfe, 0xbf, 0xa5, 0xfb, 0x9c, 0xba, 0x12, ++ 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x41, 0x70, 0x83, 0xa7, 0xaa, 0x8d, 0x13, ++ 0xf2, 0xfb, 0xb5, 0xdf, 0xc2, 0x55, 0xa8, 0x04, ++ 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x41, 0x70, 0x83, 0xa7, 0xaa, 0x8d, 0x13, ++ 0xf2, 0xfb, 0xb5, 0xdf, 0xc2, 0x55, 0xa8, 0x04, ++ 0x9a, 0x18, 0xa8, 0x28, 0x07, 0x02, 0x69, 0xf4, ++ 0x47, 0x00, 0xd0, 0x09, 0xe7, 0x17, 0x1c, 0xc9 ++}; ++static const u8 enc_assoc111[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce111[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key111[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input112[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x82, 0xe5, 0x9b, 0x45, 0x82, 0x91, 0x50, 0x38, ++ 0xf9, 0x33, 0x81, 0x1e, 0x65, 0x2d, 0xc6, 0x6a, ++ 0xfc, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0xb6, 0x71, 0xc8, 0xca, 0xc2, 0x70, 0xc2, 0x65, ++ 0xa0, 0xac, 0x2f, 0x53, 0x57, 0x99, 0x88, 0x0a, ++ 0x24, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0xfe, 0x55, 0xf9, 0x2a, 0xdc, 0x08, 0xb5, 0xaa, ++ 0x95, 0x48, 0xa9, 0x2d, 0x63, 0xaf, 0xe1, 0x13 ++}; ++static const u8 enc_output112[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x05, 0x27, 0x51, 0x4c, 0x6e, 0x88, 0x76, 0xce, ++ 0x3b, 0xf4, 0x97, 0x94, 0x59, 0x5d, 0xda, 0x2d, ++ 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xd5, 0x78, 0x00, 0xb4, 0x4c, 0x65, 0xd9, 0xa3, ++ 0x31, 0xf2, 0x8d, 0x6e, 0xe8, 0xb7, 0xdc, 0x01, ++ 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xd5, 0x78, 0x00, 0xb4, 0x4c, 0x65, 0xd9, 0xa3, ++ 0x31, 0xf2, 0x8d, 0x6e, 0xe8, 0xb7, 0xdc, 0x01, ++ 0xb4, 0x36, 0xa8, 0x2b, 0x93, 0xd5, 0x55, 0xf7, ++ 0x43, 0x00, 0xd0, 0x19, 0x9b, 0xa7, 0x18, 0xce ++}; ++static const u8 enc_assoc112[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce112[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key112[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input113[] __initconst = { ++ 0xff, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0xf1, 0xd1, 0x28, 0x87, 0xb7, 0x21, 0x69, 0x86, ++ 0xa1, 0x2d, 0x79, 0x09, 0x8b, 0x6d, 0xe6, 0x0f, ++ 0xc0, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0xa7, 0xc7, 0x58, 0x99, 0xf3, 0xe6, 0x0a, 0xf1, ++ 0xfc, 0xb6, 0xc7, 0x30, 0x7d, 0x87, 0x59, 0x0f, ++ 0x18, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0xef, 0xe3, 0x69, 0x79, 0xed, 0x9e, 0x7d, 0x3e, ++ 0xc9, 0x52, 0x41, 0x4e, 0x49, 0xb1, 0x30, 0x16 ++}; ++static const u8 enc_output113[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x76, 0x13, 0xe2, 0x8e, 0x5b, 0x38, 0x4f, 0x70, ++ 0x63, 0xea, 0x6f, 0x83, 0xb7, 0x1d, 0xfa, 0x48, ++ 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xc4, 0xce, 0x90, 0xe7, 0x7d, 0xf3, 0x11, 0x37, ++ 0x6d, 0xe8, 0x65, 0x0d, 0xc2, 0xa9, 0x0d, 0x04, ++ 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xc4, 0xce, 0x90, 0xe7, 0x7d, 0xf3, 0x11, 0x37, ++ 0x6d, 0xe8, 0x65, 0x0d, 0xc2, 0xa9, 0x0d, 0x04, ++ 0xce, 0x54, 0xa8, 0x2e, 0x1f, 0xa9, 0x42, 0xfa, ++ 0x3f, 0x00, 0xd0, 0x29, 0x4f, 0x37, 0x15, 0xd3 ++}; ++static const u8 enc_assoc113[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce113[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key113[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input114[] __initconst = { ++ 0xcb, 0xf1, 0xda, 0x9e, 0x0b, 0xa9, 0x37, 0x73, ++ 0x74, 0xe6, 0x9e, 0x1c, 0x0e, 0x60, 0x0c, 0xfc, ++ 0x34, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0xbe, 0x3f, 0xa6, 0x6b, 0x6c, 0xe7, 0x80, 0x8a, ++ 0xa3, 0xe4, 0x59, 0x49, 0xf9, 0x44, 0x64, 0x9f, ++ 0xd0, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0x66, 0x68, 0xdb, 0xc8, 0xf5, 0xf2, 0x0e, 0xf2, ++ 0xb3, 0xf3, 0x8f, 0x00, 0xe2, 0x03, 0x17, 0x88 ++}; ++static const u8 enc_output114[] __initconst = { ++ 0xcb, 0x9a, 0x0d, 0xb1, 0x8d, 0x63, 0xd7, 0xea, ++ 0xd7, 0xc9, 0x60, 0xd6, 0xb2, 0x86, 0x74, 0x5f, ++ 0xb3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xde, 0xba, 0xb4, 0xa1, 0x58, 0x42, 0x50, 0xbf, ++ 0xfc, 0x2f, 0xc8, 0x4d, 0x95, 0xde, 0xcf, 0x04, ++ 0xb3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xde, 0xba, 0xb4, 0xa1, 0x58, 0x42, 0x50, 0xbf, ++ 0xfc, 0x2f, 0xc8, 0x4d, 0x95, 0xde, 0xcf, 0x04, ++ 0x23, 0x83, 0xab, 0x0b, 0x79, 0x92, 0x05, 0x69, ++ 0x9b, 0x51, 0x0a, 0xa7, 0x09, 0xbf, 0x31, 0xf1 ++}; ++static const u8 enc_assoc114[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce114[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key114[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input115[] __initconst = { ++ 0x8f, 0x27, 0x86, 0x94, 0xc4, 0xe9, 0xda, 0xeb, ++ 0xd5, 0x8d, 0x3e, 0x5b, 0x96, 0x6e, 0x8b, 0x68, ++ 0x42, 0x3d, 0x35, 0xf6, 0x13, 0xe6, 0xd9, 0x09, ++ 0x3d, 0x38, 0xe9, 0x75, 0xc3, 0x8f, 0xe3, 0xb8, ++ 0x06, 0x53, 0xe7, 0xa3, 0x31, 0x71, 0x88, 0x33, ++ 0xac, 0xc3, 0xb9, 0xad, 0xff, 0x1c, 0x31, 0x98, ++ 0xa6, 0xf6, 0x37, 0x81, 0x71, 0xea, 0xe4, 0x39, ++ 0x6e, 0xa1, 0x5d, 0xc2, 0x40, 0xd1, 0xab, 0xf4, ++ 0xde, 0x04, 0x9a, 0x00, 0xa8, 0x64, 0x06, 0x4b, ++ 0xbc, 0xd4, 0x6f, 0xe4, 0xe4, 0x5b, 0x42, 0x8f ++}; ++static const u8 enc_output115[] __initconst = { ++ 0x8f, 0x4c, 0x51, 0xbb, 0x42, 0x23, 0x3a, 0x72, ++ 0x76, 0xa2, 0xc0, 0x91, 0x2a, 0x88, 0xf3, 0xcb, ++ 0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x66, 0xd6, 0xf5, 0x69, 0x05, 0xd4, 0x58, 0x06, ++ 0xf3, 0x08, 0x28, 0xa9, 0x93, 0x86, 0x9a, 0x03, ++ 0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x66, 0xd6, 0xf5, 0x69, 0x05, 0xd4, 0x58, 0x06, ++ 0xf3, 0x08, 0x28, 0xa9, 0x93, 0x86, 0x9a, 0x03, ++ 0x8b, 0xfb, 0xab, 0x17, 0xa9, 0xe0, 0xb8, 0x74, ++ 0x8b, 0x51, 0x0a, 0xe7, 0xd9, 0xfd, 0x23, 0x05 ++}; ++static const u8 enc_assoc115[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce115[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key115[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input116[] __initconst = { ++ 0xd5, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x9a, 0x22, 0xd7, 0x0a, 0x48, 0xe2, 0x4f, 0xdd, ++ 0xcd, 0xd4, 0x41, 0x9d, 0xe6, 0x4c, 0x8f, 0x44, ++ 0xfc, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x77, 0xb5, 0xc9, 0x07, 0xd9, 0xc9, 0xe1, 0xea, ++ 0x51, 0x85, 0x1a, 0x20, 0x4a, 0xad, 0x9f, 0x0a, ++ 0x24, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x3f, 0x91, 0xf8, 0xe7, 0xc7, 0xb1, 0x96, 0x25, ++ 0x64, 0x61, 0x9c, 0x5e, 0x7e, 0x9b, 0xf6, 0x13 ++}; ++static const u8 enc_output116[] __initconst = { ++ 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x1d, 0xe0, 0x1d, 0x03, 0xa4, 0xfb, 0x69, 0x2b, ++ 0x0f, 0x13, 0x57, 0x17, 0xda, 0x3c, 0x93, 0x03, ++ 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x14, 0xbc, 0x01, 0x79, 0x57, 0xdc, 0xfa, 0x2c, ++ 0xc0, 0xdb, 0xb8, 0x1d, 0xf5, 0x83, 0xcb, 0x01, ++ 0x9c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x14, 0xbc, 0x01, 0x79, 0x57, 0xdc, 0xfa, 0x2c, ++ 0xc0, 0xdb, 0xb8, 0x1d, 0xf5, 0x83, 0xcb, 0x01, ++ 0x49, 0xbc, 0x6e, 0x9f, 0xc5, 0x1c, 0x4d, 0x50, ++ 0x30, 0x36, 0x64, 0x4d, 0x84, 0x27, 0x73, 0xd2 ++}; ++static const u8 enc_assoc116[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce116[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key116[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input117[] __initconst = { ++ 0xdb, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x75, 0xd5, 0x64, 0x3a, 0xa5, 0xaf, 0x93, 0x4d, ++ 0x8c, 0xce, 0x39, 0x2c, 0xc3, 0xee, 0xdb, 0x47, ++ 0xc0, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0x60, 0x1b, 0x5a, 0xd2, 0x06, 0x7f, 0x28, 0x06, ++ 0x6a, 0x8f, 0x32, 0x81, 0x71, 0x5b, 0xa8, 0x08, ++ 0x18, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x28, 0x3f, 0x6b, 0x32, 0x18, 0x07, 0x5f, 0xc9, ++ 0x5f, 0x6b, 0xb4, 0xff, 0x45, 0x6d, 0xc1, 0x11 ++}; ++static const u8 enc_output117[] __initconst = { ++ 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xf2, 0x17, 0xae, 0x33, 0x49, 0xb6, 0xb5, 0xbb, ++ 0x4e, 0x09, 0x2f, 0xa6, 0xff, 0x9e, 0xc7, 0x00, ++ 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x03, 0x12, 0x92, 0xac, 0x88, 0x6a, 0x33, 0xc0, ++ 0xfb, 0xd1, 0x90, 0xbc, 0xce, 0x75, 0xfc, 0x03, ++ 0xa0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x03, 0x12, 0x92, 0xac, 0x88, 0x6a, 0x33, 0xc0, ++ 0xfb, 0xd1, 0x90, 0xbc, 0xce, 0x75, 0xfc, 0x03, ++ 0x63, 0xda, 0x6e, 0xa2, 0x51, 0xf0, 0x39, 0x53, ++ 0x2c, 0x36, 0x64, 0x5d, 0x38, 0xb7, 0x6f, 0xd7 ++}; ++static const u8 enc_assoc117[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce117[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key117[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - edge case intermediate sums in poly1305 */ ++static const u8 enc_input118[] __initconst = { ++ 0x93, 0x94, 0x28, 0xd0, 0x79, 0x35, 0x1f, 0x66, ++ 0x5c, 0xd0, 0x01, 0x35, 0x43, 0x19, 0x87, 0x5c, ++ 0x62, 0x48, 0x39, 0x60, 0x42, 0x16, 0xe4, 0x03, ++ 0xeb, 0xcc, 0x6a, 0xf5, 0x59, 0xec, 0x8b, 0x43, ++ 0x97, 0x7a, 0xed, 0x35, 0xcb, 0x5a, 0x2f, 0xca, ++ 0xa0, 0x34, 0x6e, 0xfb, 0x93, 0x65, 0x54, 0x64, ++ 0xd8, 0xc8, 0xc3, 0xfa, 0x1a, 0x9e, 0x47, 0x4a, ++ 0xbe, 0x52, 0xd0, 0x2c, 0x81, 0x87, 0xe9, 0x0f, ++ 0x4f, 0x2d, 0x90, 0x96, 0x52, 0x4f, 0xa1, 0xb2, ++ 0xb0, 0x23, 0xb8, 0xb2, 0x88, 0x22, 0x27, 0x73, ++ 0x90, 0xec, 0xf2, 0x1a, 0x04, 0xe6, 0x30, 0x85, ++ 0x8b, 0xb6, 0x56, 0x52, 0xb5, 0xb1, 0x80, 0x16 ++}; ++static const u8 enc_output118[] __initconst = { ++ 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xe5, 0x8a, 0xf3, 0x69, 0xae, 0x0f, 0xc2, 0xf5, ++ 0x29, 0x0b, 0x7c, 0x7f, 0x65, 0x9c, 0x97, 0x04, ++ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xbb, 0xc1, 0x0b, 0x84, 0x94, 0x8b, 0x5c, 0x8c, ++ 0x2f, 0x0c, 0x72, 0x11, 0x3e, 0xa9, 0xbd, 0x04, ++ 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xbb, 0xc1, 0x0b, 0x84, 0x94, 0x8b, 0x5c, 0x8c, ++ 0x2f, 0x0c, 0x72, 0x11, 0x3e, 0xa9, 0xbd, 0x04, ++ 0x73, 0xeb, 0x27, 0x24, 0xb5, 0xc4, 0x05, 0xf0, ++ 0x4d, 0x00, 0xd0, 0xf1, 0x58, 0x40, 0xa1, 0xc1 ++}; ++static const u8 enc_assoc118[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce118[] __initconst = { ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x4c, 0x2d, 0x52 ++}; ++static const u8 enc_key118[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++static const struct chacha20poly1305_testvec ++chacha20poly1305_enc_vectors[] __initconst = { ++ { enc_input001, enc_output001, enc_assoc001, enc_nonce001, enc_key001, ++ sizeof(enc_input001), sizeof(enc_assoc001), sizeof(enc_nonce001) }, ++ { enc_input002, enc_output002, enc_assoc002, enc_nonce002, enc_key002, ++ sizeof(enc_input002), sizeof(enc_assoc002), sizeof(enc_nonce002) }, ++ { enc_input003, enc_output003, enc_assoc003, enc_nonce003, enc_key003, ++ sizeof(enc_input003), sizeof(enc_assoc003), sizeof(enc_nonce003) }, ++ { enc_input004, enc_output004, enc_assoc004, enc_nonce004, enc_key004, ++ sizeof(enc_input004), sizeof(enc_assoc004), sizeof(enc_nonce004) }, ++ { enc_input005, enc_output005, enc_assoc005, enc_nonce005, enc_key005, ++ sizeof(enc_input005), sizeof(enc_assoc005), sizeof(enc_nonce005) }, ++ { enc_input006, enc_output006, enc_assoc006, enc_nonce006, enc_key006, ++ sizeof(enc_input006), sizeof(enc_assoc006), sizeof(enc_nonce006) }, ++ { enc_input007, enc_output007, enc_assoc007, enc_nonce007, enc_key007, ++ sizeof(enc_input007), sizeof(enc_assoc007), sizeof(enc_nonce007) }, ++ { enc_input008, enc_output008, enc_assoc008, enc_nonce008, enc_key008, ++ sizeof(enc_input008), sizeof(enc_assoc008), sizeof(enc_nonce008) }, ++ { enc_input009, enc_output009, enc_assoc009, enc_nonce009, enc_key009, ++ sizeof(enc_input009), sizeof(enc_assoc009), sizeof(enc_nonce009) }, ++ { enc_input010, enc_output010, enc_assoc010, enc_nonce010, enc_key010, ++ sizeof(enc_input010), sizeof(enc_assoc010), sizeof(enc_nonce010) }, ++ { enc_input011, enc_output011, enc_assoc011, enc_nonce011, enc_key011, ++ sizeof(enc_input011), sizeof(enc_assoc011), sizeof(enc_nonce011) }, ++ { enc_input012, enc_output012, enc_assoc012, enc_nonce012, enc_key012, ++ sizeof(enc_input012), sizeof(enc_assoc012), sizeof(enc_nonce012) }, ++ { enc_input053, enc_output053, enc_assoc053, enc_nonce053, enc_key053, ++ sizeof(enc_input053), sizeof(enc_assoc053), sizeof(enc_nonce053) }, ++ { enc_input054, enc_output054, enc_assoc054, enc_nonce054, enc_key054, ++ sizeof(enc_input054), sizeof(enc_assoc054), sizeof(enc_nonce054) }, ++ { enc_input055, enc_output055, enc_assoc055, enc_nonce055, enc_key055, ++ sizeof(enc_input055), sizeof(enc_assoc055), sizeof(enc_nonce055) }, ++ { enc_input056, enc_output056, enc_assoc056, enc_nonce056, enc_key056, ++ sizeof(enc_input056), sizeof(enc_assoc056), sizeof(enc_nonce056) }, ++ { enc_input057, enc_output057, enc_assoc057, enc_nonce057, enc_key057, ++ sizeof(enc_input057), sizeof(enc_assoc057), sizeof(enc_nonce057) }, ++ { enc_input058, enc_output058, enc_assoc058, enc_nonce058, enc_key058, ++ sizeof(enc_input058), sizeof(enc_assoc058), sizeof(enc_nonce058) }, ++ { enc_input059, enc_output059, enc_assoc059, enc_nonce059, enc_key059, ++ sizeof(enc_input059), sizeof(enc_assoc059), sizeof(enc_nonce059) }, ++ { enc_input060, enc_output060, enc_assoc060, enc_nonce060, enc_key060, ++ sizeof(enc_input060), sizeof(enc_assoc060), sizeof(enc_nonce060) }, ++ { enc_input061, enc_output061, enc_assoc061, enc_nonce061, enc_key061, ++ sizeof(enc_input061), sizeof(enc_assoc061), sizeof(enc_nonce061) }, ++ { enc_input062, enc_output062, enc_assoc062, enc_nonce062, enc_key062, ++ sizeof(enc_input062), sizeof(enc_assoc062), sizeof(enc_nonce062) }, ++ { enc_input063, enc_output063, enc_assoc063, enc_nonce063, enc_key063, ++ sizeof(enc_input063), sizeof(enc_assoc063), sizeof(enc_nonce063) }, ++ { enc_input064, enc_output064, enc_assoc064, enc_nonce064, enc_key064, ++ sizeof(enc_input064), sizeof(enc_assoc064), sizeof(enc_nonce064) }, ++ { enc_input065, enc_output065, enc_assoc065, enc_nonce065, enc_key065, ++ sizeof(enc_input065), sizeof(enc_assoc065), sizeof(enc_nonce065) }, ++ { enc_input066, enc_output066, enc_assoc066, enc_nonce066, enc_key066, ++ sizeof(enc_input066), sizeof(enc_assoc066), sizeof(enc_nonce066) }, ++ { enc_input067, enc_output067, enc_assoc067, enc_nonce067, enc_key067, ++ sizeof(enc_input067), sizeof(enc_assoc067), sizeof(enc_nonce067) }, ++ { enc_input068, enc_output068, enc_assoc068, enc_nonce068, enc_key068, ++ sizeof(enc_input068), sizeof(enc_assoc068), sizeof(enc_nonce068) }, ++ { enc_input069, enc_output069, enc_assoc069, enc_nonce069, enc_key069, ++ sizeof(enc_input069), sizeof(enc_assoc069), sizeof(enc_nonce069) }, ++ { enc_input070, enc_output070, enc_assoc070, enc_nonce070, enc_key070, ++ sizeof(enc_input070), sizeof(enc_assoc070), sizeof(enc_nonce070) }, ++ { enc_input071, enc_output071, enc_assoc071, enc_nonce071, enc_key071, ++ sizeof(enc_input071), sizeof(enc_assoc071), sizeof(enc_nonce071) }, ++ { enc_input072, enc_output072, enc_assoc072, enc_nonce072, enc_key072, ++ sizeof(enc_input072), sizeof(enc_assoc072), sizeof(enc_nonce072) }, ++ { enc_input073, enc_output073, enc_assoc073, enc_nonce073, enc_key073, ++ sizeof(enc_input073), sizeof(enc_assoc073), sizeof(enc_nonce073) }, ++ { enc_input076, enc_output076, enc_assoc076, enc_nonce076, enc_key076, ++ sizeof(enc_input076), sizeof(enc_assoc076), sizeof(enc_nonce076) }, ++ { enc_input077, enc_output077, enc_assoc077, enc_nonce077, enc_key077, ++ sizeof(enc_input077), sizeof(enc_assoc077), sizeof(enc_nonce077) }, ++ { enc_input078, enc_output078, enc_assoc078, enc_nonce078, enc_key078, ++ sizeof(enc_input078), sizeof(enc_assoc078), sizeof(enc_nonce078) }, ++ { enc_input079, enc_output079, enc_assoc079, enc_nonce079, enc_key079, ++ sizeof(enc_input079), sizeof(enc_assoc079), sizeof(enc_nonce079) }, ++ { enc_input080, enc_output080, enc_assoc080, enc_nonce080, enc_key080, ++ sizeof(enc_input080), sizeof(enc_assoc080), sizeof(enc_nonce080) }, ++ { enc_input081, enc_output081, enc_assoc081, enc_nonce081, enc_key081, ++ sizeof(enc_input081), sizeof(enc_assoc081), sizeof(enc_nonce081) }, ++ { enc_input082, enc_output082, enc_assoc082, enc_nonce082, enc_key082, ++ sizeof(enc_input082), sizeof(enc_assoc082), sizeof(enc_nonce082) }, ++ { enc_input083, enc_output083, enc_assoc083, enc_nonce083, enc_key083, ++ sizeof(enc_input083), sizeof(enc_assoc083), sizeof(enc_nonce083) }, ++ { enc_input084, enc_output084, enc_assoc084, enc_nonce084, enc_key084, ++ sizeof(enc_input084), sizeof(enc_assoc084), sizeof(enc_nonce084) }, ++ { enc_input085, enc_output085, enc_assoc085, enc_nonce085, enc_key085, ++ sizeof(enc_input085), sizeof(enc_assoc085), sizeof(enc_nonce085) }, ++ { enc_input093, enc_output093, enc_assoc093, enc_nonce093, enc_key093, ++ sizeof(enc_input093), sizeof(enc_assoc093), sizeof(enc_nonce093) }, ++ { enc_input094, enc_output094, enc_assoc094, enc_nonce094, enc_key094, ++ sizeof(enc_input094), sizeof(enc_assoc094), sizeof(enc_nonce094) }, ++ { enc_input095, enc_output095, enc_assoc095, enc_nonce095, enc_key095, ++ sizeof(enc_input095), sizeof(enc_assoc095), sizeof(enc_nonce095) }, ++ { enc_input096, enc_output096, enc_assoc096, enc_nonce096, enc_key096, ++ sizeof(enc_input096), sizeof(enc_assoc096), sizeof(enc_nonce096) }, ++ { enc_input097, enc_output097, enc_assoc097, enc_nonce097, enc_key097, ++ sizeof(enc_input097), sizeof(enc_assoc097), sizeof(enc_nonce097) }, ++ { enc_input098, enc_output098, enc_assoc098, enc_nonce098, enc_key098, ++ sizeof(enc_input098), sizeof(enc_assoc098), sizeof(enc_nonce098) }, ++ { enc_input099, enc_output099, enc_assoc099, enc_nonce099, enc_key099, ++ sizeof(enc_input099), sizeof(enc_assoc099), sizeof(enc_nonce099) }, ++ { enc_input100, enc_output100, enc_assoc100, enc_nonce100, enc_key100, ++ sizeof(enc_input100), sizeof(enc_assoc100), sizeof(enc_nonce100) }, ++ { enc_input101, enc_output101, enc_assoc101, enc_nonce101, enc_key101, ++ sizeof(enc_input101), sizeof(enc_assoc101), sizeof(enc_nonce101) }, ++ { enc_input102, enc_output102, enc_assoc102, enc_nonce102, enc_key102, ++ sizeof(enc_input102), sizeof(enc_assoc102), sizeof(enc_nonce102) }, ++ { enc_input103, enc_output103, enc_assoc103, enc_nonce103, enc_key103, ++ sizeof(enc_input103), sizeof(enc_assoc103), sizeof(enc_nonce103) }, ++ { enc_input104, enc_output104, enc_assoc104, enc_nonce104, enc_key104, ++ sizeof(enc_input104), sizeof(enc_assoc104), sizeof(enc_nonce104) }, ++ { enc_input105, enc_output105, enc_assoc105, enc_nonce105, enc_key105, ++ sizeof(enc_input105), sizeof(enc_assoc105), sizeof(enc_nonce105) }, ++ { enc_input106, enc_output106, enc_assoc106, enc_nonce106, enc_key106, ++ sizeof(enc_input106), sizeof(enc_assoc106), sizeof(enc_nonce106) }, ++ { enc_input107, enc_output107, enc_assoc107, enc_nonce107, enc_key107, ++ sizeof(enc_input107), sizeof(enc_assoc107), sizeof(enc_nonce107) }, ++ { enc_input108, enc_output108, enc_assoc108, enc_nonce108, enc_key108, ++ sizeof(enc_input108), sizeof(enc_assoc108), sizeof(enc_nonce108) }, ++ { enc_input109, enc_output109, enc_assoc109, enc_nonce109, enc_key109, ++ sizeof(enc_input109), sizeof(enc_assoc109), sizeof(enc_nonce109) }, ++ { enc_input110, enc_output110, enc_assoc110, enc_nonce110, enc_key110, ++ sizeof(enc_input110), sizeof(enc_assoc110), sizeof(enc_nonce110) }, ++ { enc_input111, enc_output111, enc_assoc111, enc_nonce111, enc_key111, ++ sizeof(enc_input111), sizeof(enc_assoc111), sizeof(enc_nonce111) }, ++ { enc_input112, enc_output112, enc_assoc112, enc_nonce112, enc_key112, ++ sizeof(enc_input112), sizeof(enc_assoc112), sizeof(enc_nonce112) }, ++ { enc_input113, enc_output113, enc_assoc113, enc_nonce113, enc_key113, ++ sizeof(enc_input113), sizeof(enc_assoc113), sizeof(enc_nonce113) }, ++ { enc_input114, enc_output114, enc_assoc114, enc_nonce114, enc_key114, ++ sizeof(enc_input114), sizeof(enc_assoc114), sizeof(enc_nonce114) }, ++ { enc_input115, enc_output115, enc_assoc115, enc_nonce115, enc_key115, ++ sizeof(enc_input115), sizeof(enc_assoc115), sizeof(enc_nonce115) }, ++ { enc_input116, enc_output116, enc_assoc116, enc_nonce116, enc_key116, ++ sizeof(enc_input116), sizeof(enc_assoc116), sizeof(enc_nonce116) }, ++ { enc_input117, enc_output117, enc_assoc117, enc_nonce117, enc_key117, ++ sizeof(enc_input117), sizeof(enc_assoc117), sizeof(enc_nonce117) }, ++ { enc_input118, enc_output118, enc_assoc118, enc_nonce118, enc_key118, ++ sizeof(enc_input118), sizeof(enc_assoc118), sizeof(enc_nonce118) } ++}; ++ ++static const u8 dec_input001[] __initconst = { ++ 0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4, ++ 0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd, ++ 0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89, ++ 0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2, ++ 0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee, ++ 0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0, ++ 0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00, ++ 0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf, ++ 0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce, ++ 0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81, ++ 0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd, ++ 0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55, ++ 0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61, ++ 0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38, ++ 0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0, ++ 0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4, ++ 0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46, ++ 0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9, ++ 0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e, ++ 0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e, ++ 0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15, ++ 0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a, ++ 0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea, ++ 0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a, ++ 0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99, ++ 0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e, ++ 0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10, ++ 0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10, ++ 0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94, ++ 0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30, ++ 0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf, ++ 0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29, ++ 0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70, ++ 0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, ++ 0x22, 0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f, ++ 0x38 ++}; ++static const u8 dec_output001[] __initconst = { ++ 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, ++ 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, ++ 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66, ++ 0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69, ++ 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, ++ 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, ++ 0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d, ++ 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e, ++ 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, ++ 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, ++ 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, ++ 0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, ++ 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64, ++ 0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65, ++ 0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, ++ 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, ++ 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, ++ 0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, ++ 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, ++ 0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, ++ 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, ++ 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72, ++ 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, ++ 0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, ++ 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, ++ 0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, ++ 0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, ++ 0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20, ++ 0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, ++ 0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, ++ 0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80, ++ 0x9d ++}; ++static const u8 dec_assoc001[] __initconst = { ++ 0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x4e, 0x91 ++}; ++static const u8 dec_nonce001[] __initconst = { ++ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ++}; ++static const u8 dec_key001[] __initconst = { ++ 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, ++ 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, ++ 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, ++ 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 ++}; ++ ++static const u8 dec_input002[] __initconst = { ++ 0xea, 0xe0, 0x1e, 0x9e, 0x2c, 0x91, 0xaa, 0xe1, ++ 0xdb, 0x5d, 0x99, 0x3f, 0x8a, 0xf7, 0x69, 0x92 ++}; ++static const u8 dec_output002[] __initconst = { }; ++static const u8 dec_assoc002[] __initconst = { }; ++static const u8 dec_nonce002[] __initconst = { ++ 0xca, 0xbf, 0x33, 0x71, 0x32, 0x45, 0x77, 0x8e ++}; ++static const u8 dec_key002[] __initconst = { ++ 0x4c, 0xf5, 0x96, 0x83, 0x38, 0xe6, 0xae, 0x7f, ++ 0x2d, 0x29, 0x25, 0x76, 0xd5, 0x75, 0x27, 0x86, ++ 0x91, 0x9a, 0x27, 0x7a, 0xfb, 0x46, 0xc5, 0xef, ++ 0x94, 0x81, 0x79, 0x57, 0x14, 0x59, 0x40, 0x68 ++}; ++ ++static const u8 dec_input003[] __initconst = { ++ 0xdd, 0x6b, 0x3b, 0x82, 0xce, 0x5a, 0xbd, 0xd6, ++ 0xa9, 0x35, 0x83, 0xd8, 0x8c, 0x3d, 0x85, 0x77 ++}; ++static const u8 dec_output003[] __initconst = { }; ++static const u8 dec_assoc003[] __initconst = { ++ 0x33, 0x10, 0x41, 0x12, 0x1f, 0xf3, 0xd2, 0x6b ++}; ++static const u8 dec_nonce003[] __initconst = { ++ 0x3d, 0x86, 0xb5, 0x6b, 0xc8, 0xa3, 0x1f, 0x1d ++}; ++static const u8 dec_key003[] __initconst = { ++ 0x2d, 0xb0, 0x5d, 0x40, 0xc8, 0xed, 0x44, 0x88, ++ 0x34, 0xd1, 0x13, 0xaf, 0x57, 0xa1, 0xeb, 0x3a, ++ 0x2a, 0x80, 0x51, 0x36, 0xec, 0x5b, 0xbc, 0x08, ++ 0x93, 0x84, 0x21, 0xb5, 0x13, 0x88, 0x3c, 0x0d ++}; ++ ++static const u8 dec_input004[] __initconst = { ++ 0xb7, 0x1b, 0xb0, 0x73, 0x59, 0xb0, 0x84, 0xb2, ++ 0x6d, 0x8e, 0xab, 0x94, 0x31, 0xa1, 0xae, 0xac, ++ 0x89 ++}; ++static const u8 dec_output004[] __initconst = { ++ 0xa4 ++}; ++static const u8 dec_assoc004[] __initconst = { ++ 0x6a, 0xe2, 0xad, 0x3f, 0x88, 0x39, 0x5a, 0x40 ++}; ++static const u8 dec_nonce004[] __initconst = { ++ 0xd2, 0x32, 0x1f, 0x29, 0x28, 0xc6, 0xc4, 0xc4 ++}; ++static const u8 dec_key004[] __initconst = { ++ 0x4b, 0x28, 0x4b, 0xa3, 0x7b, 0xbe, 0xe9, 0xf8, ++ 0x31, 0x80, 0x82, 0xd7, 0xd8, 0xe8, 0xb5, 0xa1, ++ 0xe2, 0x18, 0x18, 0x8a, 0x9c, 0xfa, 0xa3, 0x3d, ++ 0x25, 0x71, 0x3e, 0x40, 0xbc, 0x54, 0x7a, 0x3e ++}; ++ ++static const u8 dec_input005[] __initconst = { ++ 0xbf, 0xe1, 0x5b, 0x0b, 0xdb, 0x6b, 0xf5, 0x5e, ++ 0x6c, 0x5d, 0x84, 0x44, 0x39, 0x81, 0xc1, 0x9c, ++ 0xac ++}; ++static const u8 dec_output005[] __initconst = { ++ 0x2d ++}; ++static const u8 dec_assoc005[] __initconst = { }; ++static const u8 dec_nonce005[] __initconst = { ++ 0x20, 0x1c, 0xaa, 0x5f, 0x9c, 0xbf, 0x92, 0x30 ++}; ++static const u8 dec_key005[] __initconst = { ++ 0x66, 0xca, 0x9c, 0x23, 0x2a, 0x4b, 0x4b, 0x31, ++ 0x0e, 0x92, 0x89, 0x8b, 0xf4, 0x93, 0xc7, 0x87, ++ 0x98, 0xa3, 0xd8, 0x39, 0xf8, 0xf4, 0xa7, 0x01, ++ 0xc0, 0x2e, 0x0a, 0xa6, 0x7e, 0x5a, 0x78, 0x87 ++}; ++ ++static const u8 dec_input006[] __initconst = { ++ 0x8b, 0x06, 0xd3, 0x31, 0xb0, 0x93, 0x45, 0xb1, ++ 0x75, 0x6e, 0x26, 0xf9, 0x67, 0xbc, 0x90, 0x15, ++ 0x81, 0x2c, 0xb5, 0xf0, 0xc6, 0x2b, 0xc7, 0x8c, ++ 0x56, 0xd1, 0xbf, 0x69, 0x6c, 0x07, 0xa0, 0xda, ++ 0x65, 0x27, 0xc9, 0x90, 0x3d, 0xef, 0x4b, 0x11, ++ 0x0f, 0x19, 0x07, 0xfd, 0x29, 0x92, 0xd9, 0xc8, ++ 0xf7, 0x99, 0x2e, 0x4a, 0xd0, 0xb8, 0x2c, 0xdc, ++ 0x93, 0xf5, 0x9e, 0x33, 0x78, 0xd1, 0x37, 0xc3, ++ 0x66, 0xd7, 0x5e, 0xbc, 0x44, 0xbf, 0x53, 0xa5, ++ 0xbc, 0xc4, 0xcb, 0x7b, 0x3a, 0x8e, 0x7f, 0x02, ++ 0xbd, 0xbb, 0xe7, 0xca, 0xa6, 0x6c, 0x6b, 0x93, ++ 0x21, 0x93, 0x10, 0x61, 0xe7, 0x69, 0xd0, 0x78, ++ 0xf3, 0x07, 0x5a, 0x1a, 0x8f, 0x73, 0xaa, 0xb1, ++ 0x4e, 0xd3, 0xda, 0x4f, 0xf3, 0x32, 0xe1, 0x66, ++ 0x3e, 0x6c, 0xc6, 0x13, 0xba, 0x06, 0x5b, 0xfc, ++ 0x6a, 0xe5, 0x6f, 0x60, 0xfb, 0x07, 0x40, 0xb0, ++ 0x8c, 0x9d, 0x84, 0x43, 0x6b, 0xc1, 0xf7, 0x8d, ++ 0x8d, 0x31, 0xf7, 0x7a, 0x39, 0x4d, 0x8f, 0x9a, ++ 0xeb ++}; ++static const u8 dec_output006[] __initconst = { ++ 0x33, 0x2f, 0x94, 0xc1, 0xa4, 0xef, 0xcc, 0x2a, ++ 0x5b, 0xa6, 0xe5, 0x8f, 0x1d, 0x40, 0xf0, 0x92, ++ 0x3c, 0xd9, 0x24, 0x11, 0xa9, 0x71, 0xf9, 0x37, ++ 0x14, 0x99, 0xfa, 0xbe, 0xe6, 0x80, 0xde, 0x50, ++ 0xc9, 0x96, 0xd4, 0xb0, 0xec, 0x9e, 0x17, 0xec, ++ 0xd2, 0x5e, 0x72, 0x99, 0xfc, 0x0a, 0xe1, 0xcb, ++ 0x48, 0xd2, 0x85, 0xdd, 0x2f, 0x90, 0xe0, 0x66, ++ 0x3b, 0xe6, 0x20, 0x74, 0xbe, 0x23, 0x8f, 0xcb, ++ 0xb4, 0xe4, 0xda, 0x48, 0x40, 0xa6, 0xd1, 0x1b, ++ 0xc7, 0x42, 0xce, 0x2f, 0x0c, 0xa6, 0x85, 0x6e, ++ 0x87, 0x37, 0x03, 0xb1, 0x7c, 0x25, 0x96, 0xa3, ++ 0x05, 0xd8, 0xb0, 0xf4, 0xed, 0xea, 0xc2, 0xf0, ++ 0x31, 0x98, 0x6c, 0xd1, 0x14, 0x25, 0xc0, 0xcb, ++ 0x01, 0x74, 0xd0, 0x82, 0xf4, 0x36, 0xf5, 0x41, ++ 0xd5, 0xdc, 0xca, 0xc5, 0xbb, 0x98, 0xfe, 0xfc, ++ 0x69, 0x21, 0x70, 0xd8, 0xa4, 0x4b, 0xc8, 0xde, ++ 0x8f ++}; ++static const u8 dec_assoc006[] __initconst = { ++ 0x70, 0xd3, 0x33, 0xf3, 0x8b, 0x18, 0x0b ++}; ++static const u8 dec_nonce006[] __initconst = { ++ 0xdf, 0x51, 0x84, 0x82, 0x42, 0x0c, 0x75, 0x9c ++}; ++static const u8 dec_key006[] __initconst = { ++ 0x68, 0x7b, 0x8d, 0x8e, 0xe3, 0xc4, 0xdd, 0xae, ++ 0xdf, 0x72, 0x7f, 0x53, 0x72, 0x25, 0x1e, 0x78, ++ 0x91, 0xcb, 0x69, 0x76, 0x1f, 0x49, 0x93, 0xf9, ++ 0x6f, 0x21, 0xcc, 0x39, 0x9c, 0xad, 0xb1, 0x01 ++}; ++ ++static const u8 dec_input007[] __initconst = { ++ 0x85, 0x04, 0xc2, 0xed, 0x8d, 0xfd, 0x97, 0x5c, ++ 0xd2, 0xb7, 0xe2, 0xc1, 0x6b, 0xa3, 0xba, 0xf8, ++ 0xc9, 0x50, 0xc3, 0xc6, 0xa5, 0xe3, 0xa4, 0x7c, ++ 0xc3, 0x23, 0x49, 0x5e, 0xa9, 0xb9, 0x32, 0xeb, ++ 0x8a, 0x7c, 0xca, 0xe5, 0xec, 0xfb, 0x7c, 0xc0, ++ 0xcb, 0x7d, 0xdc, 0x2c, 0x9d, 0x92, 0x55, 0x21, ++ 0x0a, 0xc8, 0x43, 0x63, 0x59, 0x0a, 0x31, 0x70, ++ 0x82, 0x67, 0x41, 0x03, 0xf8, 0xdf, 0xf2, 0xac, ++ 0xa7, 0x02, 0xd4, 0xd5, 0x8a, 0x2d, 0xc8, 0x99, ++ 0x19, 0x66, 0xd0, 0xf6, 0x88, 0x2c, 0x77, 0xd9, ++ 0xd4, 0x0d, 0x6c, 0xbd, 0x98, 0xde, 0xe7, 0x7f, ++ 0xad, 0x7e, 0x8a, 0xfb, 0xe9, 0x4b, 0xe5, 0xf7, ++ 0xe5, 0x50, 0xa0, 0x90, 0x3f, 0xd6, 0x22, 0x53, ++ 0xe3, 0xfe, 0x1b, 0xcc, 0x79, 0x3b, 0xec, 0x12, ++ 0x47, 0x52, 0xa7, 0xd6, 0x04, 0xe3, 0x52, 0xe6, ++ 0x93, 0x90, 0x91, 0x32, 0x73, 0x79, 0xb8, 0xd0, ++ 0x31, 0xde, 0x1f, 0x9f, 0x2f, 0x05, 0x38, 0x54, ++ 0x2f, 0x35, 0x04, 0x39, 0xe0, 0xa7, 0xba, 0xc6, ++ 0x52, 0xf6, 0x37, 0x65, 0x4c, 0x07, 0xa9, 0x7e, ++ 0xb3, 0x21, 0x6f, 0x74, 0x8c, 0xc9, 0xde, 0xdb, ++ 0x65, 0x1b, 0x9b, 0xaa, 0x60, 0xb1, 0x03, 0x30, ++ 0x6b, 0xb2, 0x03, 0xc4, 0x1c, 0x04, 0xf8, 0x0f, ++ 0x64, 0xaf, 0x46, 0xe4, 0x65, 0x99, 0x49, 0xe2, ++ 0xea, 0xce, 0x78, 0x00, 0xd8, 0x8b, 0xd5, 0x2e, ++ 0xcf, 0xfc, 0x40, 0x49, 0xe8, 0x58, 0xdc, 0x34, ++ 0x9c, 0x8c, 0x61, 0xbf, 0x0a, 0x8e, 0xec, 0x39, ++ 0xa9, 0x30, 0x05, 0x5a, 0xd2, 0x56, 0x01, 0xc7, ++ 0xda, 0x8f, 0x4e, 0xbb, 0x43, 0xa3, 0x3a, 0xf9, ++ 0x15, 0x2a, 0xd0, 0xa0, 0x7a, 0x87, 0x34, 0x82, ++ 0xfe, 0x8a, 0xd1, 0x2d, 0x5e, 0xc7, 0xbf, 0x04, ++ 0x53, 0x5f, 0x3b, 0x36, 0xd4, 0x25, 0x5c, 0x34, ++ 0x7a, 0x8d, 0xd5, 0x05, 0xce, 0x72, 0xca, 0xef, ++ 0x7a, 0x4b, 0xbc, 0xb0, 0x10, 0x5c, 0x96, 0x42, ++ 0x3a, 0x00, 0x98, 0xcd, 0x15, 0xe8, 0xb7, 0x53 ++}; ++static const u8 dec_output007[] __initconst = { ++ 0x9b, 0x18, 0xdb, 0xdd, 0x9a, 0x0f, 0x3e, 0xa5, ++ 0x15, 0x17, 0xde, 0xdf, 0x08, 0x9d, 0x65, 0x0a, ++ 0x67, 0x30, 0x12, 0xe2, 0x34, 0x77, 0x4b, 0xc1, ++ 0xd9, 0xc6, 0x1f, 0xab, 0xc6, 0x18, 0x50, 0x17, ++ 0xa7, 0x9d, 0x3c, 0xa6, 0xc5, 0x35, 0x8c, 0x1c, ++ 0xc0, 0xa1, 0x7c, 0x9f, 0x03, 0x89, 0xca, 0xe1, ++ 0xe6, 0xe9, 0xd4, 0xd3, 0x88, 0xdb, 0xb4, 0x51, ++ 0x9d, 0xec, 0xb4, 0xfc, 0x52, 0xee, 0x6d, 0xf1, ++ 0x75, 0x42, 0xc6, 0xfd, 0xbd, 0x7a, 0x8e, 0x86, ++ 0xfc, 0x44, 0xb3, 0x4f, 0xf3, 0xea, 0x67, 0x5a, ++ 0x41, 0x13, 0xba, 0xb0, 0xdc, 0xe1, 0xd3, 0x2a, ++ 0x7c, 0x22, 0xb3, 0xca, 0xac, 0x6a, 0x37, 0x98, ++ 0x3e, 0x1d, 0x40, 0x97, 0xf7, 0x9b, 0x1d, 0x36, ++ 0x6b, 0xb3, 0x28, 0xbd, 0x60, 0x82, 0x47, 0x34, ++ 0xaa, 0x2f, 0x7d, 0xe9, 0xa8, 0x70, 0x81, 0x57, ++ 0xd4, 0xb9, 0x77, 0x0a, 0x9d, 0x29, 0xa7, 0x84, ++ 0x52, 0x4f, 0xc2, 0x4a, 0x40, 0x3b, 0x3c, 0xd4, ++ 0xc9, 0x2a, 0xdb, 0x4a, 0x53, 0xc4, 0xbe, 0x80, ++ 0xe9, 0x51, 0x7f, 0x8f, 0xc7, 0xa2, 0xce, 0x82, ++ 0x5c, 0x91, 0x1e, 0x74, 0xd9, 0xd0, 0xbd, 0xd5, ++ 0xf3, 0xfd, 0xda, 0x4d, 0x25, 0xb4, 0xbb, 0x2d, ++ 0xac, 0x2f, 0x3d, 0x71, 0x85, 0x7b, 0xcf, 0x3c, ++ 0x7b, 0x3e, 0x0e, 0x22, 0x78, 0x0c, 0x29, 0xbf, ++ 0xe4, 0xf4, 0x57, 0xb3, 0xcb, 0x49, 0xa0, 0xfc, ++ 0x1e, 0x05, 0x4e, 0x16, 0xbc, 0xd5, 0xa8, 0xa3, ++ 0xee, 0x05, 0x35, 0xc6, 0x7c, 0xab, 0x60, 0x14, ++ 0x55, 0x1a, 0x8e, 0xc5, 0x88, 0x5d, 0xd5, 0x81, ++ 0xc2, 0x81, 0xa5, 0xc4, 0x60, 0xdb, 0xaf, 0x77, ++ 0x91, 0xe1, 0xce, 0xa2, 0x7e, 0x7f, 0x42, 0xe3, ++ 0xb0, 0x13, 0x1c, 0x1f, 0x25, 0x60, 0x21, 0xe2, ++ 0x40, 0x5f, 0x99, 0xb7, 0x73, 0xec, 0x9b, 0x2b, ++ 0xf0, 0x65, 0x11, 0xc8, 0xd0, 0x0a, 0x9f, 0xd3 ++}; ++static const u8 dec_assoc007[] __initconst = { }; ++static const u8 dec_nonce007[] __initconst = { ++ 0xde, 0x7b, 0xef, 0xc3, 0x65, 0x1b, 0x68, 0xb0 ++}; ++static const u8 dec_key007[] __initconst = { ++ 0x8d, 0xb8, 0x91, 0x48, 0xf0, 0xe7, 0x0a, 0xbd, ++ 0xf9, 0x3f, 0xcd, 0xd9, 0xa0, 0x1e, 0x42, 0x4c, ++ 0xe7, 0xde, 0x25, 0x3d, 0xa3, 0xd7, 0x05, 0x80, ++ 0x8d, 0xf2, 0x82, 0xac, 0x44, 0x16, 0x51, 0x01 ++}; ++ ++static const u8 dec_input008[] __initconst = { ++ 0x14, 0xf6, 0x41, 0x37, 0xa6, 0xd4, 0x27, 0xcd, ++ 0xdb, 0x06, 0x3e, 0x9a, 0x4e, 0xab, 0xd5, 0xb1, ++ 0x1e, 0x6b, 0xd2, 0xbc, 0x11, 0xf4, 0x28, 0x93, ++ 0x63, 0x54, 0xef, 0xbb, 0x5e, 0x1d, 0x3a, 0x1d, ++ 0x37, 0x3c, 0x0a, 0x6c, 0x1e, 0xc2, 0xd1, 0x2c, ++ 0xb5, 0xa3, 0xb5, 0x7b, 0xb8, 0x8f, 0x25, 0xa6, ++ 0x1b, 0x61, 0x1c, 0xec, 0x28, 0x58, 0x26, 0xa4, ++ 0xa8, 0x33, 0x28, 0x25, 0x5c, 0x45, 0x05, 0xe5, ++ 0x6c, 0x99, 0xe5, 0x45, 0xc4, 0xa2, 0x03, 0x84, ++ 0x03, 0x73, 0x1e, 0x8c, 0x49, 0xac, 0x20, 0xdd, ++ 0x8d, 0xb3, 0xc4, 0xf5, 0xe7, 0x4f, 0xf1, 0xed, ++ 0xa1, 0x98, 0xde, 0xa4, 0x96, 0xdd, 0x2f, 0xab, ++ 0xab, 0x97, 0xcf, 0x3e, 0xd2, 0x9e, 0xb8, 0x13, ++ 0x07, 0x28, 0x29, 0x19, 0xaf, 0xfd, 0xf2, 0x49, ++ 0x43, 0xea, 0x49, 0x26, 0x91, 0xc1, 0x07, 0xd6, ++ 0xbb, 0x81, 0x75, 0x35, 0x0d, 0x24, 0x7f, 0xc8, ++ 0xda, 0xd4, 0xb7, 0xeb, 0xe8, 0x5c, 0x09, 0xa2, ++ 0x2f, 0xdc, 0x28, 0x7d, 0x3a, 0x03, 0xfa, 0x94, ++ 0xb5, 0x1d, 0x17, 0x99, 0x36, 0xc3, 0x1c, 0x18, ++ 0x34, 0xe3, 0x9f, 0xf5, 0x55, 0x7c, 0xb0, 0x60, ++ 0x9d, 0xff, 0xac, 0xd4, 0x61, 0xf2, 0xad, 0xf8, ++ 0xce, 0xc7, 0xbe, 0x5c, 0xd2, 0x95, 0xa8, 0x4b, ++ 0x77, 0x13, 0x19, 0x59, 0x26, 0xc9, 0xb7, 0x8f, ++ 0x6a, 0xcb, 0x2d, 0x37, 0x91, 0xea, 0x92, 0x9c, ++ 0x94, 0x5b, 0xda, 0x0b, 0xce, 0xfe, 0x30, 0x20, ++ 0xf8, 0x51, 0xad, 0xf2, 0xbe, 0xe7, 0xc7, 0xff, ++ 0xb3, 0x33, 0x91, 0x6a, 0xc9, 0x1a, 0x41, 0xc9, ++ 0x0f, 0xf3, 0x10, 0x0e, 0xfd, 0x53, 0xff, 0x6c, ++ 0x16, 0x52, 0xd9, 0xf3, 0xf7, 0x98, 0x2e, 0xc9, ++ 0x07, 0x31, 0x2c, 0x0c, 0x72, 0xd7, 0xc5, 0xc6, ++ 0x08, 0x2a, 0x7b, 0xda, 0xbd, 0x7e, 0x02, 0xea, ++ 0x1a, 0xbb, 0xf2, 0x04, 0x27, 0x61, 0x28, 0x8e, ++ 0xf5, 0x04, 0x03, 0x1f, 0x4c, 0x07, 0x55, 0x82, ++ 0xec, 0x1e, 0xd7, 0x8b, 0x2f, 0x65, 0x56, 0xd1, ++ 0xd9, 0x1e, 0x3c, 0xe9, 0x1f, 0x5e, 0x98, 0x70, ++ 0x38, 0x4a, 0x8c, 0x49, 0xc5, 0x43, 0xa0, 0xa1, ++ 0x8b, 0x74, 0x9d, 0x4c, 0x62, 0x0d, 0x10, 0x0c, ++ 0xf4, 0x6c, 0x8f, 0xe0, 0xaa, 0x9a, 0x8d, 0xb7, ++ 0xe0, 0xbe, 0x4c, 0x87, 0xf1, 0x98, 0x2f, 0xcc, ++ 0xed, 0xc0, 0x52, 0x29, 0xdc, 0x83, 0xf8, 0xfc, ++ 0x2c, 0x0e, 0xa8, 0x51, 0x4d, 0x80, 0x0d, 0xa3, ++ 0xfe, 0xd8, 0x37, 0xe7, 0x41, 0x24, 0xfc, 0xfb, ++ 0x75, 0xe3, 0x71, 0x7b, 0x57, 0x45, 0xf5, 0x97, ++ 0x73, 0x65, 0x63, 0x14, 0x74, 0xb8, 0x82, 0x9f, ++ 0xf8, 0x60, 0x2f, 0x8a, 0xf2, 0x4e, 0xf1, 0x39, ++ 0xda, 0x33, 0x91, 0xf8, 0x36, 0xe0, 0x8d, 0x3f, ++ 0x1f, 0x3b, 0x56, 0xdc, 0xa0, 0x8f, 0x3c, 0x9d, ++ 0x71, 0x52, 0xa7, 0xb8, 0xc0, 0xa5, 0xc6, 0xa2, ++ 0x73, 0xda, 0xf4, 0x4b, 0x74, 0x5b, 0x00, 0x3d, ++ 0x99, 0xd7, 0x96, 0xba, 0xe6, 0xe1, 0xa6, 0x96, ++ 0x38, 0xad, 0xb3, 0xc0, 0xd2, 0xba, 0x91, 0x6b, ++ 0xf9, 0x19, 0xdd, 0x3b, 0xbe, 0xbe, 0x9c, 0x20, ++ 0x50, 0xba, 0xa1, 0xd0, 0xce, 0x11, 0xbd, 0x95, ++ 0xd8, 0xd1, 0xdd, 0x33, 0x85, 0x74, 0xdc, 0xdb, ++ 0x66, 0x76, 0x44, 0xdc, 0x03, 0x74, 0x48, 0x35, ++ 0x98, 0xb1, 0x18, 0x47, 0x94, 0x7d, 0xff, 0x62, ++ 0xe4, 0x58, 0x78, 0xab, 0xed, 0x95, 0x36, 0xd9, ++ 0x84, 0x91, 0x82, 0x64, 0x41, 0xbb, 0x58, 0xe6, ++ 0x1c, 0x20, 0x6d, 0x15, 0x6b, 0x13, 0x96, 0xe8, ++ 0x35, 0x7f, 0xdc, 0x40, 0x2c, 0xe9, 0xbc, 0x8a, ++ 0x4f, 0x92, 0xec, 0x06, 0x2d, 0x50, 0xdf, 0x93, ++ 0x5d, 0x65, 0x5a, 0xa8, 0xfc, 0x20, 0x50, 0x14, ++ 0xa9, 0x8a, 0x7e, 0x1d, 0x08, 0x1f, 0xe2, 0x99, ++ 0xd0, 0xbe, 0xfb, 0x3a, 0x21, 0x9d, 0xad, 0x86, ++ 0x54, 0xfd, 0x0d, 0x98, 0x1c, 0x5a, 0x6f, 0x1f, ++ 0x9a, 0x40, 0xcd, 0xa2, 0xff, 0x6a, 0xf1, 0x54 ++}; ++static const u8 dec_output008[] __initconst = { ++ 0xc3, 0x09, 0x94, 0x62, 0xe6, 0x46, 0x2e, 0x10, ++ 0xbe, 0x00, 0xe4, 0xfc, 0xf3, 0x40, 0xa3, 0xe2, ++ 0x0f, 0xc2, 0x8b, 0x28, 0xdc, 0xba, 0xb4, 0x3c, ++ 0xe4, 0x21, 0x58, 0x61, 0xcd, 0x8b, 0xcd, 0xfb, ++ 0xac, 0x94, 0xa1, 0x45, 0xf5, 0x1c, 0xe1, 0x12, ++ 0xe0, 0x3b, 0x67, 0x21, 0x54, 0x5e, 0x8c, 0xaa, ++ 0xcf, 0xdb, 0xb4, 0x51, 0xd4, 0x13, 0xda, 0xe6, ++ 0x83, 0x89, 0xb6, 0x92, 0xe9, 0x21, 0x76, 0xa4, ++ 0x93, 0x7d, 0x0e, 0xfd, 0x96, 0x36, 0x03, 0x91, ++ 0x43, 0x5c, 0x92, 0x49, 0x62, 0x61, 0x7b, 0xeb, ++ 0x43, 0x89, 0xb8, 0x12, 0x20, 0x43, 0xd4, 0x47, ++ 0x06, 0x84, 0xee, 0x47, 0xe9, 0x8a, 0x73, 0x15, ++ 0x0f, 0x72, 0xcf, 0xed, 0xce, 0x96, 0xb2, 0x7f, ++ 0x21, 0x45, 0x76, 0xeb, 0x26, 0x28, 0x83, 0x6a, ++ 0xad, 0xaa, 0xa6, 0x81, 0xd8, 0x55, 0xb1, 0xa3, ++ 0x85, 0xb3, 0x0c, 0xdf, 0xf1, 0x69, 0x2d, 0x97, ++ 0x05, 0x2a, 0xbc, 0x7c, 0x7b, 0x25, 0xf8, 0x80, ++ 0x9d, 0x39, 0x25, 0xf3, 0x62, 0xf0, 0x66, 0x5e, ++ 0xf4, 0xa0, 0xcf, 0xd8, 0xfd, 0x4f, 0xb1, 0x1f, ++ 0x60, 0x3a, 0x08, 0x47, 0xaf, 0xe1, 0xf6, 0x10, ++ 0x77, 0x09, 0xa7, 0x27, 0x8f, 0x9a, 0x97, 0x5a, ++ 0x26, 0xfa, 0xfe, 0x41, 0x32, 0x83, 0x10, 0xe0, ++ 0x1d, 0xbf, 0x64, 0x0d, 0xf4, 0x1c, 0x32, 0x35, ++ 0xe5, 0x1b, 0x36, 0xef, 0xd4, 0x4a, 0x93, 0x4d, ++ 0x00, 0x7c, 0xec, 0x02, 0x07, 0x8b, 0x5d, 0x7d, ++ 0x1b, 0x0e, 0xd1, 0xa6, 0xa5, 0x5d, 0x7d, 0x57, ++ 0x88, 0xa8, 0xcc, 0x81, 0xb4, 0x86, 0x4e, 0xb4, ++ 0x40, 0xe9, 0x1d, 0xc3, 0xb1, 0x24, 0x3e, 0x7f, ++ 0xcc, 0x8a, 0x24, 0x9b, 0xdf, 0x6d, 0xf0, 0x39, ++ 0x69, 0x3e, 0x4c, 0xc0, 0x96, 0xe4, 0x13, 0xda, ++ 0x90, 0xda, 0xf4, 0x95, 0x66, 0x8b, 0x17, 0x17, ++ 0xfe, 0x39, 0x43, 0x25, 0xaa, 0xda, 0xa0, 0x43, ++ 0x3c, 0xb1, 0x41, 0x02, 0xa3, 0xf0, 0xa7, 0x19, ++ 0x59, 0xbc, 0x1d, 0x7d, 0x6c, 0x6d, 0x91, 0x09, ++ 0x5c, 0xb7, 0x5b, 0x01, 0xd1, 0x6f, 0x17, 0x21, ++ 0x97, 0xbf, 0x89, 0x71, 0xa5, 0xb0, 0x6e, 0x07, ++ 0x45, 0xfd, 0x9d, 0xea, 0x07, 0xf6, 0x7a, 0x9f, ++ 0x10, 0x18, 0x22, 0x30, 0x73, 0xac, 0xd4, 0x6b, ++ 0x72, 0x44, 0xed, 0xd9, 0x19, 0x9b, 0x2d, 0x4a, ++ 0x41, 0xdd, 0xd1, 0x85, 0x5e, 0x37, 0x19, 0xed, ++ 0xd2, 0x15, 0x8f, 0x5e, 0x91, 0xdb, 0x33, 0xf2, ++ 0xe4, 0xdb, 0xff, 0x98, 0xfb, 0xa3, 0xb5, 0xca, ++ 0x21, 0x69, 0x08, 0xe7, 0x8a, 0xdf, 0x90, 0xff, ++ 0x3e, 0xe9, 0x20, 0x86, 0x3c, 0xe9, 0xfc, 0x0b, ++ 0xfe, 0x5c, 0x61, 0xaa, 0x13, 0x92, 0x7f, 0x7b, ++ 0xec, 0xe0, 0x6d, 0xa8, 0x23, 0x22, 0xf6, 0x6b, ++ 0x77, 0xc4, 0xfe, 0x40, 0x07, 0x3b, 0xb6, 0xf6, ++ 0x8e, 0x5f, 0xd4, 0xb9, 0xb7, 0x0f, 0x21, 0x04, ++ 0xef, 0x83, 0x63, 0x91, 0x69, 0x40, 0xa3, 0x48, ++ 0x5c, 0xd2, 0x60, 0xf9, 0x4f, 0x6c, 0x47, 0x8b, ++ 0x3b, 0xb1, 0x9f, 0x8e, 0xee, 0x16, 0x8a, 0x13, ++ 0xfc, 0x46, 0x17, 0xc3, 0xc3, 0x32, 0x56, 0xf8, ++ 0x3c, 0x85, 0x3a, 0xb6, 0x3e, 0xaa, 0x89, 0x4f, ++ 0xb3, 0xdf, 0x38, 0xfd, 0xf1, 0xe4, 0x3a, 0xc0, ++ 0xe6, 0x58, 0xb5, 0x8f, 0xc5, 0x29, 0xa2, 0x92, ++ 0x4a, 0xb6, 0xa0, 0x34, 0x7f, 0xab, 0xb5, 0x8a, ++ 0x90, 0xa1, 0xdb, 0x4d, 0xca, 0xb6, 0x2c, 0x41, ++ 0x3c, 0xf7, 0x2b, 0x21, 0xc3, 0xfd, 0xf4, 0x17, ++ 0x5c, 0xb5, 0x33, 0x17, 0x68, 0x2b, 0x08, 0x30, ++ 0xf3, 0xf7, 0x30, 0x3c, 0x96, 0xe6, 0x6a, 0x20, ++ 0x97, 0xe7, 0x4d, 0x10, 0x5f, 0x47, 0x5f, 0x49, ++ 0x96, 0x09, 0xf0, 0x27, 0x91, 0xc8, 0xf8, 0x5a, ++ 0x2e, 0x79, 0xb5, 0xe2, 0xb8, 0xe8, 0xb9, 0x7b, ++ 0xd5, 0x10, 0xcb, 0xff, 0x5d, 0x14, 0x73, 0xf3 ++}; ++static const u8 dec_assoc008[] __initconst = { }; ++static const u8 dec_nonce008[] __initconst = { ++ 0x0e, 0x0d, 0x57, 0xbb, 0x7b, 0x40, 0x54, 0x02 ++}; ++static const u8 dec_key008[] __initconst = { ++ 0xf2, 0xaa, 0x4f, 0x99, 0xfd, 0x3e, 0xa8, 0x53, ++ 0xc1, 0x44, 0xe9, 0x81, 0x18, 0xdc, 0xf5, 0xf0, ++ 0x3e, 0x44, 0x15, 0x59, 0xe0, 0xc5, 0x44, 0x86, ++ 0xc3, 0x91, 0xa8, 0x75, 0xc0, 0x12, 0x46, 0xba ++}; ++ ++static const u8 dec_input009[] __initconst = { ++ 0xfd, 0x81, 0x8d, 0xd0, 0x3d, 0xb4, 0xd5, 0xdf, ++ 0xd3, 0x42, 0x47, 0x5a, 0x6d, 0x19, 0x27, 0x66, ++ 0x4b, 0x2e, 0x0c, 0x27, 0x9c, 0x96, 0x4c, 0x72, ++ 0x02, 0xa3, 0x65, 0xc3, 0xb3, 0x6f, 0x2e, 0xbd, ++ 0x63, 0x8a, 0x4a, 0x5d, 0x29, 0xa2, 0xd0, 0x28, ++ 0x48, 0xc5, 0x3d, 0x98, 0xa3, 0xbc, 0xe0, 0xbe, ++ 0x3b, 0x3f, 0xe6, 0x8a, 0xa4, 0x7f, 0x53, 0x06, ++ 0xfa, 0x7f, 0x27, 0x76, 0x72, 0x31, 0xa1, 0xf5, ++ 0xd6, 0x0c, 0x52, 0x47, 0xba, 0xcd, 0x4f, 0xd7, ++ 0xeb, 0x05, 0x48, 0x0d, 0x7c, 0x35, 0x4a, 0x09, ++ 0xc9, 0x76, 0x71, 0x02, 0xa3, 0xfb, 0xb7, 0x1a, ++ 0x65, 0xb7, 0xed, 0x98, 0xc6, 0x30, 0x8a, 0x00, ++ 0xae, 0xa1, 0x31, 0xe5, 0xb5, 0x9e, 0x6d, 0x62, ++ 0xda, 0xda, 0x07, 0x0f, 0x38, 0x38, 0xd3, 0xcb, ++ 0xc1, 0xb0, 0xad, 0xec, 0x72, 0xec, 0xb1, 0xa2, ++ 0x7b, 0x59, 0xf3, 0x3d, 0x2b, 0xef, 0xcd, 0x28, ++ 0x5b, 0x83, 0xcc, 0x18, 0x91, 0x88, 0xb0, 0x2e, ++ 0xf9, 0x29, 0x31, 0x18, 0xf9, 0x4e, 0xe9, 0x0a, ++ 0x91, 0x92, 0x9f, 0xae, 0x2d, 0xad, 0xf4, 0xe6, ++ 0x1a, 0xe2, 0xa4, 0xee, 0x47, 0x15, 0xbf, 0x83, ++ 0x6e, 0xd7, 0x72, 0x12, 0x3b, 0x2d, 0x24, 0xe9, ++ 0xb2, 0x55, 0xcb, 0x3c, 0x10, 0xf0, 0x24, 0x8a, ++ 0x4a, 0x02, 0xea, 0x90, 0x25, 0xf0, 0xb4, 0x79, ++ 0x3a, 0xef, 0x6e, 0xf5, 0x52, 0xdf, 0xb0, 0x0a, ++ 0xcd, 0x24, 0x1c, 0xd3, 0x2e, 0x22, 0x74, 0xea, ++ 0x21, 0x6f, 0xe9, 0xbd, 0xc8, 0x3e, 0x36, 0x5b, ++ 0x19, 0xf1, 0xca, 0x99, 0x0a, 0xb4, 0xa7, 0x52, ++ 0x1a, 0x4e, 0xf2, 0xad, 0x8d, 0x56, 0x85, 0xbb, ++ 0x64, 0x89, 0xba, 0x26, 0xf9, 0xc7, 0xe1, 0x89, ++ 0x19, 0x22, 0x77, 0xc3, 0xa8, 0xfc, 0xff, 0xad, ++ 0xfe, 0xb9, 0x48, 0xae, 0x12, 0x30, 0x9f, 0x19, ++ 0xfb, 0x1b, 0xef, 0x14, 0x87, 0x8a, 0x78, 0x71, ++ 0xf3, 0xf4, 0xb7, 0x00, 0x9c, 0x1d, 0xb5, 0x3d, ++ 0x49, 0x00, 0x0c, 0x06, 0xd4, 0x50, 0xf9, 0x54, ++ 0x45, 0xb2, 0x5b, 0x43, 0xdb, 0x6d, 0xcf, 0x1a, ++ 0xe9, 0x7a, 0x7a, 0xcf, 0xfc, 0x8a, 0x4e, 0x4d, ++ 0x0b, 0x07, 0x63, 0x28, 0xd8, 0xe7, 0x08, 0x95, ++ 0xdf, 0xa6, 0x72, 0x93, 0x2e, 0xbb, 0xa0, 0x42, ++ 0x89, 0x16, 0xf1, 0xd9, 0x0c, 0xf9, 0xa1, 0x16, ++ 0xfd, 0xd9, 0x03, 0xb4, 0x3b, 0x8a, 0xf5, 0xf6, ++ 0xe7, 0x6b, 0x2e, 0x8e, 0x4c, 0x3d, 0xe2, 0xaf, ++ 0x08, 0x45, 0x03, 0xff, 0x09, 0xb6, 0xeb, 0x2d, ++ 0xc6, 0x1b, 0x88, 0x94, 0xac, 0x3e, 0xf1, 0x9f, ++ 0x0e, 0x0e, 0x2b, 0xd5, 0x00, 0x4d, 0x3f, 0x3b, ++ 0x53, 0xae, 0xaf, 0x1c, 0x33, 0x5f, 0x55, 0x6e, ++ 0x8d, 0xaf, 0x05, 0x7a, 0x10, 0x34, 0xc9, 0xf4, ++ 0x66, 0xcb, 0x62, 0x12, 0xa6, 0xee, 0xe8, 0x1c, ++ 0x5d, 0x12, 0x86, 0xdb, 0x6f, 0x1c, 0x33, 0xc4, ++ 0x1c, 0xda, 0x82, 0x2d, 0x3b, 0x59, 0xfe, 0xb1, ++ 0xa4, 0x59, 0x41, 0x86, 0xd0, 0xef, 0xae, 0xfb, ++ 0xda, 0x6d, 0x11, 0xb8, 0xca, 0xe9, 0x6e, 0xff, ++ 0xf7, 0xa9, 0xd9, 0x70, 0x30, 0xfc, 0x53, 0xe2, ++ 0xd7, 0xa2, 0x4e, 0xc7, 0x91, 0xd9, 0x07, 0x06, ++ 0xaa, 0xdd, 0xb0, 0x59, 0x28, 0x1d, 0x00, 0x66, ++ 0xc5, 0x54, 0xc2, 0xfc, 0x06, 0xda, 0x05, 0x90, ++ 0x52, 0x1d, 0x37, 0x66, 0xee, 0xf0, 0xb2, 0x55, ++ 0x8a, 0x5d, 0xd2, 0x38, 0x86, 0x94, 0x9b, 0xfc, ++ 0x10, 0x4c, 0xa1, 0xb9, 0x64, 0x3e, 0x44, 0xb8, ++ 0x5f, 0xb0, 0x0c, 0xec, 0xe0, 0xc9, 0xe5, 0x62, ++ 0x75, 0x3f, 0x09, 0xd5, 0xf5, 0xd9, 0x26, 0xba, ++ 0x9e, 0xd2, 0xf4, 0xb9, 0x48, 0x0a, 0xbc, 0xa2, ++ 0xd6, 0x7c, 0x36, 0x11, 0x7d, 0x26, 0x81, 0x89, ++ 0xcf, 0xa4, 0xad, 0x73, 0x0e, 0xee, 0xcc, 0x06, ++ 0xa9, 0xdb, 0xb1, 0xfd, 0xfb, 0x09, 0x7f, 0x90, ++ 0x42, 0x37, 0x2f, 0xe1, 0x9c, 0x0f, 0x6f, 0xcf, ++ 0x43, 0xb5, 0xd9, 0x90, 0xe1, 0x85, 0xf5, 0xa8, ++ 0xae ++}; ++static const u8 dec_output009[] __initconst = { ++ 0xe6, 0xc3, 0xdb, 0x63, 0x55, 0x15, 0xe3, 0x5b, ++ 0xb7, 0x4b, 0x27, 0x8b, 0x5a, 0xdd, 0xc2, 0xe8, ++ 0x3a, 0x6b, 0xd7, 0x81, 0x96, 0x35, 0x97, 0xca, ++ 0xd7, 0x68, 0xe8, 0xef, 0xce, 0xab, 0xda, 0x09, ++ 0x6e, 0xd6, 0x8e, 0xcb, 0x55, 0xb5, 0xe1, 0xe5, ++ 0x57, 0xfd, 0xc4, 0xe3, 0xe0, 0x18, 0x4f, 0x85, ++ 0xf5, 0x3f, 0x7e, 0x4b, 0x88, 0xc9, 0x52, 0x44, ++ 0x0f, 0xea, 0xaf, 0x1f, 0x71, 0x48, 0x9f, 0x97, ++ 0x6d, 0xb9, 0x6f, 0x00, 0xa6, 0xde, 0x2b, 0x77, ++ 0x8b, 0x15, 0xad, 0x10, 0xa0, 0x2b, 0x7b, 0x41, ++ 0x90, 0x03, 0x2d, 0x69, 0xae, 0xcc, 0x77, 0x7c, ++ 0xa5, 0x9d, 0x29, 0x22, 0xc2, 0xea, 0xb4, 0x00, ++ 0x1a, 0xd2, 0x7a, 0x98, 0x8a, 0xf9, 0xf7, 0x82, ++ 0xb0, 0xab, 0xd8, 0xa6, 0x94, 0x8d, 0x58, 0x2f, ++ 0x01, 0x9e, 0x00, 0x20, 0xfc, 0x49, 0xdc, 0x0e, ++ 0x03, 0xe8, 0x45, 0x10, 0xd6, 0xa8, 0xda, 0x55, ++ 0x10, 0x9a, 0xdf, 0x67, 0x22, 0x8b, 0x43, 0xab, ++ 0x00, 0xbb, 0x02, 0xc8, 0xdd, 0x7b, 0x97, 0x17, ++ 0xd7, 0x1d, 0x9e, 0x02, 0x5e, 0x48, 0xde, 0x8e, ++ 0xcf, 0x99, 0x07, 0x95, 0x92, 0x3c, 0x5f, 0x9f, ++ 0xc5, 0x8a, 0xc0, 0x23, 0xaa, 0xd5, 0x8c, 0x82, ++ 0x6e, 0x16, 0x92, 0xb1, 0x12, 0x17, 0x07, 0xc3, ++ 0xfb, 0x36, 0xf5, 0x6c, 0x35, 0xd6, 0x06, 0x1f, ++ 0x9f, 0xa7, 0x94, 0xa2, 0x38, 0x63, 0x9c, 0xb0, ++ 0x71, 0xb3, 0xa5, 0xd2, 0xd8, 0xba, 0x9f, 0x08, ++ 0x01, 0xb3, 0xff, 0x04, 0x97, 0x73, 0x45, 0x1b, ++ 0xd5, 0xa9, 0x9c, 0x80, 0xaf, 0x04, 0x9a, 0x85, ++ 0xdb, 0x32, 0x5b, 0x5d, 0x1a, 0xc1, 0x36, 0x28, ++ 0x10, 0x79, 0xf1, 0x3c, 0xbf, 0x1a, 0x41, 0x5c, ++ 0x4e, 0xdf, 0xb2, 0x7c, 0x79, 0x3b, 0x7a, 0x62, ++ 0x3d, 0x4b, 0xc9, 0x9b, 0x2a, 0x2e, 0x7c, 0xa2, ++ 0xb1, 0x11, 0x98, 0xa7, 0x34, 0x1a, 0x00, 0xf3, ++ 0xd1, 0xbc, 0x18, 0x22, 0xba, 0x02, 0x56, 0x62, ++ 0x31, 0x10, 0x11, 0x6d, 0xe0, 0x54, 0x9d, 0x40, ++ 0x1f, 0x26, 0x80, 0x41, 0xca, 0x3f, 0x68, 0x0f, ++ 0x32, 0x1d, 0x0a, 0x8e, 0x79, 0xd8, 0xa4, 0x1b, ++ 0x29, 0x1c, 0x90, 0x8e, 0xc5, 0xe3, 0xb4, 0x91, ++ 0x37, 0x9a, 0x97, 0x86, 0x99, 0xd5, 0x09, 0xc5, ++ 0xbb, 0xa3, 0x3f, 0x21, 0x29, 0x82, 0x14, 0x5c, ++ 0xab, 0x25, 0xfb, 0xf2, 0x4f, 0x58, 0x26, 0xd4, ++ 0x83, 0xaa, 0x66, 0x89, 0x67, 0x7e, 0xc0, 0x49, ++ 0xe1, 0x11, 0x10, 0x7f, 0x7a, 0xda, 0x29, 0x04, ++ 0xff, 0xf0, 0xcb, 0x09, 0x7c, 0x9d, 0xfa, 0x03, ++ 0x6f, 0x81, 0x09, 0x31, 0x60, 0xfb, 0x08, 0xfa, ++ 0x74, 0xd3, 0x64, 0x44, 0x7c, 0x55, 0x85, 0xec, ++ 0x9c, 0x6e, 0x25, 0xb7, 0x6c, 0xc5, 0x37, 0xb6, ++ 0x83, 0x87, 0x72, 0x95, 0x8b, 0x9d, 0xe1, 0x69, ++ 0x5c, 0x31, 0x95, 0x42, 0xa6, 0x2c, 0xd1, 0x36, ++ 0x47, 0x1f, 0xec, 0x54, 0xab, 0xa2, 0x1c, 0xd8, ++ 0x00, 0xcc, 0xbc, 0x0d, 0x65, 0xe2, 0x67, 0xbf, ++ 0xbc, 0xea, 0xee, 0x9e, 0xe4, 0x36, 0x95, 0xbe, ++ 0x73, 0xd9, 0xa6, 0xd9, 0x0f, 0xa0, 0xcc, 0x82, ++ 0x76, 0x26, 0xad, 0x5b, 0x58, 0x6c, 0x4e, 0xab, ++ 0x29, 0x64, 0xd3, 0xd9, 0xa9, 0x08, 0x8c, 0x1d, ++ 0xa1, 0x4f, 0x80, 0xd8, 0x3f, 0x94, 0xfb, 0xd3, ++ 0x7b, 0xfc, 0xd1, 0x2b, 0xc3, 0x21, 0xeb, 0xe5, ++ 0x1c, 0x84, 0x23, 0x7f, 0x4b, 0xfa, 0xdb, 0x34, ++ 0x18, 0xa2, 0xc2, 0xe5, 0x13, 0xfe, 0x6c, 0x49, ++ 0x81, 0xd2, 0x73, 0xe7, 0xe2, 0xd7, 0xe4, 0x4f, ++ 0x4b, 0x08, 0x6e, 0xb1, 0x12, 0x22, 0x10, 0x9d, ++ 0xac, 0x51, 0x1e, 0x17, 0xd9, 0x8a, 0x0b, 0x42, ++ 0x88, 0x16, 0x81, 0x37, 0x7c, 0x6a, 0xf7, 0xef, ++ 0x2d, 0xe3, 0xd9, 0xf8, 0x5f, 0xe0, 0x53, 0x27, ++ 0x74, 0xb9, 0xe2, 0xd6, 0x1c, 0x80, 0x2c, 0x52, ++ 0x65 ++}; ++static const u8 dec_assoc009[] __initconst = { ++ 0x5a, 0x27, 0xff, 0xeb, 0xdf, 0x84, 0xb2, 0x9e, ++ 0xef ++}; ++static const u8 dec_nonce009[] __initconst = { ++ 0xef, 0x2d, 0x63, 0xee, 0x6b, 0x80, 0x8b, 0x78 ++}; ++static const u8 dec_key009[] __initconst = { ++ 0xea, 0xbc, 0x56, 0x99, 0xe3, 0x50, 0xff, 0xc5, ++ 0xcc, 0x1a, 0xd7, 0xc1, 0x57, 0x72, 0xea, 0x86, ++ 0x5b, 0x89, 0x88, 0x61, 0x3d, 0x2f, 0x9b, 0xb2, ++ 0xe7, 0x9c, 0xec, 0x74, 0x6e, 0x3e, 0xf4, 0x3b ++}; ++ ++static const u8 dec_input010[] __initconst = { ++ 0xe5, 0x26, 0xa4, 0x3d, 0xbd, 0x33, 0xd0, 0x4b, ++ 0x6f, 0x05, 0xa7, 0x6e, 0x12, 0x7a, 0xd2, 0x74, ++ 0xa6, 0xdd, 0xbd, 0x95, 0xeb, 0xf9, 0xa4, 0xf1, ++ 0x59, 0x93, 0x91, 0x70, 0xd9, 0xfe, 0x9a, 0xcd, ++ 0x53, 0x1f, 0x3a, 0xab, 0xa6, 0x7c, 0x9f, 0xa6, ++ 0x9e, 0xbd, 0x99, 0xd9, 0xb5, 0x97, 0x44, 0xd5, ++ 0x14, 0x48, 0x4d, 0x9d, 0xc0, 0xd0, 0x05, 0x96, ++ 0xeb, 0x4c, 0x78, 0x55, 0x09, 0x08, 0x01, 0x02, ++ 0x30, 0x90, 0x7b, 0x96, 0x7a, 0x7b, 0x5f, 0x30, ++ 0x41, 0x24, 0xce, 0x68, 0x61, 0x49, 0x86, 0x57, ++ 0x82, 0xdd, 0x53, 0x1c, 0x51, 0x28, 0x2b, 0x53, ++ 0x6e, 0x2d, 0xc2, 0x20, 0x4c, 0xdd, 0x8f, 0x65, ++ 0x10, 0x20, 0x50, 0xdd, 0x9d, 0x50, 0xe5, 0x71, ++ 0x40, 0x53, 0x69, 0xfc, 0x77, 0x48, 0x11, 0xb9, ++ 0xde, 0xa4, 0x8d, 0x58, 0xe4, 0xa6, 0x1a, 0x18, ++ 0x47, 0x81, 0x7e, 0xfc, 0xdd, 0xf6, 0xef, 0xce, ++ 0x2f, 0x43, 0x68, 0xd6, 0x06, 0xe2, 0x74, 0x6a, ++ 0xad, 0x90, 0xf5, 0x37, 0xf3, 0x3d, 0x82, 0x69, ++ 0x40, 0xe9, 0x6b, 0xa7, 0x3d, 0xa8, 0x1e, 0xd2, ++ 0x02, 0x7c, 0xb7, 0x9b, 0xe4, 0xda, 0x8f, 0x95, ++ 0x06, 0xc5, 0xdf, 0x73, 0xa3, 0x20, 0x9a, 0x49, ++ 0xde, 0x9c, 0xbc, 0xee, 0x14, 0x3f, 0x81, 0x5e, ++ 0xf8, 0x3b, 0x59, 0x3c, 0xe1, 0x68, 0x12, 0x5a, ++ 0x3a, 0x76, 0x3a, 0x3f, 0xf7, 0x87, 0x33, 0x0a, ++ 0x01, 0xb8, 0xd4, 0xed, 0xb6, 0xbe, 0x94, 0x5e, ++ 0x70, 0x40, 0x56, 0x67, 0x1f, 0x50, 0x44, 0x19, ++ 0xce, 0x82, 0x70, 0x10, 0x87, 0x13, 0x20, 0x0b, ++ 0x4c, 0x5a, 0xb6, 0xf6, 0xa7, 0xae, 0x81, 0x75, ++ 0x01, 0x81, 0xe6, 0x4b, 0x57, 0x7c, 0xdd, 0x6d, ++ 0xf8, 0x1c, 0x29, 0x32, 0xf7, 0xda, 0x3c, 0x2d, ++ 0xf8, 0x9b, 0x25, 0x6e, 0x00, 0xb4, 0xf7, 0x2f, ++ 0xf7, 0x04, 0xf7, 0xa1, 0x56, 0xac, 0x4f, 0x1a, ++ 0x64, 0xb8, 0x47, 0x55, 0x18, 0x7b, 0x07, 0x4d, ++ 0xbd, 0x47, 0x24, 0x80, 0x5d, 0xa2, 0x70, 0xc5, ++ 0xdd, 0x8e, 0x82, 0xd4, 0xeb, 0xec, 0xb2, 0x0c, ++ 0x39, 0xd2, 0x97, 0xc1, 0xcb, 0xeb, 0xf4, 0x77, ++ 0x59, 0xb4, 0x87, 0xef, 0xcb, 0x43, 0x2d, 0x46, ++ 0x54, 0xd1, 0xa7, 0xd7, 0x15, 0x99, 0x0a, 0x43, ++ 0xa1, 0xe0, 0x99, 0x33, 0x71, 0xc1, 0xed, 0xfe, ++ 0x72, 0x46, 0x33, 0x8e, 0x91, 0x08, 0x9f, 0xc8, ++ 0x2e, 0xca, 0xfa, 0xdc, 0x59, 0xd5, 0xc3, 0x76, ++ 0x84, 0x9f, 0xa3, 0x37, 0x68, 0xc3, 0xf0, 0x47, ++ 0x2c, 0x68, 0xdb, 0x5e, 0xc3, 0x49, 0x4c, 0xe8, ++ 0x92, 0x85, 0xe2, 0x23, 0xd3, 0x3f, 0xad, 0x32, ++ 0xe5, 0x2b, 0x82, 0xd7, 0x8f, 0x99, 0x0a, 0x59, ++ 0x5c, 0x45, 0xd9, 0xb4, 0x51, 0x52, 0xc2, 0xae, ++ 0xbf, 0x80, 0xcf, 0xc9, 0xc9, 0x51, 0x24, 0x2a, ++ 0x3b, 0x3a, 0x4d, 0xae, 0xeb, 0xbd, 0x22, 0xc3, ++ 0x0e, 0x0f, 0x59, 0x25, 0x92, 0x17, 0xe9, 0x74, ++ 0xc7, 0x8b, 0x70, 0x70, 0x36, 0x55, 0x95, 0x75, ++ 0x4b, 0xad, 0x61, 0x2b, 0x09, 0xbc, 0x82, 0xf2, ++ 0x6e, 0x94, 0x43, 0xae, 0xc3, 0xd5, 0xcd, 0x8e, ++ 0xfe, 0x5b, 0x9a, 0x88, 0x43, 0x01, 0x75, 0xb2, ++ 0x23, 0x09, 0xf7, 0x89, 0x83, 0xe7, 0xfa, 0xf9, ++ 0xb4, 0x9b, 0xf8, 0xef, 0xbd, 0x1c, 0x92, 0xc1, ++ 0xda, 0x7e, 0xfe, 0x05, 0xba, 0x5a, 0xcd, 0x07, ++ 0x6a, 0x78, 0x9e, 0x5d, 0xfb, 0x11, 0x2f, 0x79, ++ 0x38, 0xb6, 0xc2, 0x5b, 0x6b, 0x51, 0xb4, 0x71, ++ 0xdd, 0xf7, 0x2a, 0xe4, 0xf4, 0x72, 0x76, 0xad, ++ 0xc2, 0xdd, 0x64, 0x5d, 0x79, 0xb6, 0xf5, 0x7a, ++ 0x77, 0x20, 0x05, 0x3d, 0x30, 0x06, 0xd4, 0x4c, ++ 0x0a, 0x2c, 0x98, 0x5a, 0xb9, 0xd4, 0x98, 0xa9, ++ 0x3f, 0xc6, 0x12, 0xea, 0x3b, 0x4b, 0xc5, 0x79, ++ 0x64, 0x63, 0x6b, 0x09, 0x54, 0x3b, 0x14, 0x27, ++ 0xba, 0x99, 0x80, 0xc8, 0x72, 0xa8, 0x12, 0x90, ++ 0x29, 0xba, 0x40, 0x54, 0x97, 0x2b, 0x7b, 0xfe, ++ 0xeb, 0xcd, 0x01, 0x05, 0x44, 0x72, 0xdb, 0x99, ++ 0xe4, 0x61, 0xc9, 0x69, 0xd6, 0xb9, 0x28, 0xd1, ++ 0x05, 0x3e, 0xf9, 0x0b, 0x49, 0x0a, 0x49, 0xe9, ++ 0x8d, 0x0e, 0xa7, 0x4a, 0x0f, 0xaf, 0x32, 0xd0, ++ 0xe0, 0xb2, 0x3a, 0x55, 0x58, 0xfe, 0x5c, 0x28, ++ 0x70, 0x51, 0x23, 0xb0, 0x7b, 0x6a, 0x5f, 0x1e, ++ 0xb8, 0x17, 0xd7, 0x94, 0x15, 0x8f, 0xee, 0x20, ++ 0xc7, 0x42, 0x25, 0x3e, 0x9a, 0x14, 0xd7, 0x60, ++ 0x72, 0x39, 0x47, 0x48, 0xa9, 0xfe, 0xdd, 0x47, ++ 0x0a, 0xb1, 0xe6, 0x60, 0x28, 0x8c, 0x11, 0x68, ++ 0xe1, 0xff, 0xd7, 0xce, 0xc8, 0xbe, 0xb3, 0xfe, ++ 0x27, 0x30, 0x09, 0x70, 0xd7, 0xfa, 0x02, 0x33, ++ 0x3a, 0x61, 0x2e, 0xc7, 0xff, 0xa4, 0x2a, 0xa8, ++ 0x6e, 0xb4, 0x79, 0x35, 0x6d, 0x4c, 0x1e, 0x38, ++ 0xf8, 0xee, 0xd4, 0x84, 0x4e, 0x6e, 0x28, 0xa7, ++ 0xce, 0xc8, 0xc1, 0xcf, 0x80, 0x05, 0xf3, 0x04, ++ 0xef, 0xc8, 0x18, 0x28, 0x2e, 0x8d, 0x5e, 0x0c, ++ 0xdf, 0xb8, 0x5f, 0x96, 0xe8, 0xc6, 0x9c, 0x2f, ++ 0xe5, 0xa6, 0x44, 0xd7, 0xe7, 0x99, 0x44, 0x0c, ++ 0xec, 0xd7, 0x05, 0x60, 0x97, 0xbb, 0x74, 0x77, ++ 0x58, 0xd5, 0xbb, 0x48, 0xde, 0x5a, 0xb2, 0x54, ++ 0x7f, 0x0e, 0x46, 0x70, 0x6a, 0x6f, 0x78, 0xa5, ++ 0x08, 0x89, 0x05, 0x4e, 0x7e, 0xa0, 0x69, 0xb4, ++ 0x40, 0x60, 0x55, 0x77, 0x75, 0x9b, 0x19, 0xf2, ++ 0xd5, 0x13, 0x80, 0x77, 0xf9, 0x4b, 0x3f, 0x1e, ++ 0xee, 0xe6, 0x76, 0x84, 0x7b, 0x8c, 0xe5, 0x27, ++ 0xa8, 0x0a, 0x91, 0x01, 0x68, 0x71, 0x8a, 0x3f, ++ 0x06, 0xab, 0xf6, 0xa9, 0xa5, 0xe6, 0x72, 0x92, ++ 0xe4, 0x67, 0xe2, 0xa2, 0x46, 0x35, 0x84, 0x55, ++ 0x7d, 0xca, 0xa8, 0x85, 0xd0, 0xf1, 0x3f, 0xbe, ++ 0xd7, 0x34, 0x64, 0xfc, 0xae, 0xe3, 0xe4, 0x04, ++ 0x9f, 0x66, 0x02, 0xb9, 0x88, 0x10, 0xd9, 0xc4, ++ 0x4c, 0x31, 0x43, 0x7a, 0x93, 0xe2, 0x9b, 0x56, ++ 0x43, 0x84, 0xdc, 0xdc, 0xde, 0x1d, 0xa4, 0x02, ++ 0x0e, 0xc2, 0xef, 0xc3, 0xf8, 0x78, 0xd1, 0xb2, ++ 0x6b, 0x63, 0x18, 0xc9, 0xa9, 0xe5, 0x72, 0xd8, ++ 0xf3, 0xb9, 0xd1, 0x8a, 0xc7, 0x1a, 0x02, 0x27, ++ 0x20, 0x77, 0x10, 0xe5, 0xc8, 0xd4, 0x4a, 0x47, ++ 0xe5, 0xdf, 0x5f, 0x01, 0xaa, 0xb0, 0xd4, 0x10, ++ 0xbb, 0x69, 0xe3, 0x36, 0xc8, 0xe1, 0x3d, 0x43, ++ 0xfb, 0x86, 0xcd, 0xcc, 0xbf, 0xf4, 0x88, 0xe0, ++ 0x20, 0xca, 0xb7, 0x1b, 0xf1, 0x2f, 0x5c, 0xee, ++ 0xd4, 0xd3, 0xa3, 0xcc, 0xa4, 0x1e, 0x1c, 0x47, ++ 0xfb, 0xbf, 0xfc, 0xa2, 0x41, 0x55, 0x9d, 0xf6, ++ 0x5a, 0x5e, 0x65, 0x32, 0x34, 0x7b, 0x52, 0x8d, ++ 0xd5, 0xd0, 0x20, 0x60, 0x03, 0xab, 0x3f, 0x8c, ++ 0xd4, 0x21, 0xea, 0x2a, 0xd9, 0xc4, 0xd0, 0xd3, ++ 0x65, 0xd8, 0x7a, 0x13, 0x28, 0x62, 0x32, 0x4b, ++ 0x2c, 0x87, 0x93, 0xa8, 0xb4, 0x52, 0x45, 0x09, ++ 0x44, 0xec, 0xec, 0xc3, 0x17, 0xdb, 0x9a, 0x4d, ++ 0x5c, 0xa9, 0x11, 0xd4, 0x7d, 0xaf, 0x9e, 0xf1, ++ 0x2d, 0xb2, 0x66, 0xc5, 0x1d, 0xed, 0xb7, 0xcd, ++ 0x0b, 0x25, 0x5e, 0x30, 0x47, 0x3f, 0x40, 0xf4, ++ 0xa1, 0xa0, 0x00, 0x94, 0x10, 0xc5, 0x6a, 0x63, ++ 0x1a, 0xd5, 0x88, 0x92, 0x8e, 0x82, 0x39, 0x87, ++ 0x3c, 0x78, 0x65, 0x58, 0x42, 0x75, 0x5b, 0xdd, ++ 0x77, 0x3e, 0x09, 0x4e, 0x76, 0x5b, 0xe6, 0x0e, ++ 0x4d, 0x38, 0xb2, 0xc0, 0xb8, 0x95, 0x01, 0x7a, ++ 0x10, 0xe0, 0xfb, 0x07, 0xf2, 0xab, 0x2d, 0x8c, ++ 0x32, 0xed, 0x2b, 0xc0, 0x46, 0xc2, 0xf5, 0x38, ++ 0x83, 0xf0, 0x17, 0xec, 0xc1, 0x20, 0x6a, 0x9a, ++ 0x0b, 0x00, 0xa0, 0x98, 0x22, 0x50, 0x23, 0xd5, ++ 0x80, 0x6b, 0xf6, 0x1f, 0xc3, 0xcc, 0x97, 0xc9, ++ 0x24, 0x9f, 0xf3, 0xaf, 0x43, 0x14, 0xd5, 0xa0 ++}; ++static const u8 dec_output010[] __initconst = { ++ 0x42, 0x93, 0xe4, 0xeb, 0x97, 0xb0, 0x57, 0xbf, ++ 0x1a, 0x8b, 0x1f, 0xe4, 0x5f, 0x36, 0x20, 0x3c, ++ 0xef, 0x0a, 0xa9, 0x48, 0x5f, 0x5f, 0x37, 0x22, ++ 0x3a, 0xde, 0xe3, 0xae, 0xbe, 0xad, 0x07, 0xcc, ++ 0xb1, 0xf6, 0xf5, 0xf9, 0x56, 0xdd, 0xe7, 0x16, ++ 0x1e, 0x7f, 0xdf, 0x7a, 0x9e, 0x75, 0xb7, 0xc7, ++ 0xbe, 0xbe, 0x8a, 0x36, 0x04, 0xc0, 0x10, 0xf4, ++ 0x95, 0x20, 0x03, 0xec, 0xdc, 0x05, 0xa1, 0x7d, ++ 0xc4, 0xa9, 0x2c, 0x82, 0xd0, 0xbc, 0x8b, 0xc5, ++ 0xc7, 0x45, 0x50, 0xf6, 0xa2, 0x1a, 0xb5, 0x46, ++ 0x3b, 0x73, 0x02, 0xa6, 0x83, 0x4b, 0x73, 0x82, ++ 0x58, 0x5e, 0x3b, 0x65, 0x2f, 0x0e, 0xfd, 0x2b, ++ 0x59, 0x16, 0xce, 0xa1, 0x60, 0x9c, 0xe8, 0x3a, ++ 0x99, 0xed, 0x8d, 0x5a, 0xcf, 0xf6, 0x83, 0xaf, ++ 0xba, 0xd7, 0x73, 0x73, 0x40, 0x97, 0x3d, 0xca, ++ 0xef, 0x07, 0x57, 0xe6, 0xd9, 0x70, 0x0e, 0x95, ++ 0xae, 0xa6, 0x8d, 0x04, 0xcc, 0xee, 0xf7, 0x09, ++ 0x31, 0x77, 0x12, 0xa3, 0x23, 0x97, 0x62, 0xb3, ++ 0x7b, 0x32, 0xfb, 0x80, 0x14, 0x48, 0x81, 0xc3, ++ 0xe5, 0xea, 0x91, 0x39, 0x52, 0x81, 0xa2, 0x4f, ++ 0xe4, 0xb3, 0x09, 0xff, 0xde, 0x5e, 0xe9, 0x58, ++ 0x84, 0x6e, 0xf9, 0x3d, 0xdf, 0x25, 0xea, 0xad, ++ 0xae, 0xe6, 0x9a, 0xd1, 0x89, 0x55, 0xd3, 0xde, ++ 0x6c, 0x52, 0xdb, 0x70, 0xfe, 0x37, 0xce, 0x44, ++ 0x0a, 0xa8, 0x25, 0x5f, 0x92, 0xc1, 0x33, 0x4a, ++ 0x4f, 0x9b, 0x62, 0x35, 0xff, 0xce, 0xc0, 0xa9, ++ 0x60, 0xce, 0x52, 0x00, 0x97, 0x51, 0x35, 0x26, ++ 0x2e, 0xb9, 0x36, 0xa9, 0x87, 0x6e, 0x1e, 0xcc, ++ 0x91, 0x78, 0x53, 0x98, 0x86, 0x5b, 0x9c, 0x74, ++ 0x7d, 0x88, 0x33, 0xe1, 0xdf, 0x37, 0x69, 0x2b, ++ 0xbb, 0xf1, 0x4d, 0xf4, 0xd1, 0xf1, 0x39, 0x93, ++ 0x17, 0x51, 0x19, 0xe3, 0x19, 0x1e, 0x76, 0x37, ++ 0x25, 0xfb, 0x09, 0x27, 0x6a, 0xab, 0x67, 0x6f, ++ 0x14, 0x12, 0x64, 0xe7, 0xc4, 0x07, 0xdf, 0x4d, ++ 0x17, 0xbb, 0x6d, 0xe0, 0xe9, 0xb9, 0xab, 0xca, ++ 0x10, 0x68, 0xaf, 0x7e, 0xb7, 0x33, 0x54, 0x73, ++ 0x07, 0x6e, 0xf7, 0x81, 0x97, 0x9c, 0x05, 0x6f, ++ 0x84, 0x5f, 0xd2, 0x42, 0xfb, 0x38, 0xcf, 0xd1, ++ 0x2f, 0x14, 0x30, 0x88, 0x98, 0x4d, 0x5a, 0xa9, ++ 0x76, 0xd5, 0x4f, 0x3e, 0x70, 0x6c, 0x85, 0x76, ++ 0xd7, 0x01, 0xa0, 0x1a, 0xc8, 0x4e, 0xaa, 0xac, ++ 0x78, 0xfe, 0x46, 0xde, 0x6a, 0x05, 0x46, 0xa7, ++ 0x43, 0x0c, 0xb9, 0xde, 0xb9, 0x68, 0xfb, 0xce, ++ 0x42, 0x99, 0x07, 0x4d, 0x0b, 0x3b, 0x5a, 0x30, ++ 0x35, 0xa8, 0xf9, 0x3a, 0x73, 0xef, 0x0f, 0xdb, ++ 0x1e, 0x16, 0x42, 0xc4, 0xba, 0xae, 0x58, 0xaa, ++ 0xf8, 0xe5, 0x75, 0x2f, 0x1b, 0x15, 0x5c, 0xfd, ++ 0x0a, 0x97, 0xd0, 0xe4, 0x37, 0x83, 0x61, 0x5f, ++ 0x43, 0xa6, 0xc7, 0x3f, 0x38, 0x59, 0xe6, 0xeb, ++ 0xa3, 0x90, 0xc3, 0xaa, 0xaa, 0x5a, 0xd3, 0x34, ++ 0xd4, 0x17, 0xc8, 0x65, 0x3e, 0x57, 0xbc, 0x5e, ++ 0xdd, 0x9e, 0xb7, 0xf0, 0x2e, 0x5b, 0xb2, 0x1f, ++ 0x8a, 0x08, 0x0d, 0x45, 0x91, 0x0b, 0x29, 0x53, ++ 0x4f, 0x4c, 0x5a, 0x73, 0x56, 0xfe, 0xaf, 0x41, ++ 0x01, 0x39, 0x0a, 0x24, 0x3c, 0x7e, 0xbe, 0x4e, ++ 0x53, 0xf3, 0xeb, 0x06, 0x66, 0x51, 0x28, 0x1d, ++ 0xbd, 0x41, 0x0a, 0x01, 0xab, 0x16, 0x47, 0x27, ++ 0x47, 0x47, 0xf7, 0xcb, 0x46, 0x0a, 0x70, 0x9e, ++ 0x01, 0x9c, 0x09, 0xe1, 0x2a, 0x00, 0x1a, 0xd8, ++ 0xd4, 0x79, 0x9d, 0x80, 0x15, 0x8e, 0x53, 0x2a, ++ 0x65, 0x83, 0x78, 0x3e, 0x03, 0x00, 0x07, 0x12, ++ 0x1f, 0x33, 0x3e, 0x7b, 0x13, 0x37, 0xf1, 0xc3, ++ 0xef, 0xb7, 0xc1, 0x20, 0x3c, 0x3e, 0x67, 0x66, ++ 0x5d, 0x88, 0xa7, 0x7d, 0x33, 0x50, 0x77, 0xb0, ++ 0x28, 0x8e, 0xe7, 0x2c, 0x2e, 0x7a, 0xf4, 0x3c, ++ 0x8d, 0x74, 0x83, 0xaf, 0x8e, 0x87, 0x0f, 0xe4, ++ 0x50, 0xff, 0x84, 0x5c, 0x47, 0x0c, 0x6a, 0x49, ++ 0xbf, 0x42, 0x86, 0x77, 0x15, 0x48, 0xa5, 0x90, ++ 0x5d, 0x93, 0xd6, 0x2a, 0x11, 0xd5, 0xd5, 0x11, ++ 0xaa, 0xce, 0xe7, 0x6f, 0xa5, 0xb0, 0x09, 0x2c, ++ 0x8d, 0xd3, 0x92, 0xf0, 0x5a, 0x2a, 0xda, 0x5b, ++ 0x1e, 0xd5, 0x9a, 0xc4, 0xc4, 0xf3, 0x49, 0x74, ++ 0x41, 0xca, 0xe8, 0xc1, 0xf8, 0x44, 0xd6, 0x3c, ++ 0xae, 0x6c, 0x1d, 0x9a, 0x30, 0x04, 0x4d, 0x27, ++ 0x0e, 0xb1, 0x5f, 0x59, 0xa2, 0x24, 0xe8, 0xe1, ++ 0x98, 0xc5, 0x6a, 0x4c, 0xfe, 0x41, 0xd2, 0x27, ++ 0x42, 0x52, 0xe1, 0xe9, 0x7d, 0x62, 0xe4, 0x88, ++ 0x0f, 0xad, 0xb2, 0x70, 0xcb, 0x9d, 0x4c, 0x27, ++ 0x2e, 0x76, 0x1e, 0x1a, 0x63, 0x65, 0xf5, 0x3b, ++ 0xf8, 0x57, 0x69, 0xeb, 0x5b, 0x38, 0x26, 0x39, ++ 0x33, 0x25, 0x45, 0x3e, 0x91, 0xb8, 0xd8, 0xc7, ++ 0xd5, 0x42, 0xc0, 0x22, 0x31, 0x74, 0xf4, 0xbc, ++ 0x0c, 0x23, 0xf1, 0xca, 0xc1, 0x8d, 0xd7, 0xbe, ++ 0xc9, 0x62, 0xe4, 0x08, 0x1a, 0xcf, 0x36, 0xd5, ++ 0xfe, 0x55, 0x21, 0x59, 0x91, 0x87, 0x87, 0xdf, ++ 0x06, 0xdb, 0xdf, 0x96, 0x45, 0x58, 0xda, 0x05, ++ 0xcd, 0x50, 0x4d, 0xd2, 0x7d, 0x05, 0x18, 0x73, ++ 0x6a, 0x8d, 0x11, 0x85, 0xa6, 0x88, 0xe8, 0xda, ++ 0xe6, 0x30, 0x33, 0xa4, 0x89, 0x31, 0x75, 0xbe, ++ 0x69, 0x43, 0x84, 0x43, 0x50, 0x87, 0xdd, 0x71, ++ 0x36, 0x83, 0xc3, 0x78, 0x74, 0x24, 0x0a, 0xed, ++ 0x7b, 0xdb, 0xa4, 0x24, 0x0b, 0xb9, 0x7e, 0x5d, ++ 0xff, 0xde, 0xb1, 0xef, 0x61, 0x5a, 0x45, 0x33, ++ 0xf6, 0x17, 0x07, 0x08, 0x98, 0x83, 0x92, 0x0f, ++ 0x23, 0x6d, 0xe6, 0xaa, 0x17, 0x54, 0xad, 0x6a, ++ 0xc8, 0xdb, 0x26, 0xbe, 0xb8, 0xb6, 0x08, 0xfa, ++ 0x68, 0xf1, 0xd7, 0x79, 0x6f, 0x18, 0xb4, 0x9e, ++ 0x2d, 0x3f, 0x1b, 0x64, 0xaf, 0x8d, 0x06, 0x0e, ++ 0x49, 0x28, 0xe0, 0x5d, 0x45, 0x68, 0x13, 0x87, ++ 0xfa, 0xde, 0x40, 0x7b, 0xd2, 0xc3, 0x94, 0xd5, ++ 0xe1, 0xd9, 0xc2, 0xaf, 0x55, 0x89, 0xeb, 0xb4, ++ 0x12, 0x59, 0xa8, 0xd4, 0xc5, 0x29, 0x66, 0x38, ++ 0xe6, 0xac, 0x22, 0x22, 0xd9, 0x64, 0x9b, 0x34, ++ 0x0a, 0x32, 0x9f, 0xc2, 0xbf, 0x17, 0x6c, 0x3f, ++ 0x71, 0x7a, 0x38, 0x6b, 0x98, 0xfb, 0x49, 0x36, ++ 0x89, 0xc9, 0xe2, 0xd6, 0xc7, 0x5d, 0xd0, 0x69, ++ 0x5f, 0x23, 0x35, 0xc9, 0x30, 0xe2, 0xfd, 0x44, ++ 0x58, 0x39, 0xd7, 0x97, 0xfb, 0x5c, 0x00, 0xd5, ++ 0x4f, 0x7a, 0x1a, 0x95, 0x8b, 0x62, 0x4b, 0xce, ++ 0xe5, 0x91, 0x21, 0x7b, 0x30, 0x00, 0xd6, 0xdd, ++ 0x6d, 0x02, 0x86, 0x49, 0x0f, 0x3c, 0x1a, 0x27, ++ 0x3c, 0xd3, 0x0e, 0x71, 0xf2, 0xff, 0xf5, 0x2f, ++ 0x87, 0xac, 0x67, 0x59, 0x81, 0xa3, 0xf7, 0xf8, ++ 0xd6, 0x11, 0x0c, 0x84, 0xa9, 0x03, 0xee, 0x2a, ++ 0xc4, 0xf3, 0x22, 0xab, 0x7c, 0xe2, 0x25, 0xf5, ++ 0x67, 0xa3, 0xe4, 0x11, 0xe0, 0x59, 0xb3, 0xca, ++ 0x87, 0xa0, 0xae, 0xc9, 0xa6, 0x62, 0x1b, 0x6e, ++ 0x4d, 0x02, 0x6b, 0x07, 0x9d, 0xfd, 0xd0, 0x92, ++ 0x06, 0xe1, 0xb2, 0x9a, 0x4a, 0x1f, 0x1f, 0x13, ++ 0x49, 0x99, 0x97, 0x08, 0xde, 0x7f, 0x98, 0xaf, ++ 0x51, 0x98, 0xee, 0x2c, 0xcb, 0xf0, 0x0b, 0xc6, ++ 0xb6, 0xb7, 0x2d, 0x9a, 0xb1, 0xac, 0xa6, 0xe3, ++ 0x15, 0x77, 0x9d, 0x6b, 0x1a, 0xe4, 0xfc, 0x8b, ++ 0xf2, 0x17, 0x59, 0x08, 0x04, 0x58, 0x81, 0x9d, ++ 0x1b, 0x1b, 0x69, 0x55, 0xc2, 0xb4, 0x3c, 0x1f, ++ 0x50, 0xf1, 0x7f, 0x77, 0x90, 0x4c, 0x66, 0x40, ++ 0x5a, 0xc0, 0x33, 0x1f, 0xcb, 0x05, 0x6d, 0x5c, ++ 0x06, 0x87, 0x52, 0xa2, 0x8f, 0x26, 0xd5, 0x4f ++}; ++static const u8 dec_assoc010[] __initconst = { ++ 0xd2, 0xa1, 0x70, 0xdb, 0x7a, 0xf8, 0xfa, 0x27, ++ 0xba, 0x73, 0x0f, 0xbf, 0x3d, 0x1e, 0x82, 0xb2 ++}; ++static const u8 dec_nonce010[] __initconst = { ++ 0xdb, 0x92, 0x0f, 0x7f, 0x17, 0x54, 0x0c, 0x30 ++}; ++static const u8 dec_key010[] __initconst = { ++ 0x47, 0x11, 0xeb, 0x86, 0x2b, 0x2c, 0xab, 0x44, ++ 0x34, 0xda, 0x7f, 0x57, 0x03, 0x39, 0x0c, 0xaf, ++ 0x2c, 0x14, 0xfd, 0x65, 0x23, 0xe9, 0x8e, 0x74, ++ 0xd5, 0x08, 0x68, 0x08, 0xe7, 0xb4, 0x72, 0xd7 ++}; ++ ++static const u8 dec_input011[] __initconst = { ++ 0x6a, 0xfc, 0x4b, 0x25, 0xdf, 0xc0, 0xe4, 0xe8, ++ 0x17, 0x4d, 0x4c, 0xc9, 0x7e, 0xde, 0x3a, 0xcc, ++ 0x3c, 0xba, 0x6a, 0x77, 0x47, 0xdb, 0xe3, 0x74, ++ 0x7a, 0x4d, 0x5f, 0x8d, 0x37, 0x55, 0x80, 0x73, ++ 0x90, 0x66, 0x5d, 0x3a, 0x7d, 0x5d, 0x86, 0x5e, ++ 0x8d, 0xfd, 0x83, 0xff, 0x4e, 0x74, 0x6f, 0xf9, ++ 0xe6, 0x70, 0x17, 0x70, 0x3e, 0x96, 0xa7, 0x7e, ++ 0xcb, 0xab, 0x8f, 0x58, 0x24, 0x9b, 0x01, 0xfd, ++ 0xcb, 0xe6, 0x4d, 0x9b, 0xf0, 0x88, 0x94, 0x57, ++ 0x66, 0xef, 0x72, 0x4c, 0x42, 0x6e, 0x16, 0x19, ++ 0x15, 0xea, 0x70, 0x5b, 0xac, 0x13, 0xdb, 0x9f, ++ 0x18, 0xe2, 0x3c, 0x26, 0x97, 0xbc, 0xdc, 0x45, ++ 0x8c, 0x6c, 0x24, 0x69, 0x9c, 0xf7, 0x65, 0x1e, ++ 0x18, 0x59, 0x31, 0x7c, 0xe4, 0x73, 0xbc, 0x39, ++ 0x62, 0xc6, 0x5c, 0x9f, 0xbf, 0xfa, 0x90, 0x03, ++ 0xc9, 0x72, 0x26, 0xb6, 0x1b, 0xc2, 0xb7, 0x3f, ++ 0xf2, 0x13, 0x77, 0xf2, 0x8d, 0xb9, 0x47, 0xd0, ++ 0x53, 0xdd, 0xc8, 0x91, 0x83, 0x8b, 0xb1, 0xce, ++ 0xa3, 0xfe, 0xcd, 0xd9, 0xdd, 0x92, 0x7b, 0xdb, ++ 0xb8, 0xfb, 0xc9, 0x2d, 0x01, 0x59, 0x39, 0x52, ++ 0xad, 0x1b, 0xec, 0xcf, 0xd7, 0x70, 0x13, 0x21, ++ 0xf5, 0x47, 0xaa, 0x18, 0x21, 0x5c, 0xc9, 0x9a, ++ 0xd2, 0x6b, 0x05, 0x9c, 0x01, 0xa1, 0xda, 0x35, ++ 0x5d, 0xb3, 0x70, 0xe6, 0xa9, 0x80, 0x8b, 0x91, ++ 0xb7, 0xb3, 0x5f, 0x24, 0x9a, 0xb7, 0xd1, 0x6b, ++ 0xa1, 0x1c, 0x50, 0xba, 0x49, 0xe0, 0xee, 0x2e, ++ 0x75, 0xac, 0x69, 0xc0, 0xeb, 0x03, 0xdd, 0x19, ++ 0xe5, 0xf6, 0x06, 0xdd, 0xc3, 0xd7, 0x2b, 0x07, ++ 0x07, 0x30, 0xa7, 0x19, 0x0c, 0xbf, 0xe6, 0x18, ++ 0xcc, 0xb1, 0x01, 0x11, 0x85, 0x77, 0x1d, 0x96, ++ 0xa7, 0xa3, 0x00, 0x84, 0x02, 0xa2, 0x83, 0x68, ++ 0xda, 0x17, 0x27, 0xc8, 0x7f, 0x23, 0xb7, 0xf4, ++ 0x13, 0x85, 0xcf, 0xdd, 0x7a, 0x7d, 0x24, 0x57, ++ 0xfe, 0x05, 0x93, 0xf5, 0x74, 0xce, 0xed, 0x0c, ++ 0x20, 0x98, 0x8d, 0x92, 0x30, 0xa1, 0x29, 0x23, ++ 0x1a, 0xa0, 0x4f, 0x69, 0x56, 0x4c, 0xe1, 0xc8, ++ 0xce, 0xf6, 0x9a, 0x0c, 0xa4, 0xfa, 0x04, 0xf6, ++ 0x62, 0x95, 0xf2, 0xfa, 0xc7, 0x40, 0x68, 0x40, ++ 0x8f, 0x41, 0xda, 0xb4, 0x26, 0x6f, 0x70, 0xab, ++ 0x40, 0x61, 0xa4, 0x0e, 0x75, 0xfb, 0x86, 0xeb, ++ 0x9d, 0x9a, 0x1f, 0xec, 0x76, 0x99, 0xe7, 0xea, ++ 0xaa, 0x1e, 0x2d, 0xb5, 0xd4, 0xa6, 0x1a, 0xb8, ++ 0x61, 0x0a, 0x1d, 0x16, 0x5b, 0x98, 0xc2, 0x31, ++ 0x40, 0xe7, 0x23, 0x1d, 0x66, 0x99, 0xc8, 0xc0, ++ 0xd7, 0xce, 0xf3, 0x57, 0x40, 0x04, 0x3f, 0xfc, ++ 0xea, 0xb3, 0xfc, 0xd2, 0xd3, 0x99, 0xa4, 0x94, ++ 0x69, 0xa0, 0xef, 0xd1, 0x85, 0xb3, 0xa6, 0xb1, ++ 0x28, 0xbf, 0x94, 0x67, 0x22, 0xc3, 0x36, 0x46, ++ 0xf8, 0xd2, 0x0f, 0x5f, 0xf4, 0x59, 0x80, 0xe6, ++ 0x2d, 0x43, 0x08, 0x7d, 0x19, 0x09, 0x97, 0xa7, ++ 0x4c, 0x3d, 0x8d, 0xba, 0x65, 0x62, 0xa3, 0x71, ++ 0x33, 0x29, 0x62, 0xdb, 0xc1, 0x33, 0x34, 0x1a, ++ 0x63, 0x33, 0x16, 0xb6, 0x64, 0x7e, 0xab, 0x33, ++ 0xf0, 0xe6, 0x26, 0x68, 0xba, 0x1d, 0x2e, 0x38, ++ 0x08, 0xe6, 0x02, 0xd3, 0x25, 0x2c, 0x47, 0x23, ++ 0x58, 0x34, 0x0f, 0x9d, 0x63, 0x4f, 0x63, 0xbb, ++ 0x7f, 0x3b, 0x34, 0x38, 0xa7, 0xb5, 0x8d, 0x65, ++ 0xd9, 0x9f, 0x79, 0x55, 0x3e, 0x4d, 0xe7, 0x73, ++ 0xd8, 0xf6, 0x98, 0x97, 0x84, 0x60, 0x9c, 0xc8, ++ 0xa9, 0x3c, 0xf6, 0xdc, 0x12, 0x5c, 0xe1, 0xbb, ++ 0x0b, 0x8b, 0x98, 0x9c, 0x9d, 0x26, 0x7c, 0x4a, ++ 0xe6, 0x46, 0x36, 0x58, 0x21, 0x4a, 0xee, 0xca, ++ 0xd7, 0x3b, 0xc2, 0x6c, 0x49, 0x2f, 0xe5, 0xd5, ++ 0x03, 0x59, 0x84, 0x53, 0xcb, 0xfe, 0x92, 0x71, ++ 0x2e, 0x7c, 0x21, 0xcc, 0x99, 0x85, 0x7f, 0xb8, ++ 0x74, 0x90, 0x13, 0x42, 0x3f, 0xe0, 0x6b, 0x1d, ++ 0xf2, 0x4d, 0x54, 0xd4, 0xfc, 0x3a, 0x05, 0xe6, ++ 0x74, 0xaf, 0xa6, 0xa0, 0x2a, 0x20, 0x23, 0x5d, ++ 0x34, 0x5c, 0xd9, 0x3e, 0x4e, 0xfa, 0x93, 0xe7, ++ 0xaa, 0xe9, 0x6f, 0x08, 0x43, 0x67, 0x41, 0xc5, ++ 0xad, 0xfb, 0x31, 0x95, 0x82, 0x73, 0x32, 0xd8, ++ 0xa6, 0xa3, 0xed, 0x0e, 0x2d, 0xf6, 0x5f, 0xfd, ++ 0x80, 0xa6, 0x7a, 0xe0, 0xdf, 0x78, 0x15, 0x29, ++ 0x74, 0x33, 0xd0, 0x9e, 0x83, 0x86, 0x72, 0x22, ++ 0x57, 0x29, 0xb9, 0x9e, 0x5d, 0xd3, 0x1a, 0xb5, ++ 0x96, 0x72, 0x41, 0x3d, 0xf1, 0x64, 0x43, 0x67, ++ 0xee, 0xaa, 0x5c, 0xd3, 0x9a, 0x96, 0x13, 0x11, ++ 0x5d, 0xf3, 0x0c, 0x87, 0x82, 0x1e, 0x41, 0x9e, ++ 0xd0, 0x27, 0xd7, 0x54, 0x3b, 0x67, 0x73, 0x09, ++ 0x91, 0xe9, 0xd5, 0x36, 0xa7, 0xb5, 0x55, 0xe4, ++ 0xf3, 0x21, 0x51, 0x49, 0x22, 0x07, 0x55, 0x4f, ++ 0x44, 0x4b, 0xd2, 0x15, 0x93, 0x17, 0x2a, 0xfa, ++ 0x4d, 0x4a, 0x57, 0xdb, 0x4c, 0xa6, 0xeb, 0xec, ++ 0x53, 0x25, 0x6c, 0x21, 0xed, 0x00, 0x4c, 0x3b, ++ 0xca, 0x14, 0x57, 0xa9, 0xd6, 0x6a, 0xcd, 0x8d, ++ 0x5e, 0x74, 0xac, 0x72, 0xc1, 0x97, 0xe5, 0x1b, ++ 0x45, 0x4e, 0xda, 0xfc, 0xcc, 0x40, 0xe8, 0x48, ++ 0x88, 0x0b, 0xa3, 0xe3, 0x8d, 0x83, 0x42, 0xc3, ++ 0x23, 0xfd, 0x68, 0xb5, 0x8e, 0xf1, 0x9d, 0x63, ++ 0x77, 0xe9, 0xa3, 0x8e, 0x8c, 0x26, 0x6b, 0xbd, ++ 0x72, 0x73, 0x35, 0x0c, 0x03, 0xf8, 0x43, 0x78, ++ 0x52, 0x71, 0x15, 0x1f, 0x71, 0x5d, 0x6e, 0xed, ++ 0xb9, 0xcc, 0x86, 0x30, 0xdb, 0x2b, 0xd3, 0x82, ++ 0x88, 0x23, 0x71, 0x90, 0x53, 0x5c, 0xa9, 0x2f, ++ 0x76, 0x01, 0xb7, 0x9a, 0xfe, 0x43, 0x55, 0xa3, ++ 0x04, 0x9b, 0x0e, 0xe4, 0x59, 0xdf, 0xc9, 0xe9, ++ 0xb1, 0xea, 0x29, 0x28, 0x3c, 0x5c, 0xae, 0x72, ++ 0x84, 0xb6, 0xc6, 0xeb, 0x0c, 0x27, 0x07, 0x74, ++ 0x90, 0x0d, 0x31, 0xb0, 0x00, 0x77, 0xe9, 0x40, ++ 0x70, 0x6f, 0x68, 0xa7, 0xfd, 0x06, 0xec, 0x4b, ++ 0xc0, 0xb7, 0xac, 0xbc, 0x33, 0xb7, 0x6d, 0x0a, ++ 0xbd, 0x12, 0x1b, 0x59, 0xcb, 0xdd, 0x32, 0xf5, ++ 0x1d, 0x94, 0x57, 0x76, 0x9e, 0x0c, 0x18, 0x98, ++ 0x71, 0xd7, 0x2a, 0xdb, 0x0b, 0x7b, 0xa7, 0x71, ++ 0xb7, 0x67, 0x81, 0x23, 0x96, 0xae, 0xb9, 0x7e, ++ 0x32, 0x43, 0x92, 0x8a, 0x19, 0xa0, 0xc4, 0xd4, ++ 0x3b, 0x57, 0xf9, 0x4a, 0x2c, 0xfb, 0x51, 0x46, ++ 0xbb, 0xcb, 0x5d, 0xb3, 0xef, 0x13, 0x93, 0x6e, ++ 0x68, 0x42, 0x54, 0x57, 0xd3, 0x6a, 0x3a, 0x8f, ++ 0x9d, 0x66, 0xbf, 0xbd, 0x36, 0x23, 0xf5, 0x93, ++ 0x83, 0x7b, 0x9c, 0xc0, 0xdd, 0xc5, 0x49, 0xc0, ++ 0x64, 0xed, 0x07, 0x12, 0xb3, 0xe6, 0xe4, 0xe5, ++ 0x38, 0x95, 0x23, 0xb1, 0xa0, 0x3b, 0x1a, 0x61, ++ 0xda, 0x17, 0xac, 0xc3, 0x58, 0xdd, 0x74, 0x64, ++ 0x22, 0x11, 0xe8, 0x32, 0x1d, 0x16, 0x93, 0x85, ++ 0x99, 0xa5, 0x9c, 0x34, 0x55, 0xb1, 0xe9, 0x20, ++ 0x72, 0xc9, 0x28, 0x7b, 0x79, 0x00, 0xa1, 0xa6, ++ 0xa3, 0x27, 0x40, 0x18, 0x8a, 0x54, 0xe0, 0xcc, ++ 0xe8, 0x4e, 0x8e, 0x43, 0x96, 0xe7, 0x3f, 0xc8, ++ 0xe9, 0xb2, 0xf9, 0xc9, 0xda, 0x04, 0x71, 0x50, ++ 0x47, 0xe4, 0xaa, 0xce, 0xa2, 0x30, 0xc8, 0xe4, ++ 0xac, 0xc7, 0x0d, 0x06, 0x2e, 0xe6, 0xe8, 0x80, ++ 0x36, 0x29, 0x9e, 0x01, 0xb8, 0xc3, 0xf0, 0xa0, ++ 0x5d, 0x7a, 0xca, 0x4d, 0xa0, 0x57, 0xbd, 0x2a, ++ 0x45, 0xa7, 0x7f, 0x9c, 0x93, 0x07, 0x8f, 0x35, ++ 0x67, 0x92, 0xe3, 0xe9, 0x7f, 0xa8, 0x61, 0x43, ++ 0x9e, 0x25, 0x4f, 0x33, 0x76, 0x13, 0x6e, 0x12, ++ 0xb9, 0xdd, 0xa4, 0x7c, 0x08, 0x9f, 0x7c, 0xe7, ++ 0x0a, 0x8d, 0x84, 0x06, 0xa4, 0x33, 0x17, 0x34, ++ 0x5e, 0x10, 0x7c, 0xc0, 0xa8, 0x3d, 0x1f, 0x42, ++ 0x20, 0x51, 0x65, 0x5d, 0x09, 0xc3, 0xaa, 0xc0, ++ 0xc8, 0x0d, 0xf0, 0x79, 0xbc, 0x20, 0x1b, 0x95, ++ 0xe7, 0x06, 0x7d, 0x47, 0x20, 0x03, 0x1a, 0x74, ++ 0xdd, 0xe2, 0xd4, 0xae, 0x38, 0x71, 0x9b, 0xf5, ++ 0x80, 0xec, 0x08, 0x4e, 0x56, 0xba, 0x76, 0x12, ++ 0x1a, 0xdf, 0x48, 0xf3, 0xae, 0xb3, 0xe6, 0xe6, ++ 0xbe, 0xc0, 0x91, 0x2e, 0x01, 0xb3, 0x01, 0x86, ++ 0xa2, 0xb9, 0x52, 0xd1, 0x21, 0xae, 0xd4, 0x97, ++ 0x1d, 0xef, 0x41, 0x12, 0x95, 0x3d, 0x48, 0x45, ++ 0x1c, 0x56, 0x32, 0x8f, 0xb8, 0x43, 0xbb, 0x19, ++ 0xf3, 0xca, 0xe9, 0xeb, 0x6d, 0x84, 0xbe, 0x86, ++ 0x06, 0xe2, 0x36, 0xb2, 0x62, 0x9d, 0xd3, 0x4c, ++ 0x48, 0x18, 0x54, 0x13, 0x4e, 0xcf, 0xfd, 0xba, ++ 0x84, 0xb9, 0x30, 0x53, 0xcf, 0xfb, 0xb9, 0x29, ++ 0x8f, 0xdc, 0x9f, 0xef, 0x60, 0x0b, 0x64, 0xf6, ++ 0x8b, 0xee, 0xa6, 0x91, 0xc2, 0x41, 0x6c, 0xf6, ++ 0xfa, 0x79, 0x67, 0x4b, 0xc1, 0x3f, 0xaf, 0x09, ++ 0x81, 0xd4, 0x5d, 0xcb, 0x09, 0xdf, 0x36, 0x31, ++ 0xc0, 0x14, 0x3c, 0x7c, 0x0e, 0x65, 0x95, 0x99, ++ 0x6d, 0xa3, 0xf4, 0xd7, 0x38, 0xee, 0x1a, 0x2b, ++ 0x37, 0xe2, 0xa4, 0x3b, 0x4b, 0xd0, 0x65, 0xca, ++ 0xf8, 0xc3, 0xe8, 0x15, 0x20, 0xef, 0xf2, 0x00, ++ 0xfd, 0x01, 0x09, 0xc5, 0xc8, 0x17, 0x04, 0x93, ++ 0xd0, 0x93, 0x03, 0x55, 0xc5, 0xfe, 0x32, 0xa3, ++ 0x3e, 0x28, 0x2d, 0x3b, 0x93, 0x8a, 0xcc, 0x07, ++ 0x72, 0x80, 0x8b, 0x74, 0x16, 0x24, 0xbb, 0xda, ++ 0x94, 0x39, 0x30, 0x8f, 0xb1, 0xcd, 0x4a, 0x90, ++ 0x92, 0x7c, 0x14, 0x8f, 0x95, 0x4e, 0xac, 0x9b, ++ 0xd8, 0x8f, 0x1a, 0x87, 0xa4, 0x32, 0x27, 0x8a, ++ 0xba, 0xf7, 0x41, 0xcf, 0x84, 0x37, 0x19, 0xe6, ++ 0x06, 0xf5, 0x0e, 0xcf, 0x36, 0xf5, 0x9e, 0x6c, ++ 0xde, 0xbc, 0xff, 0x64, 0x7e, 0x4e, 0x59, 0x57, ++ 0x48, 0xfe, 0x14, 0xf7, 0x9c, 0x93, 0x5d, 0x15, ++ 0xad, 0xcc, 0x11, 0xb1, 0x17, 0x18, 0xb2, 0x7e, ++ 0xcc, 0xab, 0xe9, 0xce, 0x7d, 0x77, 0x5b, 0x51, ++ 0x1b, 0x1e, 0x20, 0xa8, 0x32, 0x06, 0x0e, 0x75, ++ 0x93, 0xac, 0xdb, 0x35, 0x37, 0x1f, 0xe9, 0x19, ++ 0x1d, 0xb4, 0x71, 0x97, 0xd6, 0x4e, 0x2c, 0x08, ++ 0xa5, 0x13, 0xf9, 0x0e, 0x7e, 0x78, 0x6e, 0x14, ++ 0xe0, 0xa9, 0xb9, 0x96, 0x4c, 0x80, 0x82, 0xba, ++ 0x17, 0xb3, 0x9d, 0x69, 0xb0, 0x84, 0x46, 0xff, ++ 0xf9, 0x52, 0x79, 0x94, 0x58, 0x3a, 0x62, 0x90, ++ 0x15, 0x35, 0x71, 0x10, 0x37, 0xed, 0xa1, 0x8e, ++ 0x53, 0x6e, 0xf4, 0x26, 0x57, 0x93, 0x15, 0x93, ++ 0xf6, 0x81, 0x2c, 0x5a, 0x10, 0xda, 0x92, 0xad, ++ 0x2f, 0xdb, 0x28, 0x31, 0x2d, 0x55, 0x04, 0xd2, ++ 0x06, 0x28, 0x8c, 0x1e, 0xdc, 0xea, 0x54, 0xac, ++ 0xff, 0xb7, 0x6c, 0x30, 0x15, 0xd4, 0xb4, 0x0d, ++ 0x00, 0x93, 0x57, 0xdd, 0xd2, 0x07, 0x07, 0x06, ++ 0xd9, 0x43, 0x9b, 0xcd, 0x3a, 0xf4, 0x7d, 0x4c, ++ 0x36, 0x5d, 0x23, 0xa2, 0xcc, 0x57, 0x40, 0x91, ++ 0xe9, 0x2c, 0x2f, 0x2c, 0xd5, 0x30, 0x9b, 0x17, ++ 0xb0, 0xc9, 0xf7, 0xa7, 0x2f, 0xd1, 0x93, 0x20, ++ 0x6b, 0xc6, 0xc1, 0xe4, 0x6f, 0xcb, 0xd1, 0xe7, ++ 0x09, 0x0f, 0x9e, 0xdc, 0xaa, 0x9f, 0x2f, 0xdf, ++ 0x56, 0x9f, 0xd4, 0x33, 0x04, 0xaf, 0xd3, 0x6c, ++ 0x58, 0x61, 0xf0, 0x30, 0xec, 0xf2, 0x7f, 0xf2, ++ 0x9c, 0xdf, 0x39, 0xbb, 0x6f, 0xa2, 0x8c, 0x7e, ++ 0xc4, 0x22, 0x51, 0x71, 0xc0, 0x4d, 0x14, 0x1a, ++ 0xc4, 0xcd, 0x04, 0xd9, 0x87, 0x08, 0x50, 0x05, ++ 0xcc, 0xaf, 0xf6, 0xf0, 0x8f, 0x92, 0x54, 0x58, ++ 0xc2, 0xc7, 0x09, 0x7a, 0x59, 0x02, 0x05, 0xe8, ++ 0xb0, 0x86, 0xd9, 0xbf, 0x7b, 0x35, 0x51, 0x4d, ++ 0xaf, 0x08, 0x97, 0x2c, 0x65, 0xda, 0x2a, 0x71, ++ 0x3a, 0xa8, 0x51, 0xcc, 0xf2, 0x73, 0x27, 0xc3, ++ 0xfd, 0x62, 0xcf, 0xe3, 0xb2, 0xca, 0xcb, 0xbe, ++ 0x1a, 0x0a, 0xa1, 0x34, 0x7b, 0x77, 0xc4, 0x62, ++ 0x68, 0x78, 0x5f, 0x94, 0x07, 0x04, 0x65, 0x16, ++ 0x4b, 0x61, 0xcb, 0xff, 0x75, 0x26, 0x50, 0x66, ++ 0x1f, 0x6e, 0x93, 0xf8, 0xc5, 0x51, 0xeb, 0xa4, ++ 0x4a, 0x48, 0x68, 0x6b, 0xe2, 0x5e, 0x44, 0xb2, ++ 0x50, 0x2c, 0x6c, 0xae, 0x79, 0x4e, 0x66, 0x35, ++ 0x81, 0x50, 0xac, 0xbc, 0x3f, 0xb1, 0x0c, 0xf3, ++ 0x05, 0x3c, 0x4a, 0xa3, 0x6c, 0x2a, 0x79, 0xb4, ++ 0xb7, 0xab, 0xca, 0xc7, 0x9b, 0x8e, 0xcd, 0x5f, ++ 0x11, 0x03, 0xcb, 0x30, 0xa3, 0xab, 0xda, 0xfe, ++ 0x64, 0xb9, 0xbb, 0xd8, 0x5e, 0x3a, 0x1a, 0x56, ++ 0xe5, 0x05, 0x48, 0x90, 0x1e, 0x61, 0x69, 0x1b, ++ 0x22, 0xe6, 0x1a, 0x3c, 0x75, 0xad, 0x1f, 0x37, ++ 0x28, 0xdc, 0xe4, 0x6d, 0xbd, 0x42, 0xdc, 0xd3, ++ 0xc8, 0xb6, 0x1c, 0x48, 0xfe, 0x94, 0x77, 0x7f, ++ 0xbd, 0x62, 0xac, 0xa3, 0x47, 0x27, 0xcf, 0x5f, ++ 0xd9, 0xdb, 0xaf, 0xec, 0xf7, 0x5e, 0xc1, 0xb0, ++ 0x9d, 0x01, 0x26, 0x99, 0x7e, 0x8f, 0x03, 0x70, ++ 0xb5, 0x42, 0xbe, 0x67, 0x28, 0x1b, 0x7c, 0xbd, ++ 0x61, 0x21, 0x97, 0xcc, 0x5c, 0xe1, 0x97, 0x8f, ++ 0x8d, 0xde, 0x2b, 0xaa, 0xa7, 0x71, 0x1d, 0x1e, ++ 0x02, 0x73, 0x70, 0x58, 0x32, 0x5b, 0x1d, 0x67, ++ 0x3d, 0xe0, 0x74, 0x4f, 0x03, 0xf2, 0x70, 0x51, ++ 0x79, 0xf1, 0x61, 0x70, 0x15, 0x74, 0x9d, 0x23, ++ 0x89, 0xde, 0xac, 0xfd, 0xde, 0xd0, 0x1f, 0xc3, ++ 0x87, 0x44, 0x35, 0x4b, 0xe5, 0xb0, 0x60, 0xc5, ++ 0x22, 0xe4, 0x9e, 0xca, 0xeb, 0xd5, 0x3a, 0x09, ++ 0x45, 0xa4, 0xdb, 0xfa, 0x3f, 0xeb, 0x1b, 0xc7, ++ 0xc8, 0x14, 0x99, 0x51, 0x92, 0x10, 0xed, 0xed, ++ 0x28, 0xe0, 0xa1, 0xf8, 0x26, 0xcf, 0xcd, 0xcb, ++ 0x63, 0xa1, 0x3b, 0xe3, 0xdf, 0x7e, 0xfe, 0xa6, ++ 0xf0, 0x81, 0x9a, 0xbf, 0x55, 0xde, 0x54, 0xd5, ++ 0x56, 0x60, 0x98, 0x10, 0x68, 0xf4, 0x38, 0x96, ++ 0x8e, 0x6f, 0x1d, 0x44, 0x7f, 0xd6, 0x2f, 0xfe, ++ 0x55, 0xfb, 0x0c, 0x7e, 0x67, 0xe2, 0x61, 0x44, ++ 0xed, 0xf2, 0x35, 0x30, 0x5d, 0xe9, 0xc7, 0xd6, ++ 0x6d, 0xe0, 0xa0, 0xed, 0xf3, 0xfc, 0xd8, 0x3e, ++ 0x0a, 0x7b, 0xcd, 0xaf, 0x65, 0x68, 0x18, 0xc0, ++ 0xec, 0x04, 0x1c, 0x74, 0x6d, 0xe2, 0x6e, 0x79, ++ 0xd4, 0x11, 0x2b, 0x62, 0xd5, 0x27, 0xad, 0x4f, ++ 0x01, 0x59, 0x73, 0xcc, 0x6a, 0x53, 0xfb, 0x2d, ++ 0xd5, 0x4e, 0x99, 0x21, 0x65, 0x4d, 0xf5, 0x82, ++ 0xf7, 0xd8, 0x42, 0xce, 0x6f, 0x3d, 0x36, 0x47, ++ 0xf1, 0x05, 0x16, 0xe8, 0x1b, 0x6a, 0x8f, 0x93, ++ 0xf2, 0x8f, 0x37, 0x40, 0x12, 0x28, 0xa3, 0xe6, ++ 0xb9, 0x17, 0x4a, 0x1f, 0xb1, 0xd1, 0x66, 0x69, ++ 0x86, 0xc4, 0xfc, 0x97, 0xae, 0x3f, 0x8f, 0x1e, ++ 0x2b, 0xdf, 0xcd, 0xf9, 0x3c ++}; ++static const u8 dec_output011[] __initconst = { ++ 0x7a, 0x57, 0xf2, 0xc7, 0x06, 0x3f, 0x50, 0x7b, ++ 0x36, 0x1a, 0x66, 0x5c, 0xb9, 0x0e, 0x5e, 0x3b, ++ 0x45, 0x60, 0xbe, 0x9a, 0x31, 0x9f, 0xff, 0x5d, ++ 0x66, 0x34, 0xb4, 0xdc, 0xfb, 0x9d, 0x8e, 0xee, ++ 0x6a, 0x33, 0xa4, 0x07, 0x3c, 0xf9, 0x4c, 0x30, ++ 0xa1, 0x24, 0x52, 0xf9, 0x50, 0x46, 0x88, 0x20, ++ 0x02, 0x32, 0x3a, 0x0e, 0x99, 0x63, 0xaf, 0x1f, ++ 0x15, 0x28, 0x2a, 0x05, 0xff, 0x57, 0x59, 0x5e, ++ 0x18, 0xa1, 0x1f, 0xd0, 0x92, 0x5c, 0x88, 0x66, ++ 0x1b, 0x00, 0x64, 0xa5, 0x93, 0x8d, 0x06, 0x46, ++ 0xb0, 0x64, 0x8b, 0x8b, 0xef, 0x99, 0x05, 0x35, ++ 0x85, 0xb3, 0xf3, 0x33, 0xbb, 0xec, 0x66, 0xb6, ++ 0x3d, 0x57, 0x42, 0xe3, 0xb4, 0xc6, 0xaa, 0xb0, ++ 0x41, 0x2a, 0xb9, 0x59, 0xa9, 0xf6, 0x3e, 0x15, ++ 0x26, 0x12, 0x03, 0x21, 0x4c, 0x74, 0x43, 0x13, ++ 0x2a, 0x03, 0x27, 0x09, 0xb4, 0xfb, 0xe7, 0xb7, ++ 0x40, 0xff, 0x5e, 0xce, 0x48, 0x9a, 0x60, 0xe3, ++ 0x8b, 0x80, 0x8c, 0x38, 0x2d, 0xcb, 0x93, 0x37, ++ 0x74, 0x05, 0x52, 0x6f, 0x73, 0x3e, 0xc3, 0xbc, ++ 0xca, 0x72, 0x0a, 0xeb, 0xf1, 0x3b, 0xa0, 0x95, ++ 0xdc, 0x8a, 0xc4, 0xa9, 0xdc, 0xca, 0x44, 0xd8, ++ 0x08, 0x63, 0x6a, 0x36, 0xd3, 0x3c, 0xb8, 0xac, ++ 0x46, 0x7d, 0xfd, 0xaa, 0xeb, 0x3e, 0x0f, 0x45, ++ 0x8f, 0x49, 0xda, 0x2b, 0xf2, 0x12, 0xbd, 0xaf, ++ 0x67, 0x8a, 0x63, 0x48, 0x4b, 0x55, 0x5f, 0x6d, ++ 0x8c, 0xb9, 0x76, 0x34, 0x84, 0xae, 0xc2, 0xfc, ++ 0x52, 0x64, 0x82, 0xf7, 0xb0, 0x06, 0xf0, 0x45, ++ 0x73, 0x12, 0x50, 0x30, 0x72, 0xea, 0x78, 0x9a, ++ 0xa8, 0xaf, 0xb5, 0xe3, 0xbb, 0x77, 0x52, 0xec, ++ 0x59, 0x84, 0xbf, 0x6b, 0x8f, 0xce, 0x86, 0x5e, ++ 0x1f, 0x23, 0xe9, 0xfb, 0x08, 0x86, 0xf7, 0x10, ++ 0xb9, 0xf2, 0x44, 0x96, 0x44, 0x63, 0xa9, 0xa8, ++ 0x78, 0x00, 0x23, 0xd6, 0xc7, 0xe7, 0x6e, 0x66, ++ 0x4f, 0xcc, 0xee, 0x15, 0xb3, 0xbd, 0x1d, 0xa0, ++ 0xe5, 0x9c, 0x1b, 0x24, 0x2c, 0x4d, 0x3c, 0x62, ++ 0x35, 0x9c, 0x88, 0x59, 0x09, 0xdd, 0x82, 0x1b, ++ 0xcf, 0x0a, 0x83, 0x6b, 0x3f, 0xae, 0x03, 0xc4, ++ 0xb4, 0xdd, 0x7e, 0x5b, 0x28, 0x76, 0x25, 0x96, ++ 0xd9, 0xc9, 0x9d, 0x5f, 0x86, 0xfa, 0xf6, 0xd7, ++ 0xd2, 0xe6, 0x76, 0x1d, 0x0f, 0xa1, 0xdc, 0x74, ++ 0x05, 0x1b, 0x1d, 0xe0, 0xcd, 0x16, 0xb0, 0xa8, ++ 0x8a, 0x34, 0x7b, 0x15, 0x11, 0x77, 0xe5, 0x7b, ++ 0x7e, 0x20, 0xf7, 0xda, 0x38, 0xda, 0xce, 0x70, ++ 0xe9, 0xf5, 0x6c, 0xd9, 0xbe, 0x0c, 0x4c, 0x95, ++ 0x4c, 0xc2, 0x9b, 0x34, 0x55, 0x55, 0xe1, 0xf3, ++ 0x46, 0x8e, 0x48, 0x74, 0x14, 0x4f, 0x9d, 0xc9, ++ 0xf5, 0xe8, 0x1a, 0xf0, 0x11, 0x4a, 0xc1, 0x8d, ++ 0xe0, 0x93, 0xa0, 0xbe, 0x09, 0x1c, 0x2b, 0x4e, ++ 0x0f, 0xb2, 0x87, 0x8b, 0x84, 0xfe, 0x92, 0x32, ++ 0x14, 0xd7, 0x93, 0xdf, 0xe7, 0x44, 0xbc, 0xc5, ++ 0xae, 0x53, 0x69, 0xd8, 0xb3, 0x79, 0x37, 0x80, ++ 0xe3, 0x17, 0x5c, 0xec, 0x53, 0x00, 0x9a, 0xe3, ++ 0x8e, 0xdc, 0x38, 0xb8, 0x66, 0xf0, 0xd3, 0xad, ++ 0x1d, 0x02, 0x96, 0x86, 0x3e, 0x9d, 0x3b, 0x5d, ++ 0xa5, 0x7f, 0x21, 0x10, 0xf1, 0x1f, 0x13, 0x20, ++ 0xf9, 0x57, 0x87, 0x20, 0xf5, 0x5f, 0xf1, 0x17, ++ 0x48, 0x0a, 0x51, 0x5a, 0xcd, 0x19, 0x03, 0xa6, ++ 0x5a, 0xd1, 0x12, 0x97, 0xe9, 0x48, 0xe2, 0x1d, ++ 0x83, 0x75, 0x50, 0xd9, 0x75, 0x7d, 0x6a, 0x82, ++ 0xa1, 0xf9, 0x4e, 0x54, 0x87, 0x89, 0xc9, 0x0c, ++ 0xb7, 0x5b, 0x6a, 0x91, 0xc1, 0x9c, 0xb2, 0xa9, ++ 0xdc, 0x9a, 0xa4, 0x49, 0x0a, 0x6d, 0x0d, 0xbb, ++ 0xde, 0x86, 0x44, 0xdd, 0x5d, 0x89, 0x2b, 0x96, ++ 0x0f, 0x23, 0x95, 0xad, 0xcc, 0xa2, 0xb3, 0xb9, ++ 0x7e, 0x74, 0x38, 0xba, 0x9f, 0x73, 0xae, 0x5f, ++ 0xf8, 0x68, 0xa2, 0xe0, 0xa9, 0xce, 0xbd, 0x40, ++ 0xd4, 0x4c, 0x6b, 0xd2, 0x56, 0x62, 0xb0, 0xcc, ++ 0x63, 0x7e, 0x5b, 0xd3, 0xae, 0xd1, 0x75, 0xce, ++ 0xbb, 0xb4, 0x5b, 0xa8, 0xf8, 0xb4, 0xac, 0x71, ++ 0x75, 0xaa, 0xc9, 0x9f, 0xbb, 0x6c, 0xad, 0x0f, ++ 0x55, 0x5d, 0xe8, 0x85, 0x7d, 0xf9, 0x21, 0x35, ++ 0xea, 0x92, 0x85, 0x2b, 0x00, 0xec, 0x84, 0x90, ++ 0x0a, 0x63, 0x96, 0xe4, 0x6b, 0xa9, 0x77, 0xb8, ++ 0x91, 0xf8, 0x46, 0x15, 0x72, 0x63, 0x70, 0x01, ++ 0x40, 0xa3, 0xa5, 0x76, 0x62, 0x2b, 0xbf, 0xf1, ++ 0xe5, 0x8d, 0x9f, 0xa3, 0xfa, 0x9b, 0x03, 0xbe, ++ 0xfe, 0x65, 0x6f, 0xa2, 0x29, 0x0d, 0x54, 0xb4, ++ 0x71, 0xce, 0xa9, 0xd6, 0x3d, 0x88, 0xf9, 0xaf, ++ 0x6b, 0xa8, 0x9e, 0xf4, 0x16, 0x96, 0x36, 0xb9, ++ 0x00, 0xdc, 0x10, 0xab, 0xb5, 0x08, 0x31, 0x1f, ++ 0x00, 0xb1, 0x3c, 0xd9, 0x38, 0x3e, 0xc6, 0x04, ++ 0xa7, 0x4e, 0xe8, 0xae, 0xed, 0x98, 0xc2, 0xf7, ++ 0xb9, 0x00, 0x5f, 0x8c, 0x60, 0xd1, 0xe5, 0x15, ++ 0xf7, 0xae, 0x1e, 0x84, 0x88, 0xd1, 0xf6, 0xbc, ++ 0x3a, 0x89, 0x35, 0x22, 0x83, 0x7c, 0xca, 0xf0, ++ 0x33, 0x82, 0x4c, 0x79, 0x3c, 0xfd, 0xb1, 0xae, ++ 0x52, 0x62, 0x55, 0xd2, 0x41, 0x60, 0xc6, 0xbb, ++ 0xfa, 0x0e, 0x59, 0xd6, 0xa8, 0xfe, 0x5d, 0xed, ++ 0x47, 0x3d, 0xe0, 0xea, 0x1f, 0x6e, 0x43, 0x51, ++ 0xec, 0x10, 0x52, 0x56, 0x77, 0x42, 0x6b, 0x52, ++ 0x87, 0xd8, 0xec, 0xe0, 0xaa, 0x76, 0xa5, 0x84, ++ 0x2a, 0x22, 0x24, 0xfd, 0x92, 0x40, 0x88, 0xd5, ++ 0x85, 0x1c, 0x1f, 0x6b, 0x47, 0xa0, 0xc4, 0xe4, ++ 0xef, 0xf4, 0xea, 0xd7, 0x59, 0xac, 0x2a, 0x9e, ++ 0x8c, 0xfa, 0x1f, 0x42, 0x08, 0xfe, 0x4f, 0x74, ++ 0xa0, 0x26, 0xf5, 0xb3, 0x84, 0xf6, 0x58, 0x5f, ++ 0x26, 0x66, 0x3e, 0xd7, 0xe4, 0x22, 0x91, 0x13, ++ 0xc8, 0xac, 0x25, 0x96, 0x23, 0xd8, 0x09, 0xea, ++ 0x45, 0x75, 0x23, 0xb8, 0x5f, 0xc2, 0x90, 0x8b, ++ 0x09, 0xc4, 0xfc, 0x47, 0x6c, 0x6d, 0x0a, 0xef, ++ 0x69, 0xa4, 0x38, 0x19, 0xcf, 0x7d, 0xf9, 0x09, ++ 0x73, 0x9b, 0x60, 0x5a, 0xf7, 0x37, 0xb5, 0xfe, ++ 0x9f, 0xe3, 0x2b, 0x4c, 0x0d, 0x6e, 0x19, 0xf1, ++ 0xd6, 0xc0, 0x70, 0xf3, 0x9d, 0x22, 0x3c, 0xf9, ++ 0x49, 0xce, 0x30, 0x8e, 0x44, 0xb5, 0x76, 0x15, ++ 0x8f, 0x52, 0xfd, 0xa5, 0x04, 0xb8, 0x55, 0x6a, ++ 0x36, 0x59, 0x7c, 0xc4, 0x48, 0xb8, 0xd7, 0xab, ++ 0x05, 0x66, 0xe9, 0x5e, 0x21, 0x6f, 0x6b, 0x36, ++ 0x29, 0xbb, 0xe9, 0xe3, 0xa2, 0x9a, 0xa8, 0xcd, ++ 0x55, 0x25, 0x11, 0xba, 0x5a, 0x58, 0xa0, 0xde, ++ 0xae, 0x19, 0x2a, 0x48, 0x5a, 0xff, 0x36, 0xcd, ++ 0x6d, 0x16, 0x7a, 0x73, 0x38, 0x46, 0xe5, 0x47, ++ 0x59, 0xc8, 0xa2, 0xf6, 0xe2, 0x6c, 0x83, 0xc5, ++ 0x36, 0x2c, 0x83, 0x7d, 0xb4, 0x01, 0x05, 0x69, ++ 0xe7, 0xaf, 0x5c, 0xc4, 0x64, 0x82, 0x12, 0x21, ++ 0xef, 0xf7, 0xd1, 0x7d, 0xb8, 0x8d, 0x8c, 0x98, ++ 0x7c, 0x5f, 0x7d, 0x92, 0x88, 0xb9, 0x94, 0x07, ++ 0x9c, 0xd8, 0xe9, 0x9c, 0x17, 0x38, 0xe3, 0x57, ++ 0x6c, 0xe0, 0xdc, 0xa5, 0x92, 0x42, 0xb3, 0xbd, ++ 0x50, 0xa2, 0x7e, 0xb5, 0xb1, 0x52, 0x72, 0x03, ++ 0x97, 0xd8, 0xaa, 0x9a, 0x1e, 0x75, 0x41, 0x11, ++ 0xa3, 0x4f, 0xcc, 0xd4, 0xe3, 0x73, 0xad, 0x96, ++ 0xdc, 0x47, 0x41, 0x9f, 0xb0, 0xbe, 0x79, 0x91, ++ 0xf5, 0xb6, 0x18, 0xfe, 0xc2, 0x83, 0x18, 0x7d, ++ 0x73, 0xd9, 0x4f, 0x83, 0x84, 0x03, 0xb3, 0xf0, ++ 0x77, 0x66, 0x3d, 0x83, 0x63, 0x2e, 0x2c, 0xf9, ++ 0xdd, 0xa6, 0x1f, 0x89, 0x82, 0xb8, 0x23, 0x42, ++ 0xeb, 0xe2, 0xca, 0x70, 0x82, 0x61, 0x41, 0x0a, ++ 0x6d, 0x5f, 0x75, 0xc5, 0xe2, 0xc4, 0x91, 0x18, ++ 0x44, 0x22, 0xfa, 0x34, 0x10, 0xf5, 0x20, 0xdc, ++ 0xb7, 0xdd, 0x2a, 0x20, 0x77, 0xf5, 0xf9, 0xce, ++ 0xdb, 0xa0, 0x0a, 0x52, 0x2a, 0x4e, 0xdd, 0xcc, ++ 0x97, 0xdf, 0x05, 0xe4, 0x5e, 0xb7, 0xaa, 0xf0, ++ 0xe2, 0x80, 0xff, 0xba, 0x1a, 0x0f, 0xac, 0xdf, ++ 0x02, 0x32, 0xe6, 0xf7, 0xc7, 0x17, 0x13, 0xb7, ++ 0xfc, 0x98, 0x48, 0x8c, 0x0d, 0x82, 0xc9, 0x80, ++ 0x7a, 0xe2, 0x0a, 0xc5, 0xb4, 0xde, 0x7c, 0x3c, ++ 0x79, 0x81, 0x0e, 0x28, 0x65, 0x79, 0x67, 0x82, ++ 0x69, 0x44, 0x66, 0x09, 0xf7, 0x16, 0x1a, 0xf9, ++ 0x7d, 0x80, 0xa1, 0x79, 0x14, 0xa9, 0xc8, 0x20, ++ 0xfb, 0xa2, 0x46, 0xbe, 0x08, 0x35, 0x17, 0x58, ++ 0xc1, 0x1a, 0xda, 0x2a, 0x6b, 0x2e, 0x1e, 0xe6, ++ 0x27, 0x55, 0x7b, 0x19, 0xe2, 0xfb, 0x64, 0xfc, ++ 0x5e, 0x15, 0x54, 0x3c, 0xe7, 0xc2, 0x11, 0x50, ++ 0x30, 0xb8, 0x72, 0x03, 0x0b, 0x1a, 0x9f, 0x86, ++ 0x27, 0x11, 0x5c, 0x06, 0x2b, 0xbd, 0x75, 0x1a, ++ 0x0a, 0xda, 0x01, 0xfa, 0x5c, 0x4a, 0xc1, 0x80, ++ 0x3a, 0x6e, 0x30, 0xc8, 0x2c, 0xeb, 0x56, 0xec, ++ 0x89, 0xfa, 0x35, 0x7b, 0xb2, 0xf0, 0x97, 0x08, ++ 0x86, 0x53, 0xbe, 0xbd, 0x40, 0x41, 0x38, 0x1c, ++ 0xb4, 0x8b, 0x79, 0x2e, 0x18, 0x96, 0x94, 0xde, ++ 0xe8, 0xca, 0xe5, 0x9f, 0x92, 0x9f, 0x15, 0x5d, ++ 0x56, 0x60, 0x5c, 0x09, 0xf9, 0x16, 0xf4, 0x17, ++ 0x0f, 0xf6, 0x4c, 0xda, 0xe6, 0x67, 0x89, 0x9f, ++ 0xca, 0x6c, 0xe7, 0x9b, 0x04, 0x62, 0x0e, 0x26, ++ 0xa6, 0x52, 0xbd, 0x29, 0xff, 0xc7, 0xa4, 0x96, ++ 0xe6, 0x6a, 0x02, 0xa5, 0x2e, 0x7b, 0xfe, 0x97, ++ 0x68, 0x3e, 0x2e, 0x5f, 0x3b, 0x0f, 0x36, 0xd6, ++ 0x98, 0x19, 0x59, 0x48, 0xd2, 0xc6, 0xe1, 0x55, ++ 0x1a, 0x6e, 0xd6, 0xed, 0x2c, 0xba, 0xc3, 0x9e, ++ 0x64, 0xc9, 0x95, 0x86, 0x35, 0x5e, 0x3e, 0x88, ++ 0x69, 0x99, 0x4b, 0xee, 0xbe, 0x9a, 0x99, 0xb5, ++ 0x6e, 0x58, 0xae, 0xdd, 0x22, 0xdb, 0xdd, 0x6b, ++ 0xfc, 0xaf, 0x90, 0xa3, 0x3d, 0xa4, 0xc1, 0x15, ++ 0x92, 0x18, 0x8d, 0xd2, 0x4b, 0x7b, 0x06, 0xd1, ++ 0x37, 0xb5, 0xe2, 0x7c, 0x2c, 0xf0, 0x25, 0xe4, ++ 0x94, 0x2a, 0xbd, 0xe3, 0x82, 0x70, 0x78, 0xa3, ++ 0x82, 0x10, 0x5a, 0x90, 0xd7, 0xa4, 0xfa, 0xaf, ++ 0x1a, 0x88, 0x59, 0xdc, 0x74, 0x12, 0xb4, 0x8e, ++ 0xd7, 0x19, 0x46, 0xf4, 0x84, 0x69, 0x9f, 0xbb, ++ 0x70, 0xa8, 0x4c, 0x52, 0x81, 0xa9, 0xff, 0x76, ++ 0x1c, 0xae, 0xd8, 0x11, 0x3d, 0x7f, 0x7d, 0xc5, ++ 0x12, 0x59, 0x28, 0x18, 0xc2, 0xa2, 0xb7, 0x1c, ++ 0x88, 0xf8, 0xd6, 0x1b, 0xa6, 0x7d, 0x9e, 0xde, ++ 0x29, 0xf8, 0xed, 0xff, 0xeb, 0x92, 0x24, 0x4f, ++ 0x05, 0xaa, 0xd9, 0x49, 0xba, 0x87, 0x59, 0x51, ++ 0xc9, 0x20, 0x5c, 0x9b, 0x74, 0xcf, 0x03, 0xd9, ++ 0x2d, 0x34, 0xc7, 0x5b, 0xa5, 0x40, 0xb2, 0x99, ++ 0xf5, 0xcb, 0xb4, 0xf6, 0xb7, 0x72, 0x4a, 0xd6, ++ 0xbd, 0xb0, 0xf3, 0x93, 0xe0, 0x1b, 0xa8, 0x04, ++ 0x1e, 0x35, 0xd4, 0x80, 0x20, 0xf4, 0x9c, 0x31, ++ 0x6b, 0x45, 0xb9, 0x15, 0xb0, 0x5e, 0xdd, 0x0a, ++ 0x33, 0x9c, 0x83, 0xcd, 0x58, 0x89, 0x50, 0x56, ++ 0xbb, 0x81, 0x00, 0x91, 0x32, 0xf3, 0x1b, 0x3e, ++ 0xcf, 0x45, 0xe1, 0xf9, 0xe1, 0x2c, 0x26, 0x78, ++ 0x93, 0x9a, 0x60, 0x46, 0xc9, 0xb5, 0x5e, 0x6a, ++ 0x28, 0x92, 0x87, 0x3f, 0x63, 0x7b, 0xdb, 0xf7, ++ 0xd0, 0x13, 0x9d, 0x32, 0x40, 0x5e, 0xcf, 0xfb, ++ 0x79, 0x68, 0x47, 0x4c, 0xfd, 0x01, 0x17, 0xe6, ++ 0x97, 0x93, 0x78, 0xbb, 0xa6, 0x27, 0xa3, 0xe8, ++ 0x1a, 0xe8, 0x94, 0x55, 0x7d, 0x08, 0xe5, 0xdc, ++ 0x66, 0xa3, 0x69, 0xc8, 0xca, 0xc5, 0xa1, 0x84, ++ 0x55, 0xde, 0x08, 0x91, 0x16, 0x3a, 0x0c, 0x86, ++ 0xab, 0x27, 0x2b, 0x64, 0x34, 0x02, 0x6c, 0x76, ++ 0x8b, 0xc6, 0xaf, 0xcc, 0xe1, 0xd6, 0x8c, 0x2a, ++ 0x18, 0x3d, 0xa6, 0x1b, 0x37, 0x75, 0x45, 0x73, ++ 0xc2, 0x75, 0xd7, 0x53, 0x78, 0x3a, 0xd6, 0xe8, ++ 0x29, 0xd2, 0x4a, 0xa8, 0x1e, 0x82, 0xf6, 0xb6, ++ 0x81, 0xde, 0x21, 0xed, 0x2b, 0x56, 0xbb, 0xf2, ++ 0xd0, 0x57, 0xc1, 0x7c, 0xd2, 0x6a, 0xd2, 0x56, ++ 0xf5, 0x13, 0x5f, 0x1c, 0x6a, 0x0b, 0x74, 0xfb, ++ 0xe9, 0xfe, 0x9e, 0xea, 0x95, 0xb2, 0x46, 0xab, ++ 0x0a, 0xfc, 0xfd, 0xf3, 0xbb, 0x04, 0x2b, 0x76, ++ 0x1b, 0xa4, 0x74, 0xb0, 0xc1, 0x78, 0xc3, 0x69, ++ 0xe2, 0xb0, 0x01, 0xe1, 0xde, 0x32, 0x4c, 0x8d, ++ 0x1a, 0xb3, 0x38, 0x08, 0xd5, 0xfc, 0x1f, 0xdc, ++ 0x0e, 0x2c, 0x9c, 0xb1, 0xa1, 0x63, 0x17, 0x22, ++ 0xf5, 0x6c, 0x93, 0x70, 0x74, 0x00, 0xf8, 0x39, ++ 0x01, 0x94, 0xd1, 0x32, 0x23, 0x56, 0x5d, 0xa6, ++ 0x02, 0x76, 0x76, 0x93, 0xce, 0x2f, 0x19, 0xe9, ++ 0x17, 0x52, 0xae, 0x6e, 0x2c, 0x6d, 0x61, 0x7f, ++ 0x3b, 0xaa, 0xe0, 0x52, 0x85, 0xc5, 0x65, 0xc1, ++ 0xbb, 0x8e, 0x5b, 0x21, 0xd5, 0xc9, 0x78, 0x83, ++ 0x07, 0x97, 0x4c, 0x62, 0x61, 0x41, 0xd4, 0xfc, ++ 0xc9, 0x39, 0xe3, 0x9b, 0xd0, 0xcc, 0x75, 0xc4, ++ 0x97, 0xe6, 0xdd, 0x2a, 0x5f, 0xa6, 0xe8, 0x59, ++ 0x6c, 0x98, 0xb9, 0x02, 0xe2, 0xa2, 0xd6, 0x68, ++ 0xee, 0x3b, 0x1d, 0xe3, 0x4d, 0x5b, 0x30, 0xef, ++ 0x03, 0xf2, 0xeb, 0x18, 0x57, 0x36, 0xe8, 0xa1, ++ 0xf4, 0x47, 0xfb, 0xcb, 0x8f, 0xcb, 0xc8, 0xf3, ++ 0x4f, 0x74, 0x9d, 0x9d, 0xb1, 0x8d, 0x14, 0x44, ++ 0xd9, 0x19, 0xb4, 0x54, 0x4f, 0x75, 0x19, 0x09, ++ 0xa0, 0x75, 0xbc, 0x3b, 0x82, 0xc6, 0x3f, 0xb8, ++ 0x83, 0x19, 0x6e, 0xd6, 0x37, 0xfe, 0x6e, 0x8a, ++ 0x4e, 0xe0, 0x4a, 0xab, 0x7b, 0xc8, 0xb4, 0x1d, ++ 0xf4, 0xed, 0x27, 0x03, 0x65, 0xa2, 0xa1, 0xae, ++ 0x11, 0xe7, 0x98, 0x78, 0x48, 0x91, 0xd2, 0xd2, ++ 0xd4, 0x23, 0x78, 0x50, 0xb1, 0x5b, 0x85, 0x10, ++ 0x8d, 0xca, 0x5f, 0x0f, 0x71, 0xae, 0x72, 0x9a, ++ 0xf6, 0x25, 0x19, 0x60, 0x06, 0xf7, 0x10, 0x34, ++ 0x18, 0x0d, 0xc9, 0x9f, 0x7b, 0x0c, 0x9b, 0x8f, ++ 0x91, 0x1b, 0x9f, 0xcd, 0x10, 0xee, 0x75, 0xf9, ++ 0x97, 0x66, 0xfc, 0x4d, 0x33, 0x6e, 0x28, 0x2b, ++ 0x92, 0x85, 0x4f, 0xab, 0x43, 0x8d, 0x8f, 0x7d, ++ 0x86, 0xa7, 0xc7, 0xd8, 0xd3, 0x0b, 0x8b, 0x57, ++ 0xb6, 0x1d, 0x95, 0x0d, 0xe9, 0xbc, 0xd9, 0x03, ++ 0xd9, 0x10, 0x19, 0xc3, 0x46, 0x63, 0x55, 0x87, ++ 0x61, 0x79, 0x6c, 0x95, 0x0e, 0x9c, 0xdd, 0xca, ++ 0xc3, 0xf3, 0x64, 0xf0, 0x7d, 0x76, 0xb7, 0x53, ++ 0x67, 0x2b, 0x1e, 0x44, 0x56, 0x81, 0xea, 0x8f, ++ 0x5c, 0x42, 0x16, 0xb8, 0x28, 0xeb, 0x1b, 0x61, ++ 0x10, 0x1e, 0xbf, 0xec, 0xa8 ++}; ++static const u8 dec_assoc011[] __initconst = { ++ 0xd6, 0x31, 0xda, 0x5d, 0x42, 0x5e, 0xd7 ++}; ++static const u8 dec_nonce011[] __initconst = { ++ 0xfd, 0x87, 0xd4, 0xd8, 0x62, 0xfd, 0xec, 0xaa ++}; ++static const u8 dec_key011[] __initconst = { ++ 0x35, 0x4e, 0xb5, 0x70, 0x50, 0x42, 0x8a, 0x85, ++ 0xf2, 0xfb, 0xed, 0x7b, 0xd0, 0x9e, 0x97, 0xca, ++ 0xfa, 0x98, 0x66, 0x63, 0xee, 0x37, 0xcc, 0x52, ++ 0xfe, 0xd1, 0xdf, 0x95, 0x15, 0x34, 0x29, 0x38 ++}; ++ ++static const u8 dec_input012[] __initconst = { ++ 0x52, 0x34, 0xb3, 0x65, 0x3b, 0xb7, 0xe5, 0xd3, ++ 0xab, 0x49, 0x17, 0x60, 0xd2, 0x52, 0x56, 0xdf, ++ 0xdf, 0x34, 0x56, 0x82, 0xe2, 0xbe, 0xe5, 0xe1, ++ 0x28, 0xd1, 0x4e, 0x5f, 0x4f, 0x01, 0x7d, 0x3f, ++ 0x99, 0x6b, 0x30, 0x6e, 0x1a, 0x7c, 0x4c, 0x8e, ++ 0x62, 0x81, 0xae, 0x86, 0x3f, 0x6b, 0xd0, 0xb5, ++ 0xa9, 0xcf, 0x50, 0xf1, 0x02, 0x12, 0xa0, 0x0b, ++ 0x24, 0xe9, 0xe6, 0x72, 0x89, 0x2c, 0x52, 0x1b, ++ 0x34, 0x38, 0xf8, 0x75, 0x5f, 0xa0, 0x74, 0xe2, ++ 0x99, 0xdd, 0xa6, 0x4b, 0x14, 0x50, 0x4e, 0xf1, ++ 0xbe, 0xd6, 0x9e, 0xdb, 0xb2, 0x24, 0x27, 0x74, ++ 0x12, 0x4a, 0x78, 0x78, 0x17, 0xa5, 0x58, 0x8e, ++ 0x2f, 0xf9, 0xf4, 0x8d, 0xee, 0x03, 0x88, 0xae, ++ 0xb8, 0x29, 0xa1, 0x2f, 0x4b, 0xee, 0x92, 0xbd, ++ 0x87, 0xb3, 0xce, 0x34, 0x21, 0x57, 0x46, 0x04, ++ 0x49, 0x0c, 0x80, 0xf2, 0x01, 0x13, 0xa1, 0x55, ++ 0xb3, 0xff, 0x44, 0x30, 0x3c, 0x1c, 0xd0, 0xef, ++ 0xbc, 0x18, 0x74, 0x26, 0xad, 0x41, 0x5b, 0x5b, ++ 0x3e, 0x9a, 0x7a, 0x46, 0x4f, 0x16, 0xd6, 0x74, ++ 0x5a, 0xb7, 0x3a, 0x28, 0x31, 0xd8, 0xae, 0x26, ++ 0xac, 0x50, 0x53, 0x86, 0xf2, 0x56, 0xd7, 0x3f, ++ 0x29, 0xbc, 0x45, 0x68, 0x8e, 0xcb, 0x98, 0x64, ++ 0xdd, 0xc9, 0xba, 0xb8, 0x4b, 0x7b, 0x82, 0xdd, ++ 0x14, 0xa7, 0xcb, 0x71, 0x72, 0x00, 0x5c, 0xad, ++ 0x7b, 0x6a, 0x89, 0xa4, 0x3d, 0xbf, 0xb5, 0x4b, ++ 0x3e, 0x7c, 0x5a, 0xcf, 0xb8, 0xa1, 0xc5, 0x6e, ++ 0xc8, 0xb6, 0x31, 0x57, 0x7b, 0xdf, 0xa5, 0x7e, ++ 0xb1, 0xd6, 0x42, 0x2a, 0x31, 0x36, 0xd1, 0xd0, ++ 0x3f, 0x7a, 0xe5, 0x94, 0xd6, 0x36, 0xa0, 0x6f, ++ 0xb7, 0x40, 0x7d, 0x37, 0xc6, 0x55, 0x7c, 0x50, ++ 0x40, 0x6d, 0x29, 0x89, 0xe3, 0x5a, 0xae, 0x97, ++ 0xe7, 0x44, 0x49, 0x6e, 0xbd, 0x81, 0x3d, 0x03, ++ 0x93, 0x06, 0x12, 0x06, 0xe2, 0x41, 0x12, 0x4a, ++ 0xf1, 0x6a, 0xa4, 0x58, 0xa2, 0xfb, 0xd2, 0x15, ++ 0xba, 0xc9, 0x79, 0xc9, 0xce, 0x5e, 0x13, 0xbb, ++ 0xf1, 0x09, 0x04, 0xcc, 0xfd, 0xe8, 0x51, 0x34, ++ 0x6a, 0xe8, 0x61, 0x88, 0xda, 0xed, 0x01, 0x47, ++ 0x84, 0xf5, 0x73, 0x25, 0xf9, 0x1c, 0x42, 0x86, ++ 0x07, 0xf3, 0x5b, 0x1a, 0x01, 0xb3, 0xeb, 0x24, ++ 0x32, 0x8d, 0xf6, 0xed, 0x7c, 0x4b, 0xeb, 0x3c, ++ 0x36, 0x42, 0x28, 0xdf, 0xdf, 0xb6, 0xbe, 0xd9, ++ 0x8c, 0x52, 0xd3, 0x2b, 0x08, 0x90, 0x8c, 0xe7, ++ 0x98, 0x31, 0xe2, 0x32, 0x8e, 0xfc, 0x11, 0x48, ++ 0x00, 0xa8, 0x6a, 0x42, 0x4a, 0x02, 0xc6, 0x4b, ++ 0x09, 0xf1, 0xe3, 0x49, 0xf3, 0x45, 0x1f, 0x0e, ++ 0xbc, 0x56, 0xe2, 0xe4, 0xdf, 0xfb, 0xeb, 0x61, ++ 0xfa, 0x24, 0xc1, 0x63, 0x75, 0xbb, 0x47, 0x75, ++ 0xaf, 0xe1, 0x53, 0x16, 0x96, 0x21, 0x85, 0x26, ++ 0x11, 0xb3, 0x76, 0xe3, 0x23, 0xa1, 0x6b, 0x74, ++ 0x37, 0xd0, 0xde, 0x06, 0x90, 0x71, 0x5d, 0x43, ++ 0x88, 0x9b, 0x00, 0x54, 0xa6, 0x75, 0x2f, 0xa1, ++ 0xc2, 0x0b, 0x73, 0x20, 0x1d, 0xb6, 0x21, 0x79, ++ 0x57, 0x3f, 0xfa, 0x09, 0xbe, 0x8a, 0x33, 0xc3, ++ 0x52, 0xf0, 0x1d, 0x82, 0x31, 0xd1, 0x55, 0xb5, ++ 0x6c, 0x99, 0x25, 0xcf, 0x5c, 0x32, 0xce, 0xe9, ++ 0x0d, 0xfa, 0x69, 0x2c, 0xd5, 0x0d, 0xc5, 0x6d, ++ 0x86, 0xd0, 0x0c, 0x3b, 0x06, 0x50, 0x79, 0xe8, ++ 0xc3, 0xae, 0x04, 0xe6, 0xcd, 0x51, 0xe4, 0x26, ++ 0x9b, 0x4f, 0x7e, 0xa6, 0x0f, 0xab, 0xd8, 0xe5, ++ 0xde, 0xa9, 0x00, 0x95, 0xbe, 0xa3, 0x9d, 0x5d, ++ 0xb2, 0x09, 0x70, 0x18, 0x1c, 0xf0, 0xac, 0x29, ++ 0x23, 0x02, 0x29, 0x28, 0xd2, 0x74, 0x35, 0x57, ++ 0x62, 0x0f, 0x24, 0xea, 0x5e, 0x33, 0xc2, 0x92, ++ 0xf3, 0x78, 0x4d, 0x30, 0x1e, 0xa1, 0x99, 0xa9, ++ 0x82, 0xb0, 0x42, 0x31, 0x8d, 0xad, 0x8a, 0xbc, ++ 0xfc, 0xd4, 0x57, 0x47, 0x3e, 0xb4, 0x50, 0xdd, ++ 0x6e, 0x2c, 0x80, 0x4d, 0x22, 0xf1, 0xfb, 0x57, ++ 0xc4, 0xdd, 0x17, 0xe1, 0x8a, 0x36, 0x4a, 0xb3, ++ 0x37, 0xca, 0xc9, 0x4e, 0xab, 0xd5, 0x69, 0xc4, ++ 0xf4, 0xbc, 0x0b, 0x3b, 0x44, 0x4b, 0x29, 0x9c, ++ 0xee, 0xd4, 0x35, 0x22, 0x21, 0xb0, 0x1f, 0x27, ++ 0x64, 0xa8, 0x51, 0x1b, 0xf0, 0x9f, 0x19, 0x5c, ++ 0xfb, 0x5a, 0x64, 0x74, 0x70, 0x45, 0x09, 0xf5, ++ 0x64, 0xfe, 0x1a, 0x2d, 0xc9, 0x14, 0x04, 0x14, ++ 0xcf, 0xd5, 0x7d, 0x60, 0xaf, 0x94, 0x39, 0x94, ++ 0xe2, 0x7d, 0x79, 0x82, 0xd0, 0x65, 0x3b, 0x6b, ++ 0x9c, 0x19, 0x84, 0xb4, 0x6d, 0xb3, 0x0c, 0x99, ++ 0xc0, 0x56, 0xa8, 0xbd, 0x73, 0xce, 0x05, 0x84, ++ 0x3e, 0x30, 0xaa, 0xc4, 0x9b, 0x1b, 0x04, 0x2a, ++ 0x9f, 0xd7, 0x43, 0x2b, 0x23, 0xdf, 0xbf, 0xaa, ++ 0xd5, 0xc2, 0x43, 0x2d, 0x70, 0xab, 0xdc, 0x75, ++ 0xad, 0xac, 0xf7, 0xc0, 0xbe, 0x67, 0xb2, 0x74, ++ 0xed, 0x67, 0x10, 0x4a, 0x92, 0x60, 0xc1, 0x40, ++ 0x50, 0x19, 0x8a, 0x8a, 0x8c, 0x09, 0x0e, 0x72, ++ 0xe1, 0x73, 0x5e, 0xe8, 0x41, 0x85, 0x63, 0x9f, ++ 0x3f, 0xd7, 0x7d, 0xc4, 0xfb, 0x22, 0x5d, 0x92, ++ 0x6c, 0xb3, 0x1e, 0xe2, 0x50, 0x2f, 0x82, 0xa8, ++ 0x28, 0xc0, 0xb5, 0xd7, 0x5f, 0x68, 0x0d, 0x2c, ++ 0x2d, 0xaf, 0x7e, 0xfa, 0x2e, 0x08, 0x0f, 0x1f, ++ 0x70, 0x9f, 0xe9, 0x19, 0x72, 0x55, 0xf8, 0xfb, ++ 0x51, 0xd2, 0x33, 0x5d, 0xa0, 0xd3, 0x2b, 0x0a, ++ 0x6c, 0xbc, 0x4e, 0xcf, 0x36, 0x4d, 0xdc, 0x3b, ++ 0xe9, 0x3e, 0x81, 0x7c, 0x61, 0xdb, 0x20, 0x2d, ++ 0x3a, 0xc3, 0xb3, 0x0c, 0x1e, 0x00, 0xb9, 0x7c, ++ 0xf5, 0xca, 0x10, 0x5f, 0x3a, 0x71, 0xb3, 0xe4, ++ 0x20, 0xdb, 0x0c, 0x2a, 0x98, 0x63, 0x45, 0x00, ++ 0x58, 0xf6, 0x68, 0xe4, 0x0b, 0xda, 0x13, 0x3b, ++ 0x60, 0x5c, 0x76, 0xdb, 0xb9, 0x97, 0x71, 0xe4, ++ 0xd9, 0xb7, 0xdb, 0xbd, 0x68, 0xc7, 0x84, 0x84, ++ 0xaa, 0x7c, 0x68, 0x62, 0x5e, 0x16, 0xfc, 0xba, ++ 0x72, 0xaa, 0x9a, 0xa9, 0xeb, 0x7c, 0x75, 0x47, ++ 0x97, 0x7e, 0xad, 0xe2, 0xd9, 0x91, 0xe8, 0xe4, ++ 0xa5, 0x31, 0xd7, 0x01, 0x8e, 0xa2, 0x11, 0x88, ++ 0x95, 0xb9, 0xf2, 0x9b, 0xd3, 0x7f, 0x1b, 0x81, ++ 0x22, 0xf7, 0x98, 0x60, 0x0a, 0x64, 0xa6, 0xc1, ++ 0xf6, 0x49, 0xc7, 0xe3, 0x07, 0x4d, 0x94, 0x7a, ++ 0xcf, 0x6e, 0x68, 0x0c, 0x1b, 0x3f, 0x6e, 0x2e, ++ 0xee, 0x92, 0xfa, 0x52, 0xb3, 0x59, 0xf8, 0xf1, ++ 0x8f, 0x6a, 0x66, 0xa3, 0x82, 0x76, 0x4a, 0x07, ++ 0x1a, 0xc7, 0xdd, 0xf5, 0xda, 0x9c, 0x3c, 0x24, ++ 0xbf, 0xfd, 0x42, 0xa1, 0x10, 0x64, 0x6a, 0x0f, ++ 0x89, 0xee, 0x36, 0xa5, 0xce, 0x99, 0x48, 0x6a, ++ 0xf0, 0x9f, 0x9e, 0x69, 0xa4, 0x40, 0x20, 0xe9, ++ 0x16, 0x15, 0xf7, 0xdb, 0x75, 0x02, 0xcb, 0xe9, ++ 0x73, 0x8b, 0x3b, 0x49, 0x2f, 0xf0, 0xaf, 0x51, ++ 0x06, 0x5c, 0xdf, 0x27, 0x27, 0x49, 0x6a, 0xd1, ++ 0xcc, 0xc7, 0xb5, 0x63, 0xb5, 0xfc, 0xb8, 0x5c, ++ 0x87, 0x7f, 0x84, 0xb4, 0xcc, 0x14, 0xa9, 0x53, ++ 0xda, 0xa4, 0x56, 0xf8, 0xb6, 0x1b, 0xcc, 0x40, ++ 0x27, 0x52, 0x06, 0x5a, 0x13, 0x81, 0xd7, 0x3a, ++ 0xd4, 0x3b, 0xfb, 0x49, 0x65, 0x31, 0x33, 0xb2, ++ 0xfa, 0xcd, 0xad, 0x58, 0x4e, 0x2b, 0xae, 0xd2, ++ 0x20, 0xfb, 0x1a, 0x48, 0xb4, 0x3f, 0x9a, 0xd8, ++ 0x7a, 0x35, 0x4a, 0xc8, 0xee, 0x88, 0x5e, 0x07, ++ 0x66, 0x54, 0xb9, 0xec, 0x9f, 0xa3, 0xe3, 0xb9, ++ 0x37, 0xaa, 0x49, 0x76, 0x31, 0xda, 0x74, 0x2d, ++ 0x3c, 0xa4, 0x65, 0x10, 0x32, 0x38, 0xf0, 0xde, ++ 0xd3, 0x99, 0x17, 0xaa, 0x71, 0xaa, 0x8f, 0x0f, ++ 0x8c, 0xaf, 0xa2, 0xf8, 0x5d, 0x64, 0xba, 0x1d, ++ 0xa3, 0xef, 0x96, 0x73, 0xe8, 0xa1, 0x02, 0x8d, ++ 0x0c, 0x6d, 0xb8, 0x06, 0x90, 0xb8, 0x08, 0x56, ++ 0x2c, 0xa7, 0x06, 0xc9, 0xc2, 0x38, 0xdb, 0x7c, ++ 0x63, 0xb1, 0x57, 0x8e, 0xea, 0x7c, 0x79, 0xf3, ++ 0x49, 0x1d, 0xfe, 0x9f, 0xf3, 0x6e, 0xb1, 0x1d, ++ 0xba, 0x19, 0x80, 0x1a, 0x0a, 0xd3, 0xb0, 0x26, ++ 0x21, 0x40, 0xb1, 0x7c, 0xf9, 0x4d, 0x8d, 0x10, ++ 0xc1, 0x7e, 0xf4, 0xf6, 0x3c, 0xa8, 0xfd, 0x7c, ++ 0xa3, 0x92, 0xb2, 0x0f, 0xaa, 0xcc, 0xa6, 0x11, ++ 0xfe, 0x04, 0xe3, 0xd1, 0x7a, 0x32, 0x89, 0xdf, ++ 0x0d, 0xc4, 0x8f, 0x79, 0x6b, 0xca, 0x16, 0x7c, ++ 0x6e, 0xf9, 0xad, 0x0f, 0xf6, 0xfe, 0x27, 0xdb, ++ 0xc4, 0x13, 0x70, 0xf1, 0x62, 0x1a, 0x4f, 0x79, ++ 0x40, 0xc9, 0x9b, 0x8b, 0x21, 0xea, 0x84, 0xfa, ++ 0xf5, 0xf1, 0x89, 0xce, 0xb7, 0x55, 0x0a, 0x80, ++ 0x39, 0x2f, 0x55, 0x36, 0x16, 0x9c, 0x7b, 0x08, ++ 0xbd, 0x87, 0x0d, 0xa5, 0x32, 0xf1, 0x52, 0x7c, ++ 0xe8, 0x55, 0x60, 0x5b, 0xd7, 0x69, 0xe4, 0xfc, ++ 0xfa, 0x12, 0x85, 0x96, 0xea, 0x50, 0x28, 0xab, ++ 0x8a, 0xf7, 0xbb, 0x0e, 0x53, 0x74, 0xca, 0xa6, ++ 0x27, 0x09, 0xc2, 0xb5, 0xde, 0x18, 0x14, 0xd9, ++ 0xea, 0xe5, 0x29, 0x1c, 0x40, 0x56, 0xcf, 0xd7, ++ 0xae, 0x05, 0x3f, 0x65, 0xaf, 0x05, 0x73, 0xe2, ++ 0x35, 0x96, 0x27, 0x07, 0x14, 0xc0, 0xad, 0x33, ++ 0xf1, 0xdc, 0x44, 0x7a, 0x89, 0x17, 0x77, 0xd2, ++ 0x9c, 0x58, 0x60, 0xf0, 0x3f, 0x7b, 0x2d, 0x2e, ++ 0x57, 0x95, 0x54, 0x87, 0xed, 0xf2, 0xc7, 0x4c, ++ 0xf0, 0xae, 0x56, 0x29, 0x19, 0x7d, 0x66, 0x4b, ++ 0x9b, 0x83, 0x84, 0x42, 0x3b, 0x01, 0x25, 0x66, ++ 0x8e, 0x02, 0xde, 0xb9, 0x83, 0x54, 0x19, 0xf6, ++ 0x9f, 0x79, 0x0d, 0x67, 0xc5, 0x1d, 0x7a, 0x44, ++ 0x02, 0x98, 0xa7, 0x16, 0x1c, 0x29, 0x0d, 0x74, ++ 0xff, 0x85, 0x40, 0x06, 0xef, 0x2c, 0xa9, 0xc6, ++ 0xf5, 0x53, 0x07, 0x06, 0xae, 0xe4, 0xfa, 0x5f, ++ 0xd8, 0x39, 0x4d, 0xf1, 0x9b, 0x6b, 0xd9, 0x24, ++ 0x84, 0xfe, 0x03, 0x4c, 0xb2, 0x3f, 0xdf, 0xa1, ++ 0x05, 0x9e, 0x50, 0x14, 0x5a, 0xd9, 0x1a, 0xa2, ++ 0xa7, 0xfa, 0xfa, 0x17, 0xf7, 0x78, 0xd6, 0xb5, ++ 0x92, 0x61, 0x91, 0xac, 0x36, 0xfa, 0x56, 0x0d, ++ 0x38, 0x32, 0x18, 0x85, 0x08, 0x58, 0x37, 0xf0, ++ 0x4b, 0xdb, 0x59, 0xe7, 0xa4, 0x34, 0xc0, 0x1b, ++ 0x01, 0xaf, 0x2d, 0xde, 0xa1, 0xaa, 0x5d, 0xd3, ++ 0xec, 0xe1, 0xd4, 0xf7, 0xe6, 0x54, 0x68, 0xf0, ++ 0x51, 0x97, 0xa7, 0x89, 0xea, 0x24, 0xad, 0xd3, ++ 0x6e, 0x47, 0x93, 0x8b, 0x4b, 0xb4, 0xf7, 0x1c, ++ 0x42, 0x06, 0x67, 0xe8, 0x99, 0xf6, 0xf5, 0x7b, ++ 0x85, 0xb5, 0x65, 0xb5, 0xb5, 0xd2, 0x37, 0xf5, ++ 0xf3, 0x02, 0xa6, 0x4d, 0x11, 0xa7, 0xdc, 0x51, ++ 0x09, 0x7f, 0xa0, 0xd8, 0x88, 0x1c, 0x13, 0x71, ++ 0xae, 0x9c, 0xb7, 0x7b, 0x34, 0xd6, 0x4e, 0x68, ++ 0x26, 0x83, 0x51, 0xaf, 0x1d, 0xee, 0x8b, 0xbb, ++ 0x69, 0x43, 0x2b, 0x9e, 0x8a, 0xbc, 0x02, 0x0e, ++ 0xa0, 0x1b, 0xe0, 0xa8, 0x5f, 0x6f, 0xaf, 0x1b, ++ 0x8f, 0xe7, 0x64, 0x71, 0x74, 0x11, 0x7e, 0xa8, ++ 0xd8, 0xf9, 0x97, 0x06, 0xc3, 0xb6, 0xfb, 0xfb, ++ 0xb7, 0x3d, 0x35, 0x9d, 0x3b, 0x52, 0xed, 0x54, ++ 0xca, 0xf4, 0x81, 0x01, 0x2d, 0x1b, 0xc3, 0xa7, ++ 0x00, 0x3d, 0x1a, 0x39, 0x54, 0xe1, 0xf6, 0xff, ++ 0xed, 0x6f, 0x0b, 0x5a, 0x68, 0xda, 0x58, 0xdd, ++ 0xa9, 0xcf, 0x5c, 0x4a, 0xe5, 0x09, 0x4e, 0xde, ++ 0x9d, 0xbc, 0x3e, 0xee, 0x5a, 0x00, 0x3b, 0x2c, ++ 0x87, 0x10, 0x65, 0x60, 0xdd, 0xd7, 0x56, 0xd1, ++ 0x4c, 0x64, 0x45, 0xe4, 0x21, 0xec, 0x78, 0xf8, ++ 0x25, 0x7a, 0x3e, 0x16, 0x5d, 0x09, 0x53, 0x14, ++ 0xbe, 0x4f, 0xae, 0x87, 0xd8, 0xd1, 0xaa, 0x3c, ++ 0xf6, 0x3e, 0xa4, 0x70, 0x8c, 0x5e, 0x70, 0xa4, ++ 0xb3, 0x6b, 0x66, 0x73, 0xd3, 0xbf, 0x31, 0x06, ++ 0x19, 0x62, 0x93, 0x15, 0xf2, 0x86, 0xe4, 0x52, ++ 0x7e, 0x53, 0x4c, 0x12, 0x38, 0xcc, 0x34, 0x7d, ++ 0x57, 0xf6, 0x42, 0x93, 0x8a, 0xc4, 0xee, 0x5c, ++ 0x8a, 0xe1, 0x52, 0x8f, 0x56, 0x64, 0xf6, 0xa6, ++ 0xd1, 0x91, 0x57, 0x70, 0xcd, 0x11, 0x76, 0xf5, ++ 0x59, 0x60, 0x60, 0x3c, 0xc1, 0xc3, 0x0b, 0x7f, ++ 0x58, 0x1a, 0x50, 0x91, 0xf1, 0x68, 0x8f, 0x6e, ++ 0x74, 0x74, 0xa8, 0x51, 0x0b, 0xf7, 0x7a, 0x98, ++ 0x37, 0xf2, 0x0a, 0x0e, 0xa4, 0x97, 0x04, 0xb8, ++ 0x9b, 0xfd, 0xa0, 0xea, 0xf7, 0x0d, 0xe1, 0xdb, ++ 0x03, 0xf0, 0x31, 0x29, 0xf8, 0xdd, 0x6b, 0x8b, ++ 0x5d, 0xd8, 0x59, 0xa9, 0x29, 0xcf, 0x9a, 0x79, ++ 0x89, 0x19, 0x63, 0x46, 0x09, 0x79, 0x6a, 0x11, ++ 0xda, 0x63, 0x68, 0x48, 0x77, 0x23, 0xfb, 0x7d, ++ 0x3a, 0x43, 0xcb, 0x02, 0x3b, 0x7a, 0x6d, 0x10, ++ 0x2a, 0x9e, 0xac, 0xf1, 0xd4, 0x19, 0xf8, 0x23, ++ 0x64, 0x1d, 0x2c, 0x5f, 0xf2, 0xb0, 0x5c, 0x23, ++ 0x27, 0xf7, 0x27, 0x30, 0x16, 0x37, 0xb1, 0x90, ++ 0xab, 0x38, 0xfb, 0x55, 0xcd, 0x78, 0x58, 0xd4, ++ 0x7d, 0x43, 0xf6, 0x45, 0x5e, 0x55, 0x8d, 0xb1, ++ 0x02, 0x65, 0x58, 0xb4, 0x13, 0x4b, 0x36, 0xf7, ++ 0xcc, 0xfe, 0x3d, 0x0b, 0x82, 0xe2, 0x12, 0x11, ++ 0xbb, 0xe6, 0xb8, 0x3a, 0x48, 0x71, 0xc7, 0x50, ++ 0x06, 0x16, 0x3a, 0xe6, 0x7c, 0x05, 0xc7, 0xc8, ++ 0x4d, 0x2f, 0x08, 0x6a, 0x17, 0x9a, 0x95, 0x97, ++ 0x50, 0x68, 0xdc, 0x28, 0x18, 0xc4, 0x61, 0x38, ++ 0xb9, 0xe0, 0x3e, 0x78, 0xdb, 0x29, 0xe0, 0x9f, ++ 0x52, 0xdd, 0xf8, 0x4f, 0x91, 0xc1, 0xd0, 0x33, ++ 0xa1, 0x7a, 0x8e, 0x30, 0x13, 0x82, 0x07, 0x9f, ++ 0xd3, 0x31, 0x0f, 0x23, 0xbe, 0x32, 0x5a, 0x75, ++ 0xcf, 0x96, 0xb2, 0xec, 0xb5, 0x32, 0xac, 0x21, ++ 0xd1, 0x82, 0x33, 0xd3, 0x15, 0x74, 0xbd, 0x90, ++ 0xf1, 0x2c, 0xe6, 0x5f, 0x8d, 0xe3, 0x02, 0xe8, ++ 0xe9, 0xc4, 0xca, 0x96, 0xeb, 0x0e, 0xbc, 0x91, ++ 0xf4, 0xb9, 0xea, 0xd9, 0x1b, 0x75, 0xbd, 0xe1, ++ 0xac, 0x2a, 0x05, 0x37, 0x52, 0x9b, 0x1b, 0x3f, ++ 0x5a, 0xdc, 0x21, 0xc3, 0x98, 0xbb, 0xaf, 0xa3, ++ 0xf2, 0x00, 0xbf, 0x0d, 0x30, 0x89, 0x05, 0xcc, ++ 0xa5, 0x76, 0xf5, 0x06, 0xf0, 0xc6, 0x54, 0x8a, ++ 0x5d, 0xd4, 0x1e, 0xc1, 0xf2, 0xce, 0xb0, 0x62, ++ 0xc8, 0xfc, 0x59, 0x42, 0x9a, 0x90, 0x60, 0x55, ++ 0xfe, 0x88, 0xa5, 0x8b, 0xb8, 0x33, 0x0c, 0x23, ++ 0x24, 0x0d, 0x15, 0x70, 0x37, 0x1e, 0x3d, 0xf6, ++ 0xd2, 0xea, 0x92, 0x10, 0xb2, 0xc4, 0x51, 0xac, ++ 0xf2, 0xac, 0xf3, 0x6b, 0x6c, 0xaa, 0xcf, 0x12, ++ 0xc5, 0x6c, 0x90, 0x50, 0xb5, 0x0c, 0xfc, 0x1a, ++ 0x15, 0x52, 0xe9, 0x26, 0xc6, 0x52, 0xa4, 0xe7, ++ 0x81, 0x69, 0xe1, 0xe7, 0x9e, 0x30, 0x01, 0xec, ++ 0x84, 0x89, 0xb2, 0x0d, 0x66, 0xdd, 0xce, 0x28, ++ 0x5c, 0xec, 0x98, 0x46, 0x68, 0x21, 0x9f, 0x88, ++ 0x3f, 0x1f, 0x42, 0x77, 0xce, 0xd0, 0x61, 0xd4, ++ 0x20, 0xa7, 0xff, 0x53, 0xad, 0x37, 0xd0, 0x17, ++ 0x35, 0xc9, 0xfc, 0xba, 0x0a, 0x78, 0x3f, 0xf2, ++ 0xcc, 0x86, 0x89, 0xe8, 0x4b, 0x3c, 0x48, 0x33, ++ 0x09, 0x7f, 0xc6, 0xc0, 0xdd, 0xb8, 0xfd, 0x7a, ++ 0x66, 0x66, 0x65, 0xeb, 0x47, 0xa7, 0x04, 0x28, ++ 0xa3, 0x19, 0x8e, 0xa9, 0xb1, 0x13, 0x67, 0x62, ++ 0x70, 0xcf, 0xd6 ++}; ++static const u8 dec_output012[] __initconst = { ++ 0x74, 0xa6, 0x3e, 0xe4, 0xb1, 0xcb, 0xaf, 0xb0, ++ 0x40, 0xe5, 0x0f, 0x9e, 0xf1, 0xf2, 0x89, 0xb5, ++ 0x42, 0x34, 0x8a, 0xa1, 0x03, 0xb7, 0xe9, 0x57, ++ 0x46, 0xbe, 0x20, 0xe4, 0x6e, 0xb0, 0xeb, 0xff, ++ 0xea, 0x07, 0x7e, 0xef, 0xe2, 0x55, 0x9f, 0xe5, ++ 0x78, 0x3a, 0xb7, 0x83, 0xc2, 0x18, 0x40, 0x7b, ++ 0xeb, 0xcd, 0x81, 0xfb, 0x90, 0x12, 0x9e, 0x46, ++ 0xa9, 0xd6, 0x4a, 0xba, 0xb0, 0x62, 0xdb, 0x6b, ++ 0x99, 0xc4, 0xdb, 0x54, 0x4b, 0xb8, 0xa5, 0x71, ++ 0xcb, 0xcd, 0x63, 0x32, 0x55, 0xfb, 0x31, 0xf0, ++ 0x38, 0xf5, 0xbe, 0x78, 0xe4, 0x45, 0xce, 0x1b, ++ 0x6a, 0x5b, 0x0e, 0xf4, 0x16, 0xe4, 0xb1, 0x3d, ++ 0xf6, 0x63, 0x7b, 0xa7, 0x0c, 0xde, 0x6f, 0x8f, ++ 0x74, 0xdf, 0xe0, 0x1e, 0x9d, 0xce, 0x8f, 0x24, ++ 0xef, 0x23, 0x35, 0x33, 0x7b, 0x83, 0x34, 0x23, ++ 0x58, 0x74, 0x14, 0x77, 0x1f, 0xc2, 0x4f, 0x4e, ++ 0xc6, 0x89, 0xf9, 0x52, 0x09, 0x37, 0x64, 0x14, ++ 0xc4, 0x01, 0x6b, 0x9d, 0x77, 0xe8, 0x90, 0x5d, ++ 0xa8, 0x4a, 0x2a, 0xef, 0x5c, 0x7f, 0xeb, 0xbb, ++ 0xb2, 0xc6, 0x93, 0x99, 0x66, 0xdc, 0x7f, 0xd4, ++ 0x9e, 0x2a, 0xca, 0x8d, 0xdb, 0xe7, 0x20, 0xcf, ++ 0xe4, 0x73, 0xae, 0x49, 0x7d, 0x64, 0x0f, 0x0e, ++ 0x28, 0x46, 0xa9, 0xa8, 0x32, 0xe4, 0x0e, 0xf6, ++ 0x51, 0x53, 0xb8, 0x3c, 0xb1, 0xff, 0xa3, 0x33, ++ 0x41, 0x75, 0xff, 0xf1, 0x6f, 0xf1, 0xfb, 0xbb, ++ 0x83, 0x7f, 0x06, 0x9b, 0xe7, 0x1b, 0x0a, 0xe0, ++ 0x5c, 0x33, 0x60, 0x5b, 0xdb, 0x5b, 0xed, 0xfe, ++ 0xa5, 0x16, 0x19, 0x72, 0xa3, 0x64, 0x23, 0x00, ++ 0x02, 0xc7, 0xf3, 0x6a, 0x81, 0x3e, 0x44, 0x1d, ++ 0x79, 0x15, 0x5f, 0x9a, 0xde, 0xe2, 0xfd, 0x1b, ++ 0x73, 0xc1, 0xbc, 0x23, 0xba, 0x31, 0xd2, 0x50, ++ 0xd5, 0xad, 0x7f, 0x74, 0xa7, 0xc9, 0xf8, 0x3e, ++ 0x2b, 0x26, 0x10, 0xf6, 0x03, 0x36, 0x74, 0xe4, ++ 0x0e, 0x6a, 0x72, 0xb7, 0x73, 0x0a, 0x42, 0x28, ++ 0xc2, 0xad, 0x5e, 0x03, 0xbe, 0xb8, 0x0b, 0xa8, ++ 0x5b, 0xd4, 0xb8, 0xba, 0x52, 0x89, 0xb1, 0x9b, ++ 0xc1, 0xc3, 0x65, 0x87, 0xed, 0xa5, 0xf4, 0x86, ++ 0xfd, 0x41, 0x80, 0x91, 0x27, 0x59, 0x53, 0x67, ++ 0x15, 0x78, 0x54, 0x8b, 0x2d, 0x3d, 0xc7, 0xff, ++ 0x02, 0x92, 0x07, 0x5f, 0x7a, 0x4b, 0x60, 0x59, ++ 0x3c, 0x6f, 0x5c, 0xd8, 0xec, 0x95, 0xd2, 0xfe, ++ 0xa0, 0x3b, 0xd8, 0x3f, 0xd1, 0x69, 0xa6, 0xd6, ++ 0x41, 0xb2, 0xf4, 0x4d, 0x12, 0xf4, 0x58, 0x3e, ++ 0x66, 0x64, 0x80, 0x31, 0x9b, 0xa8, 0x4c, 0x8b, ++ 0x07, 0xb2, 0xec, 0x66, 0x94, 0x66, 0x47, 0x50, ++ 0x50, 0x5f, 0x18, 0x0b, 0x0e, 0xd6, 0xc0, 0x39, ++ 0x21, 0x13, 0x9e, 0x33, 0xbc, 0x79, 0x36, 0x02, ++ 0x96, 0x70, 0xf0, 0x48, 0x67, 0x2f, 0x26, 0xe9, ++ 0x6d, 0x10, 0xbb, 0xd6, 0x3f, 0xd1, 0x64, 0x7a, ++ 0x2e, 0xbe, 0x0c, 0x61, 0xf0, 0x75, 0x42, 0x38, ++ 0x23, 0xb1, 0x9e, 0x9f, 0x7c, 0x67, 0x66, 0xd9, ++ 0x58, 0x9a, 0xf1, 0xbb, 0x41, 0x2a, 0x8d, 0x65, ++ 0x84, 0x94, 0xfc, 0xdc, 0x6a, 0x50, 0x64, 0xdb, ++ 0x56, 0x33, 0x76, 0x00, 0x10, 0xed, 0xbe, 0xd2, ++ 0x12, 0xf6, 0xf6, 0x1b, 0xa2, 0x16, 0xde, 0xae, ++ 0x31, 0x95, 0xdd, 0xb1, 0x08, 0x7e, 0x4e, 0xee, ++ 0xe7, 0xf9, 0xa5, 0xfb, 0x5b, 0x61, 0x43, 0x00, ++ 0x40, 0xf6, 0x7e, 0x02, 0x04, 0x32, 0x4e, 0x0c, ++ 0xe2, 0x66, 0x0d, 0xd7, 0x07, 0x98, 0x0e, 0xf8, ++ 0x72, 0x34, 0x6d, 0x95, 0x86, 0xd7, 0xcb, 0x31, ++ 0x54, 0x47, 0xd0, 0x38, 0x29, 0x9c, 0x5a, 0x68, ++ 0xd4, 0x87, 0x76, 0xc9, 0xe7, 0x7e, 0xe3, 0xf4, ++ 0x81, 0x6d, 0x18, 0xcb, 0xc9, 0x05, 0xaf, 0xa0, ++ 0xfb, 0x66, 0xf7, 0xf1, 0x1c, 0xc6, 0x14, 0x11, ++ 0x4f, 0x2b, 0x79, 0x42, 0x8b, 0xbc, 0xac, 0xe7, ++ 0x6c, 0xfe, 0x0f, 0x58, 0xe7, 0x7c, 0x78, 0x39, ++ 0x30, 0xb0, 0x66, 0x2c, 0x9b, 0x6d, 0x3a, 0xe1, ++ 0xcf, 0xc9, 0xa4, 0x0e, 0x6d, 0x6d, 0x8a, 0xa1, ++ 0x3a, 0xe7, 0x28, 0xd4, 0x78, 0x4c, 0xa6, 0xa2, ++ 0x2a, 0xa6, 0x03, 0x30, 0xd7, 0xa8, 0x25, 0x66, ++ 0x87, 0x2f, 0x69, 0x5c, 0x4e, 0xdd, 0xa5, 0x49, ++ 0x5d, 0x37, 0x4a, 0x59, 0xc4, 0xaf, 0x1f, 0xa2, ++ 0xe4, 0xf8, 0xa6, 0x12, 0x97, 0xd5, 0x79, 0xf5, ++ 0xe2, 0x4a, 0x2b, 0x5f, 0x61, 0xe4, 0x9e, 0xe3, ++ 0xee, 0xb8, 0xa7, 0x5b, 0x2f, 0xf4, 0x9e, 0x6c, ++ 0xfb, 0xd1, 0xc6, 0x56, 0x77, 0xba, 0x75, 0xaa, ++ 0x3d, 0x1a, 0xa8, 0x0b, 0xb3, 0x68, 0x24, 0x00, ++ 0x10, 0x7f, 0xfd, 0xd7, 0xa1, 0x8d, 0x83, 0x54, ++ 0x4f, 0x1f, 0xd8, 0x2a, 0xbe, 0x8a, 0x0c, 0x87, ++ 0xab, 0xa2, 0xde, 0xc3, 0x39, 0xbf, 0x09, 0x03, ++ 0xa5, 0xf3, 0x05, 0x28, 0xe1, 0xe1, 0xee, 0x39, ++ 0x70, 0x9c, 0xd8, 0x81, 0x12, 0x1e, 0x02, 0x40, ++ 0xd2, 0x6e, 0xf0, 0xeb, 0x1b, 0x3d, 0x22, 0xc6, ++ 0xe5, 0xe3, 0xb4, 0x5a, 0x98, 0xbb, 0xf0, 0x22, ++ 0x28, 0x8d, 0xe5, 0xd3, 0x16, 0x48, 0x24, 0xa5, ++ 0xe6, 0x66, 0x0c, 0xf9, 0x08, 0xf9, 0x7e, 0x1e, ++ 0xe1, 0x28, 0x26, 0x22, 0xc7, 0xc7, 0x0a, 0x32, ++ 0x47, 0xfa, 0xa3, 0xbe, 0x3c, 0xc4, 0xc5, 0x53, ++ 0x0a, 0xd5, 0x94, 0x4a, 0xd7, 0x93, 0xd8, 0x42, ++ 0x99, 0xb9, 0x0a, 0xdb, 0x56, 0xf7, 0xb9, 0x1c, ++ 0x53, 0x4f, 0xfa, 0xd3, 0x74, 0xad, 0xd9, 0x68, ++ 0xf1, 0x1b, 0xdf, 0x61, 0xc6, 0x5e, 0xa8, 0x48, ++ 0xfc, 0xd4, 0x4a, 0x4c, 0x3c, 0x32, 0xf7, 0x1c, ++ 0x96, 0x21, 0x9b, 0xf9, 0xa3, 0xcc, 0x5a, 0xce, ++ 0xd5, 0xd7, 0x08, 0x24, 0xf6, 0x1c, 0xfd, 0xdd, ++ 0x38, 0xc2, 0x32, 0xe9, 0xb8, 0xe7, 0xb6, 0xfa, ++ 0x9d, 0x45, 0x13, 0x2c, 0x83, 0xfd, 0x4a, 0x69, ++ 0x82, 0xcd, 0xdc, 0xb3, 0x76, 0x0c, 0x9e, 0xd8, ++ 0xf4, 0x1b, 0x45, 0x15, 0xb4, 0x97, 0xe7, 0x58, ++ 0x34, 0xe2, 0x03, 0x29, 0x5a, 0xbf, 0xb6, 0xe0, ++ 0x5d, 0x13, 0xd9, 0x2b, 0xb4, 0x80, 0xb2, 0x45, ++ 0x81, 0x6a, 0x2e, 0x6c, 0x89, 0x7d, 0xee, 0xbb, ++ 0x52, 0xdd, 0x1f, 0x18, 0xe7, 0x13, 0x6b, 0x33, ++ 0x0e, 0xea, 0x36, 0x92, 0x77, 0x7b, 0x6d, 0x9c, ++ 0x5a, 0x5f, 0x45, 0x7b, 0x7b, 0x35, 0x62, 0x23, ++ 0xd1, 0xbf, 0x0f, 0xd0, 0x08, 0x1b, 0x2b, 0x80, ++ 0x6b, 0x7e, 0xf1, 0x21, 0x47, 0xb0, 0x57, 0xd1, ++ 0x98, 0x72, 0x90, 0x34, 0x1c, 0x20, 0x04, 0xff, ++ 0x3d, 0x5c, 0xee, 0x0e, 0x57, 0x5f, 0x6f, 0x24, ++ 0x4e, 0x3c, 0xea, 0xfc, 0xa5, 0xa9, 0x83, 0xc9, ++ 0x61, 0xb4, 0x51, 0x24, 0xf8, 0x27, 0x5e, 0x46, ++ 0x8c, 0xb1, 0x53, 0x02, 0x96, 0x35, 0xba, 0xb8, ++ 0x4c, 0x71, 0xd3, 0x15, 0x59, 0x35, 0x22, 0x20, ++ 0xad, 0x03, 0x9f, 0x66, 0x44, 0x3b, 0x9c, 0x35, ++ 0x37, 0x1f, 0x9b, 0xbb, 0xf3, 0xdb, 0x35, 0x63, ++ 0x30, 0x64, 0xaa, 0xa2, 0x06, 0xa8, 0x5d, 0xbb, ++ 0xe1, 0x9f, 0x70, 0xec, 0x82, 0x11, 0x06, 0x36, ++ 0xec, 0x8b, 0x69, 0x66, 0x24, 0x44, 0xc9, 0x4a, ++ 0x57, 0xbb, 0x9b, 0x78, 0x13, 0xce, 0x9c, 0x0c, ++ 0xba, 0x92, 0x93, 0x63, 0xb8, 0xe2, 0x95, 0x0f, ++ 0x0f, 0x16, 0x39, 0x52, 0xfd, 0x3a, 0x6d, 0x02, ++ 0x4b, 0xdf, 0x13, 0xd3, 0x2a, 0x22, 0xb4, 0x03, ++ 0x7c, 0x54, 0x49, 0x96, 0x68, 0x54, 0x10, 0xfa, ++ 0xef, 0xaa, 0x6c, 0xe8, 0x22, 0xdc, 0x71, 0x16, ++ 0x13, 0x1a, 0xf6, 0x28, 0xe5, 0x6d, 0x77, 0x3d, ++ 0xcd, 0x30, 0x63, 0xb1, 0x70, 0x52, 0xa1, 0xc5, ++ 0x94, 0x5f, 0xcf, 0xe8, 0xb8, 0x26, 0x98, 0xf7, ++ 0x06, 0xa0, 0x0a, 0x70, 0xfa, 0x03, 0x80, 0xac, ++ 0xc1, 0xec, 0xd6, 0x4c, 0x54, 0xd7, 0xfe, 0x47, ++ 0xb6, 0x88, 0x4a, 0xf7, 0x71, 0x24, 0xee, 0xf3, ++ 0xd2, 0xc2, 0x4a, 0x7f, 0xfe, 0x61, 0xc7, 0x35, ++ 0xc9, 0x37, 0x67, 0xcb, 0x24, 0x35, 0xda, 0x7e, ++ 0xca, 0x5f, 0xf3, 0x8d, 0xd4, 0x13, 0x8e, 0xd6, ++ 0xcb, 0x4d, 0x53, 0x8f, 0x53, 0x1f, 0xc0, 0x74, ++ 0xf7, 0x53, 0xb9, 0x5e, 0x23, 0x37, 0xba, 0x6e, ++ 0xe3, 0x9d, 0x07, 0x55, 0x25, 0x7b, 0xe6, 0x2a, ++ 0x64, 0xd1, 0x32, 0xdd, 0x54, 0x1b, 0x4b, 0xc0, ++ 0xe1, 0xd7, 0x69, 0x58, 0xf8, 0x93, 0x29, 0xc4, ++ 0xdd, 0x23, 0x2f, 0xa5, 0xfc, 0x9d, 0x7e, 0xf8, ++ 0xd4, 0x90, 0xcd, 0x82, 0x55, 0xdc, 0x16, 0x16, ++ 0x9f, 0x07, 0x52, 0x9b, 0x9d, 0x25, 0xed, 0x32, ++ 0xc5, 0x7b, 0xdf, 0xf6, 0x83, 0x46, 0x3d, 0x65, ++ 0xb7, 0xef, 0x87, 0x7a, 0x12, 0x69, 0x8f, 0x06, ++ 0x7c, 0x51, 0x15, 0x4a, 0x08, 0xe8, 0xac, 0x9a, ++ 0x0c, 0x24, 0xa7, 0x27, 0xd8, 0x46, 0x2f, 0xe7, ++ 0x01, 0x0e, 0x1c, 0xc6, 0x91, 0xb0, 0x6e, 0x85, ++ 0x65, 0xf0, 0x29, 0x0d, 0x2e, 0x6b, 0x3b, 0xfb, ++ 0x4b, 0xdf, 0xe4, 0x80, 0x93, 0x03, 0x66, 0x46, ++ 0x3e, 0x8a, 0x6e, 0xf3, 0x5e, 0x4d, 0x62, 0x0e, ++ 0x49, 0x05, 0xaf, 0xd4, 0xf8, 0x21, 0x20, 0x61, ++ 0x1d, 0x39, 0x17, 0xf4, 0x61, 0x47, 0x95, 0xfb, ++ 0x15, 0x2e, 0xb3, 0x4f, 0xd0, 0x5d, 0xf5, 0x7d, ++ 0x40, 0xda, 0x90, 0x3c, 0x6b, 0xcb, 0x17, 0x00, ++ 0x13, 0x3b, 0x64, 0x34, 0x1b, 0xf0, 0xf2, 0xe5, ++ 0x3b, 0xb2, 0xc7, 0xd3, 0x5f, 0x3a, 0x44, 0xa6, ++ 0x9b, 0xb7, 0x78, 0x0e, 0x42, 0x5d, 0x4c, 0xc1, ++ 0xe9, 0xd2, 0xcb, 0xb7, 0x78, 0xd1, 0xfe, 0x9a, ++ 0xb5, 0x07, 0xe9, 0xe0, 0xbe, 0xe2, 0x8a, 0xa7, ++ 0x01, 0x83, 0x00, 0x8c, 0x5c, 0x08, 0xe6, 0x63, ++ 0x12, 0x92, 0xb7, 0xb7, 0xa6, 0x19, 0x7d, 0x38, ++ 0x13, 0x38, 0x92, 0x87, 0x24, 0xf9, 0x48, 0xb3, ++ 0x5e, 0x87, 0x6a, 0x40, 0x39, 0x5c, 0x3f, 0xed, ++ 0x8f, 0xee, 0xdb, 0x15, 0x82, 0x06, 0xda, 0x49, ++ 0x21, 0x2b, 0xb5, 0xbf, 0x32, 0x7c, 0x9f, 0x42, ++ 0x28, 0x63, 0xcf, 0xaf, 0x1e, 0xf8, 0xc6, 0xa0, ++ 0xd1, 0x02, 0x43, 0x57, 0x62, 0xec, 0x9b, 0x0f, ++ 0x01, 0x9e, 0x71, 0xd8, 0x87, 0x9d, 0x01, 0xc1, ++ 0x58, 0x77, 0xd9, 0xaf, 0xb1, 0x10, 0x7e, 0xdd, ++ 0xa6, 0x50, 0x96, 0xe5, 0xf0, 0x72, 0x00, 0x6d, ++ 0x4b, 0xf8, 0x2a, 0x8f, 0x19, 0xf3, 0x22, 0x88, ++ 0x11, 0x4a, 0x8b, 0x7c, 0xfd, 0xb7, 0xed, 0xe1, ++ 0xf6, 0x40, 0x39, 0xe0, 0xe9, 0xf6, 0x3d, 0x25, ++ 0xe6, 0x74, 0x3c, 0x58, 0x57, 0x7f, 0xe1, 0x22, ++ 0x96, 0x47, 0x31, 0x91, 0xba, 0x70, 0x85, 0x28, ++ 0x6b, 0x9f, 0x6e, 0x25, 0xac, 0x23, 0x66, 0x2f, ++ 0x29, 0x88, 0x28, 0xce, 0x8c, 0x5c, 0x88, 0x53, ++ 0xd1, 0x3b, 0xcc, 0x6a, 0x51, 0xb2, 0xe1, 0x28, ++ 0x3f, 0x91, 0xb4, 0x0d, 0x00, 0x3a, 0xe3, 0xf8, ++ 0xc3, 0x8f, 0xd7, 0x96, 0x62, 0x0e, 0x2e, 0xfc, ++ 0xc8, 0x6c, 0x77, 0xa6, 0x1d, 0x22, 0xc1, 0xb8, ++ 0xe6, 0x61, 0xd7, 0x67, 0x36, 0x13, 0x7b, 0xbb, ++ 0x9b, 0x59, 0x09, 0xa6, 0xdf, 0xf7, 0x6b, 0xa3, ++ 0x40, 0x1a, 0xf5, 0x4f, 0xb4, 0xda, 0xd3, 0xf3, ++ 0x81, 0x93, 0xc6, 0x18, 0xd9, 0x26, 0xee, 0xac, ++ 0xf0, 0xaa, 0xdf, 0xc5, 0x9c, 0xca, 0xc2, 0xa2, ++ 0xcc, 0x7b, 0x5c, 0x24, 0xb0, 0xbc, 0xd0, 0x6a, ++ 0x4d, 0x89, 0x09, 0xb8, 0x07, 0xfe, 0x87, 0xad, ++ 0x0a, 0xea, 0xb8, 0x42, 0xf9, 0x5e, 0xb3, 0x3e, ++ 0x36, 0x4c, 0xaf, 0x75, 0x9e, 0x1c, 0xeb, 0xbd, ++ 0xbc, 0xbb, 0x80, 0x40, 0xa7, 0x3a, 0x30, 0xbf, ++ 0xa8, 0x44, 0xf4, 0xeb, 0x38, 0xad, 0x29, 0xba, ++ 0x23, 0xed, 0x41, 0x0c, 0xea, 0xd2, 0xbb, 0x41, ++ 0x18, 0xd6, 0xb9, 0xba, 0x65, 0x2b, 0xa3, 0x91, ++ 0x6d, 0x1f, 0xa9, 0xf4, 0xd1, 0x25, 0x8d, 0x4d, ++ 0x38, 0xff, 0x64, 0xa0, 0xec, 0xde, 0xa6, 0xb6, ++ 0x79, 0xab, 0x8e, 0x33, 0x6c, 0x47, 0xde, 0xaf, ++ 0x94, 0xa4, 0xa5, 0x86, 0x77, 0x55, 0x09, 0x92, ++ 0x81, 0x31, 0x76, 0xc7, 0x34, 0x22, 0x89, 0x8e, ++ 0x3d, 0x26, 0x26, 0xd7, 0xfc, 0x1e, 0x16, 0x72, ++ 0x13, 0x33, 0x63, 0xd5, 0x22, 0xbe, 0xb8, 0x04, ++ 0x34, 0x84, 0x41, 0xbb, 0x80, 0xd0, 0x9f, 0x46, ++ 0x48, 0x07, 0xa7, 0xfc, 0x2b, 0x3a, 0x75, 0x55, ++ 0x8c, 0xc7, 0x6a, 0xbd, 0x7e, 0x46, 0x08, 0x84, ++ 0x0f, 0xd5, 0x74, 0xc0, 0x82, 0x8e, 0xaa, 0x61, ++ 0x05, 0x01, 0xb2, 0x47, 0x6e, 0x20, 0x6a, 0x2d, ++ 0x58, 0x70, 0x48, 0x32, 0xa7, 0x37, 0xd2, 0xb8, ++ 0x82, 0x1a, 0x51, 0xb9, 0x61, 0xdd, 0xfd, 0x9d, ++ 0x6b, 0x0e, 0x18, 0x97, 0xf8, 0x45, 0x5f, 0x87, ++ 0x10, 0xcf, 0x34, 0x72, 0x45, 0x26, 0x49, 0x70, ++ 0xe7, 0xa3, 0x78, 0xe0, 0x52, 0x89, 0x84, 0x94, ++ 0x83, 0x82, 0xc2, 0x69, 0x8f, 0xe3, 0xe1, 0x3f, ++ 0x60, 0x74, 0x88, 0xc4, 0xf7, 0x75, 0x2c, 0xfb, ++ 0xbd, 0xb6, 0xc4, 0x7e, 0x10, 0x0a, 0x6c, 0x90, ++ 0x04, 0x9e, 0xc3, 0x3f, 0x59, 0x7c, 0xce, 0x31, ++ 0x18, 0x60, 0x57, 0x73, 0x46, 0x94, 0x7d, 0x06, ++ 0xa0, 0x6d, 0x44, 0xec, 0xa2, 0x0a, 0x9e, 0x05, ++ 0x15, 0xef, 0xca, 0x5c, 0xbf, 0x00, 0xeb, 0xf7, ++ 0x3d, 0x32, 0xd4, 0xa5, 0xef, 0x49, 0x89, 0x5e, ++ 0x46, 0xb0, 0xa6, 0x63, 0x5b, 0x8a, 0x73, 0xae, ++ 0x6f, 0xd5, 0x9d, 0xf8, 0x4f, 0x40, 0xb5, 0xb2, ++ 0x6e, 0xd3, 0xb6, 0x01, 0xa9, 0x26, 0xa2, 0x21, ++ 0xcf, 0x33, 0x7a, 0x3a, 0xa4, 0x23, 0x13, 0xb0, ++ 0x69, 0x6a, 0xee, 0xce, 0xd8, 0x9d, 0x01, 0x1d, ++ 0x50, 0xc1, 0x30, 0x6c, 0xb1, 0xcd, 0xa0, 0xf0, ++ 0xf0, 0xa2, 0x64, 0x6f, 0xbb, 0xbf, 0x5e, 0xe6, ++ 0xab, 0x87, 0xb4, 0x0f, 0x4f, 0x15, 0xaf, 0xb5, ++ 0x25, 0xa1, 0xb2, 0xd0, 0x80, 0x2c, 0xfb, 0xf9, ++ 0xfe, 0xd2, 0x33, 0xbb, 0x76, 0xfe, 0x7c, 0xa8, ++ 0x66, 0xf7, 0xe7, 0x85, 0x9f, 0x1f, 0x85, 0x57, ++ 0x88, 0xe1, 0xe9, 0x63, 0xe4, 0xd8, 0x1c, 0xa1, ++ 0xfb, 0xda, 0x44, 0x05, 0x2e, 0x1d, 0x3a, 0x1c, ++ 0xff, 0xc8, 0x3b, 0xc0, 0xfe, 0xda, 0x22, 0x0b, ++ 0x43, 0xd6, 0x88, 0x39, 0x4c, 0x4a, 0xa6, 0x69, ++ 0x18, 0x93, 0x42, 0x4e, 0xb5, 0xcc, 0x66, 0x0d, ++ 0x09, 0xf8, 0x1e, 0x7c, 0xd3, 0x3c, 0x99, 0x0d, ++ 0x50, 0x1d, 0x62, 0xe9, 0x57, 0x06, 0xbf, 0x19, ++ 0x88, 0xdd, 0xad, 0x7b, 0x4f, 0xf9, 0xc7, 0x82, ++ 0x6d, 0x8d, 0xc8, 0xc4, 0xc5, 0x78, 0x17, 0x20, ++ 0x15, 0xc5, 0x52, 0x41, 0xcf, 0x5b, 0xd6, 0x7f, ++ 0x94, 0x02, 0x41, 0xe0, 0x40, 0x22, 0x03, 0x5e, ++ 0xd1, 0x53, 0xd4, 0x86, 0xd3, 0x2c, 0x9f, 0x0f, ++ 0x96, 0xe3, 0x6b, 0x9a, 0x76, 0x32, 0x06, 0x47, ++ 0x4b, 0x11, 0xb3, 0xdd, 0x03, 0x65, 0xbd, 0x9b, ++ 0x01, 0xda, 0x9c, 0xb9, 0x7e, 0x3f, 0x6a, 0xc4, ++ 0x7b, 0xea, 0xd4, 0x3c, 0xb9, 0xfb, 0x5c, 0x6b, ++ 0x64, 0x33, 0x52, 0xba, 0x64, 0x78, 0x8f, 0xa4, ++ 0xaf, 0x7a, 0x61, 0x8d, 0xbc, 0xc5, 0x73, 0xe9, ++ 0x6b, 0x58, 0x97, 0x4b, 0xbf, 0x63, 0x22, 0xd3, ++ 0x37, 0x02, 0x54, 0xc5, 0xb9, 0x16, 0x4a, 0xf0, ++ 0x19, 0xd8, 0x94, 0x57, 0xb8, 0x8a, 0xb3, 0x16, ++ 0x3b, 0xd0, 0x84, 0x8e, 0x67, 0xa6, 0xa3, 0x7d, ++ 0x78, 0xec, 0x00 ++}; ++static const u8 dec_assoc012[] __initconst = { ++ 0xb1, 0x69, 0x83, 0x87, 0x30, 0xaa, 0x5d, 0xb8, ++ 0x77, 0xe8, 0x21, 0xff, 0x06, 0x59, 0x35, 0xce, ++ 0x75, 0xfe, 0x38, 0xef, 0xb8, 0x91, 0x43, 0x8c, ++ 0xcf, 0x70, 0xdd, 0x0a, 0x68, 0xbf, 0xd4, 0xbc, ++ 0x16, 0x76, 0x99, 0x36, 0x1e, 0x58, 0x79, 0x5e, ++ 0xd4, 0x29, 0xf7, 0x33, 0x93, 0x48, 0xdb, 0x5f, ++ 0x01, 0xae, 0x9c, 0xb6, 0xe4, 0x88, 0x6d, 0x2b, ++ 0x76, 0x75, 0xe0, 0xf3, 0x74, 0xe2, 0xc9 ++}; ++static const u8 dec_nonce012[] __initconst = { ++ 0x05, 0xa3, 0x93, 0xed, 0x30, 0xc5, 0xa2, 0x06 ++}; ++static const u8 dec_key012[] __initconst = { ++ 0xb3, 0x35, 0x50, 0x03, 0x54, 0x2e, 0x40, 0x5e, ++ 0x8f, 0x59, 0x8e, 0xc5, 0x90, 0xd5, 0x27, 0x2d, ++ 0xba, 0x29, 0x2e, 0xcb, 0x1b, 0x70, 0x44, 0x1e, ++ 0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64 ++}; ++ ++static const u8 dec_input013[] __initconst = { ++ 0x52, 0x34, 0xb3, 0x65, 0x3b, 0xb7, 0xe5, 0xd3, ++ 0xab, 0x49, 0x17, 0x60, 0xd2, 0x52, 0x56, 0xdf, ++ 0xdf, 0x34, 0x56, 0x82, 0xe2, 0xbe, 0xe5, 0xe1, ++ 0x28, 0xd1, 0x4e, 0x5f, 0x4f, 0x01, 0x7d, 0x3f, ++ 0x99, 0x6b, 0x30, 0x6e, 0x1a, 0x7c, 0x4c, 0x8e, ++ 0x62, 0x81, 0xae, 0x86, 0x3f, 0x6b, 0xd0, 0xb5, ++ 0xa9, 0xcf, 0x50, 0xf1, 0x02, 0x12, 0xa0, 0x0b, ++ 0x24, 0xe9, 0xe6, 0x72, 0x89, 0x2c, 0x52, 0x1b, ++ 0x34, 0x38, 0xf8, 0x75, 0x5f, 0xa0, 0x74, 0xe2, ++ 0x99, 0xdd, 0xa6, 0x4b, 0x14, 0x50, 0x4e, 0xf1, ++ 0xbe, 0xd6, 0x9e, 0xdb, 0xb2, 0x24, 0x27, 0x74, ++ 0x12, 0x4a, 0x78, 0x78, 0x17, 0xa5, 0x58, 0x8e, ++ 0x2f, 0xf9, 0xf4, 0x8d, 0xee, 0x03, 0x88, 0xae, ++ 0xb8, 0x29, 0xa1, 0x2f, 0x4b, 0xee, 0x92, 0xbd, ++ 0x87, 0xb3, 0xce, 0x34, 0x21, 0x57, 0x46, 0x04, ++ 0x49, 0x0c, 0x80, 0xf2, 0x01, 0x13, 0xa1, 0x55, ++ 0xb3, 0xff, 0x44, 0x30, 0x3c, 0x1c, 0xd0, 0xef, ++ 0xbc, 0x18, 0x74, 0x26, 0xad, 0x41, 0x5b, 0x5b, ++ 0x3e, 0x9a, 0x7a, 0x46, 0x4f, 0x16, 0xd6, 0x74, ++ 0x5a, 0xb7, 0x3a, 0x28, 0x31, 0xd8, 0xae, 0x26, ++ 0xac, 0x50, 0x53, 0x86, 0xf2, 0x56, 0xd7, 0x3f, ++ 0x29, 0xbc, 0x45, 0x68, 0x8e, 0xcb, 0x98, 0x64, ++ 0xdd, 0xc9, 0xba, 0xb8, 0x4b, 0x7b, 0x82, 0xdd, ++ 0x14, 0xa7, 0xcb, 0x71, 0x72, 0x00, 0x5c, 0xad, ++ 0x7b, 0x6a, 0x89, 0xa4, 0x3d, 0xbf, 0xb5, 0x4b, ++ 0x3e, 0x7c, 0x5a, 0xcf, 0xb8, 0xa1, 0xc5, 0x6e, ++ 0xc8, 0xb6, 0x31, 0x57, 0x7b, 0xdf, 0xa5, 0x7e, ++ 0xb1, 0xd6, 0x42, 0x2a, 0x31, 0x36, 0xd1, 0xd0, ++ 0x3f, 0x7a, 0xe5, 0x94, 0xd6, 0x36, 0xa0, 0x6f, ++ 0xb7, 0x40, 0x7d, 0x37, 0xc6, 0x55, 0x7c, 0x50, ++ 0x40, 0x6d, 0x29, 0x89, 0xe3, 0x5a, 0xae, 0x97, ++ 0xe7, 0x44, 0x49, 0x6e, 0xbd, 0x81, 0x3d, 0x03, ++ 0x93, 0x06, 0x12, 0x06, 0xe2, 0x41, 0x12, 0x4a, ++ 0xf1, 0x6a, 0xa4, 0x58, 0xa2, 0xfb, 0xd2, 0x15, ++ 0xba, 0xc9, 0x79, 0xc9, 0xce, 0x5e, 0x13, 0xbb, ++ 0xf1, 0x09, 0x04, 0xcc, 0xfd, 0xe8, 0x51, 0x34, ++ 0x6a, 0xe8, 0x61, 0x88, 0xda, 0xed, 0x01, 0x47, ++ 0x84, 0xf5, 0x73, 0x25, 0xf9, 0x1c, 0x42, 0x86, ++ 0x07, 0xf3, 0x5b, 0x1a, 0x01, 0xb3, 0xeb, 0x24, ++ 0x32, 0x8d, 0xf6, 0xed, 0x7c, 0x4b, 0xeb, 0x3c, ++ 0x36, 0x42, 0x28, 0xdf, 0xdf, 0xb6, 0xbe, 0xd9, ++ 0x8c, 0x52, 0xd3, 0x2b, 0x08, 0x90, 0x8c, 0xe7, ++ 0x98, 0x31, 0xe2, 0x32, 0x8e, 0xfc, 0x11, 0x48, ++ 0x00, 0xa8, 0x6a, 0x42, 0x4a, 0x02, 0xc6, 0x4b, ++ 0x09, 0xf1, 0xe3, 0x49, 0xf3, 0x45, 0x1f, 0x0e, ++ 0xbc, 0x56, 0xe2, 0xe4, 0xdf, 0xfb, 0xeb, 0x61, ++ 0xfa, 0x24, 0xc1, 0x63, 0x75, 0xbb, 0x47, 0x75, ++ 0xaf, 0xe1, 0x53, 0x16, 0x96, 0x21, 0x85, 0x26, ++ 0x11, 0xb3, 0x76, 0xe3, 0x23, 0xa1, 0x6b, 0x74, ++ 0x37, 0xd0, 0xde, 0x06, 0x90, 0x71, 0x5d, 0x43, ++ 0x88, 0x9b, 0x00, 0x54, 0xa6, 0x75, 0x2f, 0xa1, ++ 0xc2, 0x0b, 0x73, 0x20, 0x1d, 0xb6, 0x21, 0x79, ++ 0x57, 0x3f, 0xfa, 0x09, 0xbe, 0x8a, 0x33, 0xc3, ++ 0x52, 0xf0, 0x1d, 0x82, 0x31, 0xd1, 0x55, 0xb5, ++ 0x6c, 0x99, 0x25, 0xcf, 0x5c, 0x32, 0xce, 0xe9, ++ 0x0d, 0xfa, 0x69, 0x2c, 0xd5, 0x0d, 0xc5, 0x6d, ++ 0x86, 0xd0, 0x0c, 0x3b, 0x06, 0x50, 0x79, 0xe8, ++ 0xc3, 0xae, 0x04, 0xe6, 0xcd, 0x51, 0xe4, 0x26, ++ 0x9b, 0x4f, 0x7e, 0xa6, 0x0f, 0xab, 0xd8, 0xe5, ++ 0xde, 0xa9, 0x00, 0x95, 0xbe, 0xa3, 0x9d, 0x5d, ++ 0xb2, 0x09, 0x70, 0x18, 0x1c, 0xf0, 0xac, 0x29, ++ 0x23, 0x02, 0x29, 0x28, 0xd2, 0x74, 0x35, 0x57, ++ 0x62, 0x0f, 0x24, 0xea, 0x5e, 0x33, 0xc2, 0x92, ++ 0xf3, 0x78, 0x4d, 0x30, 0x1e, 0xa1, 0x99, 0xa9, ++ 0x82, 0xb0, 0x42, 0x31, 0x8d, 0xad, 0x8a, 0xbc, ++ 0xfc, 0xd4, 0x57, 0x47, 0x3e, 0xb4, 0x50, 0xdd, ++ 0x6e, 0x2c, 0x80, 0x4d, 0x22, 0xf1, 0xfb, 0x57, ++ 0xc4, 0xdd, 0x17, 0xe1, 0x8a, 0x36, 0x4a, 0xb3, ++ 0x37, 0xca, 0xc9, 0x4e, 0xab, 0xd5, 0x69, 0xc4, ++ 0xf4, 0xbc, 0x0b, 0x3b, 0x44, 0x4b, 0x29, 0x9c, ++ 0xee, 0xd4, 0x35, 0x22, 0x21, 0xb0, 0x1f, 0x27, ++ 0x64, 0xa8, 0x51, 0x1b, 0xf0, 0x9f, 0x19, 0x5c, ++ 0xfb, 0x5a, 0x64, 0x74, 0x70, 0x45, 0x09, 0xf5, ++ 0x64, 0xfe, 0x1a, 0x2d, 0xc9, 0x14, 0x04, 0x14, ++ 0xcf, 0xd5, 0x7d, 0x60, 0xaf, 0x94, 0x39, 0x94, ++ 0xe2, 0x7d, 0x79, 0x82, 0xd0, 0x65, 0x3b, 0x6b, ++ 0x9c, 0x19, 0x84, 0xb4, 0x6d, 0xb3, 0x0c, 0x99, ++ 0xc0, 0x56, 0xa8, 0xbd, 0x73, 0xce, 0x05, 0x84, ++ 0x3e, 0x30, 0xaa, 0xc4, 0x9b, 0x1b, 0x04, 0x2a, ++ 0x9f, 0xd7, 0x43, 0x2b, 0x23, 0xdf, 0xbf, 0xaa, ++ 0xd5, 0xc2, 0x43, 0x2d, 0x70, 0xab, 0xdc, 0x75, ++ 0xad, 0xac, 0xf7, 0xc0, 0xbe, 0x67, 0xb2, 0x74, ++ 0xed, 0x67, 0x10, 0x4a, 0x92, 0x60, 0xc1, 0x40, ++ 0x50, 0x19, 0x8a, 0x8a, 0x8c, 0x09, 0x0e, 0x72, ++ 0xe1, 0x73, 0x5e, 0xe8, 0x41, 0x85, 0x63, 0x9f, ++ 0x3f, 0xd7, 0x7d, 0xc4, 0xfb, 0x22, 0x5d, 0x92, ++ 0x6c, 0xb3, 0x1e, 0xe2, 0x50, 0x2f, 0x82, 0xa8, ++ 0x28, 0xc0, 0xb5, 0xd7, 0x5f, 0x68, 0x0d, 0x2c, ++ 0x2d, 0xaf, 0x7e, 0xfa, 0x2e, 0x08, 0x0f, 0x1f, ++ 0x70, 0x9f, 0xe9, 0x19, 0x72, 0x55, 0xf8, 0xfb, ++ 0x51, 0xd2, 0x33, 0x5d, 0xa0, 0xd3, 0x2b, 0x0a, ++ 0x6c, 0xbc, 0x4e, 0xcf, 0x36, 0x4d, 0xdc, 0x3b, ++ 0xe9, 0x3e, 0x81, 0x7c, 0x61, 0xdb, 0x20, 0x2d, ++ 0x3a, 0xc3, 0xb3, 0x0c, 0x1e, 0x00, 0xb9, 0x7c, ++ 0xf5, 0xca, 0x10, 0x5f, 0x3a, 0x71, 0xb3, 0xe4, ++ 0x20, 0xdb, 0x0c, 0x2a, 0x98, 0x63, 0x45, 0x00, ++ 0x58, 0xf6, 0x68, 0xe4, 0x0b, 0xda, 0x13, 0x3b, ++ 0x60, 0x5c, 0x76, 0xdb, 0xb9, 0x97, 0x71, 0xe4, ++ 0xd9, 0xb7, 0xdb, 0xbd, 0x68, 0xc7, 0x84, 0x84, ++ 0xaa, 0x7c, 0x68, 0x62, 0x5e, 0x16, 0xfc, 0xba, ++ 0x72, 0xaa, 0x9a, 0xa9, 0xeb, 0x7c, 0x75, 0x47, ++ 0x97, 0x7e, 0xad, 0xe2, 0xd9, 0x91, 0xe8, 0xe4, ++ 0xa5, 0x31, 0xd7, 0x01, 0x8e, 0xa2, 0x11, 0x88, ++ 0x95, 0xb9, 0xf2, 0x9b, 0xd3, 0x7f, 0x1b, 0x81, ++ 0x22, 0xf7, 0x98, 0x60, 0x0a, 0x64, 0xa6, 0xc1, ++ 0xf6, 0x49, 0xc7, 0xe3, 0x07, 0x4d, 0x94, 0x7a, ++ 0xcf, 0x6e, 0x68, 0x0c, 0x1b, 0x3f, 0x6e, 0x2e, ++ 0xee, 0x92, 0xfa, 0x52, 0xb3, 0x59, 0xf8, 0xf1, ++ 0x8f, 0x6a, 0x66, 0xa3, 0x82, 0x76, 0x4a, 0x07, ++ 0x1a, 0xc7, 0xdd, 0xf5, 0xda, 0x9c, 0x3c, 0x24, ++ 0xbf, 0xfd, 0x42, 0xa1, 0x10, 0x64, 0x6a, 0x0f, ++ 0x89, 0xee, 0x36, 0xa5, 0xce, 0x99, 0x48, 0x6a, ++ 0xf0, 0x9f, 0x9e, 0x69, 0xa4, 0x40, 0x20, 0xe9, ++ 0x16, 0x15, 0xf7, 0xdb, 0x75, 0x02, 0xcb, 0xe9, ++ 0x73, 0x8b, 0x3b, 0x49, 0x2f, 0xf0, 0xaf, 0x51, ++ 0x06, 0x5c, 0xdf, 0x27, 0x27, 0x49, 0x6a, 0xd1, ++ 0xcc, 0xc7, 0xb5, 0x63, 0xb5, 0xfc, 0xb8, 0x5c, ++ 0x87, 0x7f, 0x84, 0xb4, 0xcc, 0x14, 0xa9, 0x53, ++ 0xda, 0xa4, 0x56, 0xf8, 0xb6, 0x1b, 0xcc, 0x40, ++ 0x27, 0x52, 0x06, 0x5a, 0x13, 0x81, 0xd7, 0x3a, ++ 0xd4, 0x3b, 0xfb, 0x49, 0x65, 0x31, 0x33, 0xb2, ++ 0xfa, 0xcd, 0xad, 0x58, 0x4e, 0x2b, 0xae, 0xd2, ++ 0x20, 0xfb, 0x1a, 0x48, 0xb4, 0x3f, 0x9a, 0xd8, ++ 0x7a, 0x35, 0x4a, 0xc8, 0xee, 0x88, 0x5e, 0x07, ++ 0x66, 0x54, 0xb9, 0xec, 0x9f, 0xa3, 0xe3, 0xb9, ++ 0x37, 0xaa, 0x49, 0x76, 0x31, 0xda, 0x74, 0x2d, ++ 0x3c, 0xa4, 0x65, 0x10, 0x32, 0x38, 0xf0, 0xde, ++ 0xd3, 0x99, 0x17, 0xaa, 0x71, 0xaa, 0x8f, 0x0f, ++ 0x8c, 0xaf, 0xa2, 0xf8, 0x5d, 0x64, 0xba, 0x1d, ++ 0xa3, 0xef, 0x96, 0x73, 0xe8, 0xa1, 0x02, 0x8d, ++ 0x0c, 0x6d, 0xb8, 0x06, 0x90, 0xb8, 0x08, 0x56, ++ 0x2c, 0xa7, 0x06, 0xc9, 0xc2, 0x38, 0xdb, 0x7c, ++ 0x63, 0xb1, 0x57, 0x8e, 0xea, 0x7c, 0x79, 0xf3, ++ 0x49, 0x1d, 0xfe, 0x9f, 0xf3, 0x6e, 0xb1, 0x1d, ++ 0xba, 0x19, 0x80, 0x1a, 0x0a, 0xd3, 0xb0, 0x26, ++ 0x21, 0x40, 0xb1, 0x7c, 0xf9, 0x4d, 0x8d, 0x10, ++ 0xc1, 0x7e, 0xf4, 0xf6, 0x3c, 0xa8, 0xfd, 0x7c, ++ 0xa3, 0x92, 0xb2, 0x0f, 0xaa, 0xcc, 0xa6, 0x11, ++ 0xfe, 0x04, 0xe3, 0xd1, 0x7a, 0x32, 0x89, 0xdf, ++ 0x0d, 0xc4, 0x8f, 0x79, 0x6b, 0xca, 0x16, 0x7c, ++ 0x6e, 0xf9, 0xad, 0x0f, 0xf6, 0xfe, 0x27, 0xdb, ++ 0xc4, 0x13, 0x70, 0xf1, 0x62, 0x1a, 0x4f, 0x79, ++ 0x40, 0xc9, 0x9b, 0x8b, 0x21, 0xea, 0x84, 0xfa, ++ 0xf5, 0xf1, 0x89, 0xce, 0xb7, 0x55, 0x0a, 0x80, ++ 0x39, 0x2f, 0x55, 0x36, 0x16, 0x9c, 0x7b, 0x08, ++ 0xbd, 0x87, 0x0d, 0xa5, 0x32, 0xf1, 0x52, 0x7c, ++ 0xe8, 0x55, 0x60, 0x5b, 0xd7, 0x69, 0xe4, 0xfc, ++ 0xfa, 0x12, 0x85, 0x96, 0xea, 0x50, 0x28, 0xab, ++ 0x8a, 0xf7, 0xbb, 0x0e, 0x53, 0x74, 0xca, 0xa6, ++ 0x27, 0x09, 0xc2, 0xb5, 0xde, 0x18, 0x14, 0xd9, ++ 0xea, 0xe5, 0x29, 0x1c, 0x40, 0x56, 0xcf, 0xd7, ++ 0xae, 0x05, 0x3f, 0x65, 0xaf, 0x05, 0x73, 0xe2, ++ 0x35, 0x96, 0x27, 0x07, 0x14, 0xc0, 0xad, 0x33, ++ 0xf1, 0xdc, 0x44, 0x7a, 0x89, 0x17, 0x77, 0xd2, ++ 0x9c, 0x58, 0x60, 0xf0, 0x3f, 0x7b, 0x2d, 0x2e, ++ 0x57, 0x95, 0x54, 0x87, 0xed, 0xf2, 0xc7, 0x4c, ++ 0xf0, 0xae, 0x56, 0x29, 0x19, 0x7d, 0x66, 0x4b, ++ 0x9b, 0x83, 0x84, 0x42, 0x3b, 0x01, 0x25, 0x66, ++ 0x8e, 0x02, 0xde, 0xb9, 0x83, 0x54, 0x19, 0xf6, ++ 0x9f, 0x79, 0x0d, 0x67, 0xc5, 0x1d, 0x7a, 0x44, ++ 0x02, 0x98, 0xa7, 0x16, 0x1c, 0x29, 0x0d, 0x74, ++ 0xff, 0x85, 0x40, 0x06, 0xef, 0x2c, 0xa9, 0xc6, ++ 0xf5, 0x53, 0x07, 0x06, 0xae, 0xe4, 0xfa, 0x5f, ++ 0xd8, 0x39, 0x4d, 0xf1, 0x9b, 0x6b, 0xd9, 0x24, ++ 0x84, 0xfe, 0x03, 0x4c, 0xb2, 0x3f, 0xdf, 0xa1, ++ 0x05, 0x9e, 0x50, 0x14, 0x5a, 0xd9, 0x1a, 0xa2, ++ 0xa7, 0xfa, 0xfa, 0x17, 0xf7, 0x78, 0xd6, 0xb5, ++ 0x92, 0x61, 0x91, 0xac, 0x36, 0xfa, 0x56, 0x0d, ++ 0x38, 0x32, 0x18, 0x85, 0x08, 0x58, 0x37, 0xf0, ++ 0x4b, 0xdb, 0x59, 0xe7, 0xa4, 0x34, 0xc0, 0x1b, ++ 0x01, 0xaf, 0x2d, 0xde, 0xa1, 0xaa, 0x5d, 0xd3, ++ 0xec, 0xe1, 0xd4, 0xf7, 0xe6, 0x54, 0x68, 0xf0, ++ 0x51, 0x97, 0xa7, 0x89, 0xea, 0x24, 0xad, 0xd3, ++ 0x6e, 0x47, 0x93, 0x8b, 0x4b, 0xb4, 0xf7, 0x1c, ++ 0x42, 0x06, 0x67, 0xe8, 0x99, 0xf6, 0xf5, 0x7b, ++ 0x85, 0xb5, 0x65, 0xb5, 0xb5, 0xd2, 0x37, 0xf5, ++ 0xf3, 0x02, 0xa6, 0x4d, 0x11, 0xa7, 0xdc, 0x51, ++ 0x09, 0x7f, 0xa0, 0xd8, 0x88, 0x1c, 0x13, 0x71, ++ 0xae, 0x9c, 0xb7, 0x7b, 0x34, 0xd6, 0x4e, 0x68, ++ 0x26, 0x83, 0x51, 0xaf, 0x1d, 0xee, 0x8b, 0xbb, ++ 0x69, 0x43, 0x2b, 0x9e, 0x8a, 0xbc, 0x02, 0x0e, ++ 0xa0, 0x1b, 0xe0, 0xa8, 0x5f, 0x6f, 0xaf, 0x1b, ++ 0x8f, 0xe7, 0x64, 0x71, 0x74, 0x11, 0x7e, 0xa8, ++ 0xd8, 0xf9, 0x97, 0x06, 0xc3, 0xb6, 0xfb, 0xfb, ++ 0xb7, 0x3d, 0x35, 0x9d, 0x3b, 0x52, 0xed, 0x54, ++ 0xca, 0xf4, 0x81, 0x01, 0x2d, 0x1b, 0xc3, 0xa7, ++ 0x00, 0x3d, 0x1a, 0x39, 0x54, 0xe1, 0xf6, 0xff, ++ 0xed, 0x6f, 0x0b, 0x5a, 0x68, 0xda, 0x58, 0xdd, ++ 0xa9, 0xcf, 0x5c, 0x4a, 0xe5, 0x09, 0x4e, 0xde, ++ 0x9d, 0xbc, 0x3e, 0xee, 0x5a, 0x00, 0x3b, 0x2c, ++ 0x87, 0x10, 0x65, 0x60, 0xdd, 0xd7, 0x56, 0xd1, ++ 0x4c, 0x64, 0x45, 0xe4, 0x21, 0xec, 0x78, 0xf8, ++ 0x25, 0x7a, 0x3e, 0x16, 0x5d, 0x09, 0x53, 0x14, ++ 0xbe, 0x4f, 0xae, 0x87, 0xd8, 0xd1, 0xaa, 0x3c, ++ 0xf6, 0x3e, 0xa4, 0x70, 0x8c, 0x5e, 0x70, 0xa4, ++ 0xb3, 0x6b, 0x66, 0x73, 0xd3, 0xbf, 0x31, 0x06, ++ 0x19, 0x62, 0x93, 0x15, 0xf2, 0x86, 0xe4, 0x52, ++ 0x7e, 0x53, 0x4c, 0x12, 0x38, 0xcc, 0x34, 0x7d, ++ 0x57, 0xf6, 0x42, 0x93, 0x8a, 0xc4, 0xee, 0x5c, ++ 0x8a, 0xe1, 0x52, 0x8f, 0x56, 0x64, 0xf6, 0xa6, ++ 0xd1, 0x91, 0x57, 0x70, 0xcd, 0x11, 0x76, 0xf5, ++ 0x59, 0x60, 0x60, 0x3c, 0xc1, 0xc3, 0x0b, 0x7f, ++ 0x58, 0x1a, 0x50, 0x91, 0xf1, 0x68, 0x8f, 0x6e, ++ 0x74, 0x74, 0xa8, 0x51, 0x0b, 0xf7, 0x7a, 0x98, ++ 0x37, 0xf2, 0x0a, 0x0e, 0xa4, 0x97, 0x04, 0xb8, ++ 0x9b, 0xfd, 0xa0, 0xea, 0xf7, 0x0d, 0xe1, 0xdb, ++ 0x03, 0xf0, 0x31, 0x29, 0xf8, 0xdd, 0x6b, 0x8b, ++ 0x5d, 0xd8, 0x59, 0xa9, 0x29, 0xcf, 0x9a, 0x79, ++ 0x89, 0x19, 0x63, 0x46, 0x09, 0x79, 0x6a, 0x11, ++ 0xda, 0x63, 0x68, 0x48, 0x77, 0x23, 0xfb, 0x7d, ++ 0x3a, 0x43, 0xcb, 0x02, 0x3b, 0x7a, 0x6d, 0x10, ++ 0x2a, 0x9e, 0xac, 0xf1, 0xd4, 0x19, 0xf8, 0x23, ++ 0x64, 0x1d, 0x2c, 0x5f, 0xf2, 0xb0, 0x5c, 0x23, ++ 0x27, 0xf7, 0x27, 0x30, 0x16, 0x37, 0xb1, 0x90, ++ 0xab, 0x38, 0xfb, 0x55, 0xcd, 0x78, 0x58, 0xd4, ++ 0x7d, 0x43, 0xf6, 0x45, 0x5e, 0x55, 0x8d, 0xb1, ++ 0x02, 0x65, 0x58, 0xb4, 0x13, 0x4b, 0x36, 0xf7, ++ 0xcc, 0xfe, 0x3d, 0x0b, 0x82, 0xe2, 0x12, 0x11, ++ 0xbb, 0xe6, 0xb8, 0x3a, 0x48, 0x71, 0xc7, 0x50, ++ 0x06, 0x16, 0x3a, 0xe6, 0x7c, 0x05, 0xc7, 0xc8, ++ 0x4d, 0x2f, 0x08, 0x6a, 0x17, 0x9a, 0x95, 0x97, ++ 0x50, 0x68, 0xdc, 0x28, 0x18, 0xc4, 0x61, 0x38, ++ 0xb9, 0xe0, 0x3e, 0x78, 0xdb, 0x29, 0xe0, 0x9f, ++ 0x52, 0xdd, 0xf8, 0x4f, 0x91, 0xc1, 0xd0, 0x33, ++ 0xa1, 0x7a, 0x8e, 0x30, 0x13, 0x82, 0x07, 0x9f, ++ 0xd3, 0x31, 0x0f, 0x23, 0xbe, 0x32, 0x5a, 0x75, ++ 0xcf, 0x96, 0xb2, 0xec, 0xb5, 0x32, 0xac, 0x21, ++ 0xd1, 0x82, 0x33, 0xd3, 0x15, 0x74, 0xbd, 0x90, ++ 0xf1, 0x2c, 0xe6, 0x5f, 0x8d, 0xe3, 0x02, 0xe8, ++ 0xe9, 0xc4, 0xca, 0x96, 0xeb, 0x0e, 0xbc, 0x91, ++ 0xf4, 0xb9, 0xea, 0xd9, 0x1b, 0x75, 0xbd, 0xe1, ++ 0xac, 0x2a, 0x05, 0x37, 0x52, 0x9b, 0x1b, 0x3f, ++ 0x5a, 0xdc, 0x21, 0xc3, 0x98, 0xbb, 0xaf, 0xa3, ++ 0xf2, 0x00, 0xbf, 0x0d, 0x30, 0x89, 0x05, 0xcc, ++ 0xa5, 0x76, 0xf5, 0x06, 0xf0, 0xc6, 0x54, 0x8a, ++ 0x5d, 0xd4, 0x1e, 0xc1, 0xf2, 0xce, 0xb0, 0x62, ++ 0xc8, 0xfc, 0x59, 0x42, 0x9a, 0x90, 0x60, 0x55, ++ 0xfe, 0x88, 0xa5, 0x8b, 0xb8, 0x33, 0x0c, 0x23, ++ 0x24, 0x0d, 0x15, 0x70, 0x37, 0x1e, 0x3d, 0xf6, ++ 0xd2, 0xea, 0x92, 0x10, 0xb2, 0xc4, 0x51, 0xac, ++ 0xf2, 0xac, 0xf3, 0x6b, 0x6c, 0xaa, 0xcf, 0x12, ++ 0xc5, 0x6c, 0x90, 0x50, 0xb5, 0x0c, 0xfc, 0x1a, ++ 0x15, 0x52, 0xe9, 0x26, 0xc6, 0x52, 0xa4, 0xe7, ++ 0x81, 0x69, 0xe1, 0xe7, 0x9e, 0x30, 0x01, 0xec, ++ 0x84, 0x89, 0xb2, 0x0d, 0x66, 0xdd, 0xce, 0x28, ++ 0x5c, 0xec, 0x98, 0x46, 0x68, 0x21, 0x9f, 0x88, ++ 0x3f, 0x1f, 0x42, 0x77, 0xce, 0xd0, 0x61, 0xd4, ++ 0x20, 0xa7, 0xff, 0x53, 0xad, 0x37, 0xd0, 0x17, ++ 0x35, 0xc9, 0xfc, 0xba, 0x0a, 0x78, 0x3f, 0xf2, ++ 0xcc, 0x86, 0x89, 0xe8, 0x4b, 0x3c, 0x48, 0x33, ++ 0x09, 0x7f, 0xc6, 0xc0, 0xdd, 0xb8, 0xfd, 0x7a, ++ 0x66, 0x66, 0x65, 0xeb, 0x47, 0xa7, 0x04, 0x28, ++ 0xa3, 0x19, 0x8e, 0xa9, 0xb1, 0x13, 0x67, 0x62, ++ 0x70, 0xcf, 0xd7 ++}; ++static const u8 dec_output013[] __initconst = { ++ 0x74, 0xa6, 0x3e, 0xe4, 0xb1, 0xcb, 0xaf, 0xb0, ++ 0x40, 0xe5, 0x0f, 0x9e, 0xf1, 0xf2, 0x89, 0xb5, ++ 0x42, 0x34, 0x8a, 0xa1, 0x03, 0xb7, 0xe9, 0x57, ++ 0x46, 0xbe, 0x20, 0xe4, 0x6e, 0xb0, 0xeb, 0xff, ++ 0xea, 0x07, 0x7e, 0xef, 0xe2, 0x55, 0x9f, 0xe5, ++ 0x78, 0x3a, 0xb7, 0x83, 0xc2, 0x18, 0x40, 0x7b, ++ 0xeb, 0xcd, 0x81, 0xfb, 0x90, 0x12, 0x9e, 0x46, ++ 0xa9, 0xd6, 0x4a, 0xba, 0xb0, 0x62, 0xdb, 0x6b, ++ 0x99, 0xc4, 0xdb, 0x54, 0x4b, 0xb8, 0xa5, 0x71, ++ 0xcb, 0xcd, 0x63, 0x32, 0x55, 0xfb, 0x31, 0xf0, ++ 0x38, 0xf5, 0xbe, 0x78, 0xe4, 0x45, 0xce, 0x1b, ++ 0x6a, 0x5b, 0x0e, 0xf4, 0x16, 0xe4, 0xb1, 0x3d, ++ 0xf6, 0x63, 0x7b, 0xa7, 0x0c, 0xde, 0x6f, 0x8f, ++ 0x74, 0xdf, 0xe0, 0x1e, 0x9d, 0xce, 0x8f, 0x24, ++ 0xef, 0x23, 0x35, 0x33, 0x7b, 0x83, 0x34, 0x23, ++ 0x58, 0x74, 0x14, 0x77, 0x1f, 0xc2, 0x4f, 0x4e, ++ 0xc6, 0x89, 0xf9, 0x52, 0x09, 0x37, 0x64, 0x14, ++ 0xc4, 0x01, 0x6b, 0x9d, 0x77, 0xe8, 0x90, 0x5d, ++ 0xa8, 0x4a, 0x2a, 0xef, 0x5c, 0x7f, 0xeb, 0xbb, ++ 0xb2, 0xc6, 0x93, 0x99, 0x66, 0xdc, 0x7f, 0xd4, ++ 0x9e, 0x2a, 0xca, 0x8d, 0xdb, 0xe7, 0x20, 0xcf, ++ 0xe4, 0x73, 0xae, 0x49, 0x7d, 0x64, 0x0f, 0x0e, ++ 0x28, 0x46, 0xa9, 0xa8, 0x32, 0xe4, 0x0e, 0xf6, ++ 0x51, 0x53, 0xb8, 0x3c, 0xb1, 0xff, 0xa3, 0x33, ++ 0x41, 0x75, 0xff, 0xf1, 0x6f, 0xf1, 0xfb, 0xbb, ++ 0x83, 0x7f, 0x06, 0x9b, 0xe7, 0x1b, 0x0a, 0xe0, ++ 0x5c, 0x33, 0x60, 0x5b, 0xdb, 0x5b, 0xed, 0xfe, ++ 0xa5, 0x16, 0x19, 0x72, 0xa3, 0x64, 0x23, 0x00, ++ 0x02, 0xc7, 0xf3, 0x6a, 0x81, 0x3e, 0x44, 0x1d, ++ 0x79, 0x15, 0x5f, 0x9a, 0xde, 0xe2, 0xfd, 0x1b, ++ 0x73, 0xc1, 0xbc, 0x23, 0xba, 0x31, 0xd2, 0x50, ++ 0xd5, 0xad, 0x7f, 0x74, 0xa7, 0xc9, 0xf8, 0x3e, ++ 0x2b, 0x26, 0x10, 0xf6, 0x03, 0x36, 0x74, 0xe4, ++ 0x0e, 0x6a, 0x72, 0xb7, 0x73, 0x0a, 0x42, 0x28, ++ 0xc2, 0xad, 0x5e, 0x03, 0xbe, 0xb8, 0x0b, 0xa8, ++ 0x5b, 0xd4, 0xb8, 0xba, 0x52, 0x89, 0xb1, 0x9b, ++ 0xc1, 0xc3, 0x65, 0x87, 0xed, 0xa5, 0xf4, 0x86, ++ 0xfd, 0x41, 0x80, 0x91, 0x27, 0x59, 0x53, 0x67, ++ 0x15, 0x78, 0x54, 0x8b, 0x2d, 0x3d, 0xc7, 0xff, ++ 0x02, 0x92, 0x07, 0x5f, 0x7a, 0x4b, 0x60, 0x59, ++ 0x3c, 0x6f, 0x5c, 0xd8, 0xec, 0x95, 0xd2, 0xfe, ++ 0xa0, 0x3b, 0xd8, 0x3f, 0xd1, 0x69, 0xa6, 0xd6, ++ 0x41, 0xb2, 0xf4, 0x4d, 0x12, 0xf4, 0x58, 0x3e, ++ 0x66, 0x64, 0x80, 0x31, 0x9b, 0xa8, 0x4c, 0x8b, ++ 0x07, 0xb2, 0xec, 0x66, 0x94, 0x66, 0x47, 0x50, ++ 0x50, 0x5f, 0x18, 0x0b, 0x0e, 0xd6, 0xc0, 0x39, ++ 0x21, 0x13, 0x9e, 0x33, 0xbc, 0x79, 0x36, 0x02, ++ 0x96, 0x70, 0xf0, 0x48, 0x67, 0x2f, 0x26, 0xe9, ++ 0x6d, 0x10, 0xbb, 0xd6, 0x3f, 0xd1, 0x64, 0x7a, ++ 0x2e, 0xbe, 0x0c, 0x61, 0xf0, 0x75, 0x42, 0x38, ++ 0x23, 0xb1, 0x9e, 0x9f, 0x7c, 0x67, 0x66, 0xd9, ++ 0x58, 0x9a, 0xf1, 0xbb, 0x41, 0x2a, 0x8d, 0x65, ++ 0x84, 0x94, 0xfc, 0xdc, 0x6a, 0x50, 0x64, 0xdb, ++ 0x56, 0x33, 0x76, 0x00, 0x10, 0xed, 0xbe, 0xd2, ++ 0x12, 0xf6, 0xf6, 0x1b, 0xa2, 0x16, 0xde, 0xae, ++ 0x31, 0x95, 0xdd, 0xb1, 0x08, 0x7e, 0x4e, 0xee, ++ 0xe7, 0xf9, 0xa5, 0xfb, 0x5b, 0x61, 0x43, 0x00, ++ 0x40, 0xf6, 0x7e, 0x02, 0x04, 0x32, 0x4e, 0x0c, ++ 0xe2, 0x66, 0x0d, 0xd7, 0x07, 0x98, 0x0e, 0xf8, ++ 0x72, 0x34, 0x6d, 0x95, 0x86, 0xd7, 0xcb, 0x31, ++ 0x54, 0x47, 0xd0, 0x38, 0x29, 0x9c, 0x5a, 0x68, ++ 0xd4, 0x87, 0x76, 0xc9, 0xe7, 0x7e, 0xe3, 0xf4, ++ 0x81, 0x6d, 0x18, 0xcb, 0xc9, 0x05, 0xaf, 0xa0, ++ 0xfb, 0x66, 0xf7, 0xf1, 0x1c, 0xc6, 0x14, 0x11, ++ 0x4f, 0x2b, 0x79, 0x42, 0x8b, 0xbc, 0xac, 0xe7, ++ 0x6c, 0xfe, 0x0f, 0x58, 0xe7, 0x7c, 0x78, 0x39, ++ 0x30, 0xb0, 0x66, 0x2c, 0x9b, 0x6d, 0x3a, 0xe1, ++ 0xcf, 0xc9, 0xa4, 0x0e, 0x6d, 0x6d, 0x8a, 0xa1, ++ 0x3a, 0xe7, 0x28, 0xd4, 0x78, 0x4c, 0xa6, 0xa2, ++ 0x2a, 0xa6, 0x03, 0x30, 0xd7, 0xa8, 0x25, 0x66, ++ 0x87, 0x2f, 0x69, 0x5c, 0x4e, 0xdd, 0xa5, 0x49, ++ 0x5d, 0x37, 0x4a, 0x59, 0xc4, 0xaf, 0x1f, 0xa2, ++ 0xe4, 0xf8, 0xa6, 0x12, 0x97, 0xd5, 0x79, 0xf5, ++ 0xe2, 0x4a, 0x2b, 0x5f, 0x61, 0xe4, 0x9e, 0xe3, ++ 0xee, 0xb8, 0xa7, 0x5b, 0x2f, 0xf4, 0x9e, 0x6c, ++ 0xfb, 0xd1, 0xc6, 0x56, 0x77, 0xba, 0x75, 0xaa, ++ 0x3d, 0x1a, 0xa8, 0x0b, 0xb3, 0x68, 0x24, 0x00, ++ 0x10, 0x7f, 0xfd, 0xd7, 0xa1, 0x8d, 0x83, 0x54, ++ 0x4f, 0x1f, 0xd8, 0x2a, 0xbe, 0x8a, 0x0c, 0x87, ++ 0xab, 0xa2, 0xde, 0xc3, 0x39, 0xbf, 0x09, 0x03, ++ 0xa5, 0xf3, 0x05, 0x28, 0xe1, 0xe1, 0xee, 0x39, ++ 0x70, 0x9c, 0xd8, 0x81, 0x12, 0x1e, 0x02, 0x40, ++ 0xd2, 0x6e, 0xf0, 0xeb, 0x1b, 0x3d, 0x22, 0xc6, ++ 0xe5, 0xe3, 0xb4, 0x5a, 0x98, 0xbb, 0xf0, 0x22, ++ 0x28, 0x8d, 0xe5, 0xd3, 0x16, 0x48, 0x24, 0xa5, ++ 0xe6, 0x66, 0x0c, 0xf9, 0x08, 0xf9, 0x7e, 0x1e, ++ 0xe1, 0x28, 0x26, 0x22, 0xc7, 0xc7, 0x0a, 0x32, ++ 0x47, 0xfa, 0xa3, 0xbe, 0x3c, 0xc4, 0xc5, 0x53, ++ 0x0a, 0xd5, 0x94, 0x4a, 0xd7, 0x93, 0xd8, 0x42, ++ 0x99, 0xb9, 0x0a, 0xdb, 0x56, 0xf7, 0xb9, 0x1c, ++ 0x53, 0x4f, 0xfa, 0xd3, 0x74, 0xad, 0xd9, 0x68, ++ 0xf1, 0x1b, 0xdf, 0x61, 0xc6, 0x5e, 0xa8, 0x48, ++ 0xfc, 0xd4, 0x4a, 0x4c, 0x3c, 0x32, 0xf7, 0x1c, ++ 0x96, 0x21, 0x9b, 0xf9, 0xa3, 0xcc, 0x5a, 0xce, ++ 0xd5, 0xd7, 0x08, 0x24, 0xf6, 0x1c, 0xfd, 0xdd, ++ 0x38, 0xc2, 0x32, 0xe9, 0xb8, 0xe7, 0xb6, 0xfa, ++ 0x9d, 0x45, 0x13, 0x2c, 0x83, 0xfd, 0x4a, 0x69, ++ 0x82, 0xcd, 0xdc, 0xb3, 0x76, 0x0c, 0x9e, 0xd8, ++ 0xf4, 0x1b, 0x45, 0x15, 0xb4, 0x97, 0xe7, 0x58, ++ 0x34, 0xe2, 0x03, 0x29, 0x5a, 0xbf, 0xb6, 0xe0, ++ 0x5d, 0x13, 0xd9, 0x2b, 0xb4, 0x80, 0xb2, 0x45, ++ 0x81, 0x6a, 0x2e, 0x6c, 0x89, 0x7d, 0xee, 0xbb, ++ 0x52, 0xdd, 0x1f, 0x18, 0xe7, 0x13, 0x6b, 0x33, ++ 0x0e, 0xea, 0x36, 0x92, 0x77, 0x7b, 0x6d, 0x9c, ++ 0x5a, 0x5f, 0x45, 0x7b, 0x7b, 0x35, 0x62, 0x23, ++ 0xd1, 0xbf, 0x0f, 0xd0, 0x08, 0x1b, 0x2b, 0x80, ++ 0x6b, 0x7e, 0xf1, 0x21, 0x47, 0xb0, 0x57, 0xd1, ++ 0x98, 0x72, 0x90, 0x34, 0x1c, 0x20, 0x04, 0xff, ++ 0x3d, 0x5c, 0xee, 0x0e, 0x57, 0x5f, 0x6f, 0x24, ++ 0x4e, 0x3c, 0xea, 0xfc, 0xa5, 0xa9, 0x83, 0xc9, ++ 0x61, 0xb4, 0x51, 0x24, 0xf8, 0x27, 0x5e, 0x46, ++ 0x8c, 0xb1, 0x53, 0x02, 0x96, 0x35, 0xba, 0xb8, ++ 0x4c, 0x71, 0xd3, 0x15, 0x59, 0x35, 0x22, 0x20, ++ 0xad, 0x03, 0x9f, 0x66, 0x44, 0x3b, 0x9c, 0x35, ++ 0x37, 0x1f, 0x9b, 0xbb, 0xf3, 0xdb, 0x35, 0x63, ++ 0x30, 0x64, 0xaa, 0xa2, 0x06, 0xa8, 0x5d, 0xbb, ++ 0xe1, 0x9f, 0x70, 0xec, 0x82, 0x11, 0x06, 0x36, ++ 0xec, 0x8b, 0x69, 0x66, 0x24, 0x44, 0xc9, 0x4a, ++ 0x57, 0xbb, 0x9b, 0x78, 0x13, 0xce, 0x9c, 0x0c, ++ 0xba, 0x92, 0x93, 0x63, 0xb8, 0xe2, 0x95, 0x0f, ++ 0x0f, 0x16, 0x39, 0x52, 0xfd, 0x3a, 0x6d, 0x02, ++ 0x4b, 0xdf, 0x13, 0xd3, 0x2a, 0x22, 0xb4, 0x03, ++ 0x7c, 0x54, 0x49, 0x96, 0x68, 0x54, 0x10, 0xfa, ++ 0xef, 0xaa, 0x6c, 0xe8, 0x22, 0xdc, 0x71, 0x16, ++ 0x13, 0x1a, 0xf6, 0x28, 0xe5, 0x6d, 0x77, 0x3d, ++ 0xcd, 0x30, 0x63, 0xb1, 0x70, 0x52, 0xa1, 0xc5, ++ 0x94, 0x5f, 0xcf, 0xe8, 0xb8, 0x26, 0x98, 0xf7, ++ 0x06, 0xa0, 0x0a, 0x70, 0xfa, 0x03, 0x80, 0xac, ++ 0xc1, 0xec, 0xd6, 0x4c, 0x54, 0xd7, 0xfe, 0x47, ++ 0xb6, 0x88, 0x4a, 0xf7, 0x71, 0x24, 0xee, 0xf3, ++ 0xd2, 0xc2, 0x4a, 0x7f, 0xfe, 0x61, 0xc7, 0x35, ++ 0xc9, 0x37, 0x67, 0xcb, 0x24, 0x35, 0xda, 0x7e, ++ 0xca, 0x5f, 0xf3, 0x8d, 0xd4, 0x13, 0x8e, 0xd6, ++ 0xcb, 0x4d, 0x53, 0x8f, 0x53, 0x1f, 0xc0, 0x74, ++ 0xf7, 0x53, 0xb9, 0x5e, 0x23, 0x37, 0xba, 0x6e, ++ 0xe3, 0x9d, 0x07, 0x55, 0x25, 0x7b, 0xe6, 0x2a, ++ 0x64, 0xd1, 0x32, 0xdd, 0x54, 0x1b, 0x4b, 0xc0, ++ 0xe1, 0xd7, 0x69, 0x58, 0xf8, 0x93, 0x29, 0xc4, ++ 0xdd, 0x23, 0x2f, 0xa5, 0xfc, 0x9d, 0x7e, 0xf8, ++ 0xd4, 0x90, 0xcd, 0x82, 0x55, 0xdc, 0x16, 0x16, ++ 0x9f, 0x07, 0x52, 0x9b, 0x9d, 0x25, 0xed, 0x32, ++ 0xc5, 0x7b, 0xdf, 0xf6, 0x83, 0x46, 0x3d, 0x65, ++ 0xb7, 0xef, 0x87, 0x7a, 0x12, 0x69, 0x8f, 0x06, ++ 0x7c, 0x51, 0x15, 0x4a, 0x08, 0xe8, 0xac, 0x9a, ++ 0x0c, 0x24, 0xa7, 0x27, 0xd8, 0x46, 0x2f, 0xe7, ++ 0x01, 0x0e, 0x1c, 0xc6, 0x91, 0xb0, 0x6e, 0x85, ++ 0x65, 0xf0, 0x29, 0x0d, 0x2e, 0x6b, 0x3b, 0xfb, ++ 0x4b, 0xdf, 0xe4, 0x80, 0x93, 0x03, 0x66, 0x46, ++ 0x3e, 0x8a, 0x6e, 0xf3, 0x5e, 0x4d, 0x62, 0x0e, ++ 0x49, 0x05, 0xaf, 0xd4, 0xf8, 0x21, 0x20, 0x61, ++ 0x1d, 0x39, 0x17, 0xf4, 0x61, 0x47, 0x95, 0xfb, ++ 0x15, 0x2e, 0xb3, 0x4f, 0xd0, 0x5d, 0xf5, 0x7d, ++ 0x40, 0xda, 0x90, 0x3c, 0x6b, 0xcb, 0x17, 0x00, ++ 0x13, 0x3b, 0x64, 0x34, 0x1b, 0xf0, 0xf2, 0xe5, ++ 0x3b, 0xb2, 0xc7, 0xd3, 0x5f, 0x3a, 0x44, 0xa6, ++ 0x9b, 0xb7, 0x78, 0x0e, 0x42, 0x5d, 0x4c, 0xc1, ++ 0xe9, 0xd2, 0xcb, 0xb7, 0x78, 0xd1, 0xfe, 0x9a, ++ 0xb5, 0x07, 0xe9, 0xe0, 0xbe, 0xe2, 0x8a, 0xa7, ++ 0x01, 0x83, 0x00, 0x8c, 0x5c, 0x08, 0xe6, 0x63, ++ 0x12, 0x92, 0xb7, 0xb7, 0xa6, 0x19, 0x7d, 0x38, ++ 0x13, 0x38, 0x92, 0x87, 0x24, 0xf9, 0x48, 0xb3, ++ 0x5e, 0x87, 0x6a, 0x40, 0x39, 0x5c, 0x3f, 0xed, ++ 0x8f, 0xee, 0xdb, 0x15, 0x82, 0x06, 0xda, 0x49, ++ 0x21, 0x2b, 0xb5, 0xbf, 0x32, 0x7c, 0x9f, 0x42, ++ 0x28, 0x63, 0xcf, 0xaf, 0x1e, 0xf8, 0xc6, 0xa0, ++ 0xd1, 0x02, 0x43, 0x57, 0x62, 0xec, 0x9b, 0x0f, ++ 0x01, 0x9e, 0x71, 0xd8, 0x87, 0x9d, 0x01, 0xc1, ++ 0x58, 0x77, 0xd9, 0xaf, 0xb1, 0x10, 0x7e, 0xdd, ++ 0xa6, 0x50, 0x96, 0xe5, 0xf0, 0x72, 0x00, 0x6d, ++ 0x4b, 0xf8, 0x2a, 0x8f, 0x19, 0xf3, 0x22, 0x88, ++ 0x11, 0x4a, 0x8b, 0x7c, 0xfd, 0xb7, 0xed, 0xe1, ++ 0xf6, 0x40, 0x39, 0xe0, 0xe9, 0xf6, 0x3d, 0x25, ++ 0xe6, 0x74, 0x3c, 0x58, 0x57, 0x7f, 0xe1, 0x22, ++ 0x96, 0x47, 0x31, 0x91, 0xba, 0x70, 0x85, 0x28, ++ 0x6b, 0x9f, 0x6e, 0x25, 0xac, 0x23, 0x66, 0x2f, ++ 0x29, 0x88, 0x28, 0xce, 0x8c, 0x5c, 0x88, 0x53, ++ 0xd1, 0x3b, 0xcc, 0x6a, 0x51, 0xb2, 0xe1, 0x28, ++ 0x3f, 0x91, 0xb4, 0x0d, 0x00, 0x3a, 0xe3, 0xf8, ++ 0xc3, 0x8f, 0xd7, 0x96, 0x62, 0x0e, 0x2e, 0xfc, ++ 0xc8, 0x6c, 0x77, 0xa6, 0x1d, 0x22, 0xc1, 0xb8, ++ 0xe6, 0x61, 0xd7, 0x67, 0x36, 0x13, 0x7b, 0xbb, ++ 0x9b, 0x59, 0x09, 0xa6, 0xdf, 0xf7, 0x6b, 0xa3, ++ 0x40, 0x1a, 0xf5, 0x4f, 0xb4, 0xda, 0xd3, 0xf3, ++ 0x81, 0x93, 0xc6, 0x18, 0xd9, 0x26, 0xee, 0xac, ++ 0xf0, 0xaa, 0xdf, 0xc5, 0x9c, 0xca, 0xc2, 0xa2, ++ 0xcc, 0x7b, 0x5c, 0x24, 0xb0, 0xbc, 0xd0, 0x6a, ++ 0x4d, 0x89, 0x09, 0xb8, 0x07, 0xfe, 0x87, 0xad, ++ 0x0a, 0xea, 0xb8, 0x42, 0xf9, 0x5e, 0xb3, 0x3e, ++ 0x36, 0x4c, 0xaf, 0x75, 0x9e, 0x1c, 0xeb, 0xbd, ++ 0xbc, 0xbb, 0x80, 0x40, 0xa7, 0x3a, 0x30, 0xbf, ++ 0xa8, 0x44, 0xf4, 0xeb, 0x38, 0xad, 0x29, 0xba, ++ 0x23, 0xed, 0x41, 0x0c, 0xea, 0xd2, 0xbb, 0x41, ++ 0x18, 0xd6, 0xb9, 0xba, 0x65, 0x2b, 0xa3, 0x91, ++ 0x6d, 0x1f, 0xa9, 0xf4, 0xd1, 0x25, 0x8d, 0x4d, ++ 0x38, 0xff, 0x64, 0xa0, 0xec, 0xde, 0xa6, 0xb6, ++ 0x79, 0xab, 0x8e, 0x33, 0x6c, 0x47, 0xde, 0xaf, ++ 0x94, 0xa4, 0xa5, 0x86, 0x77, 0x55, 0x09, 0x92, ++ 0x81, 0x31, 0x76, 0xc7, 0x34, 0x22, 0x89, 0x8e, ++ 0x3d, 0x26, 0x26, 0xd7, 0xfc, 0x1e, 0x16, 0x72, ++ 0x13, 0x33, 0x63, 0xd5, 0x22, 0xbe, 0xb8, 0x04, ++ 0x34, 0x84, 0x41, 0xbb, 0x80, 0xd0, 0x9f, 0x46, ++ 0x48, 0x07, 0xa7, 0xfc, 0x2b, 0x3a, 0x75, 0x55, ++ 0x8c, 0xc7, 0x6a, 0xbd, 0x7e, 0x46, 0x08, 0x84, ++ 0x0f, 0xd5, 0x74, 0xc0, 0x82, 0x8e, 0xaa, 0x61, ++ 0x05, 0x01, 0xb2, 0x47, 0x6e, 0x20, 0x6a, 0x2d, ++ 0x58, 0x70, 0x48, 0x32, 0xa7, 0x37, 0xd2, 0xb8, ++ 0x82, 0x1a, 0x51, 0xb9, 0x61, 0xdd, 0xfd, 0x9d, ++ 0x6b, 0x0e, 0x18, 0x97, 0xf8, 0x45, 0x5f, 0x87, ++ 0x10, 0xcf, 0x34, 0x72, 0x45, 0x26, 0x49, 0x70, ++ 0xe7, 0xa3, 0x78, 0xe0, 0x52, 0x89, 0x84, 0x94, ++ 0x83, 0x82, 0xc2, 0x69, 0x8f, 0xe3, 0xe1, 0x3f, ++ 0x60, 0x74, 0x88, 0xc4, 0xf7, 0x75, 0x2c, 0xfb, ++ 0xbd, 0xb6, 0xc4, 0x7e, 0x10, 0x0a, 0x6c, 0x90, ++ 0x04, 0x9e, 0xc3, 0x3f, 0x59, 0x7c, 0xce, 0x31, ++ 0x18, 0x60, 0x57, 0x73, 0x46, 0x94, 0x7d, 0x06, ++ 0xa0, 0x6d, 0x44, 0xec, 0xa2, 0x0a, 0x9e, 0x05, ++ 0x15, 0xef, 0xca, 0x5c, 0xbf, 0x00, 0xeb, 0xf7, ++ 0x3d, 0x32, 0xd4, 0xa5, 0xef, 0x49, 0x89, 0x5e, ++ 0x46, 0xb0, 0xa6, 0x63, 0x5b, 0x8a, 0x73, 0xae, ++ 0x6f, 0xd5, 0x9d, 0xf8, 0x4f, 0x40, 0xb5, 0xb2, ++ 0x6e, 0xd3, 0xb6, 0x01, 0xa9, 0x26, 0xa2, 0x21, ++ 0xcf, 0x33, 0x7a, 0x3a, 0xa4, 0x23, 0x13, 0xb0, ++ 0x69, 0x6a, 0xee, 0xce, 0xd8, 0x9d, 0x01, 0x1d, ++ 0x50, 0xc1, 0x30, 0x6c, 0xb1, 0xcd, 0xa0, 0xf0, ++ 0xf0, 0xa2, 0x64, 0x6f, 0xbb, 0xbf, 0x5e, 0xe6, ++ 0xab, 0x87, 0xb4, 0x0f, 0x4f, 0x15, 0xaf, 0xb5, ++ 0x25, 0xa1, 0xb2, 0xd0, 0x80, 0x2c, 0xfb, 0xf9, ++ 0xfe, 0xd2, 0x33, 0xbb, 0x76, 0xfe, 0x7c, 0xa8, ++ 0x66, 0xf7, 0xe7, 0x85, 0x9f, 0x1f, 0x85, 0x57, ++ 0x88, 0xe1, 0xe9, 0x63, 0xe4, 0xd8, 0x1c, 0xa1, ++ 0xfb, 0xda, 0x44, 0x05, 0x2e, 0x1d, 0x3a, 0x1c, ++ 0xff, 0xc8, 0x3b, 0xc0, 0xfe, 0xda, 0x22, 0x0b, ++ 0x43, 0xd6, 0x88, 0x39, 0x4c, 0x4a, 0xa6, 0x69, ++ 0x18, 0x93, 0x42, 0x4e, 0xb5, 0xcc, 0x66, 0x0d, ++ 0x09, 0xf8, 0x1e, 0x7c, 0xd3, 0x3c, 0x99, 0x0d, ++ 0x50, 0x1d, 0x62, 0xe9, 0x57, 0x06, 0xbf, 0x19, ++ 0x88, 0xdd, 0xad, 0x7b, 0x4f, 0xf9, 0xc7, 0x82, ++ 0x6d, 0x8d, 0xc8, 0xc4, 0xc5, 0x78, 0x17, 0x20, ++ 0x15, 0xc5, 0x52, 0x41, 0xcf, 0x5b, 0xd6, 0x7f, ++ 0x94, 0x02, 0x41, 0xe0, 0x40, 0x22, 0x03, 0x5e, ++ 0xd1, 0x53, 0xd4, 0x86, 0xd3, 0x2c, 0x9f, 0x0f, ++ 0x96, 0xe3, 0x6b, 0x9a, 0x76, 0x32, 0x06, 0x47, ++ 0x4b, 0x11, 0xb3, 0xdd, 0x03, 0x65, 0xbd, 0x9b, ++ 0x01, 0xda, 0x9c, 0xb9, 0x7e, 0x3f, 0x6a, 0xc4, ++ 0x7b, 0xea, 0xd4, 0x3c, 0xb9, 0xfb, 0x5c, 0x6b, ++ 0x64, 0x33, 0x52, 0xba, 0x64, 0x78, 0x8f, 0xa4, ++ 0xaf, 0x7a, 0x61, 0x8d, 0xbc, 0xc5, 0x73, 0xe9, ++ 0x6b, 0x58, 0x97, 0x4b, 0xbf, 0x63, 0x22, 0xd3, ++ 0x37, 0x02, 0x54, 0xc5, 0xb9, 0x16, 0x4a, 0xf0, ++ 0x19, 0xd8, 0x94, 0x57, 0xb8, 0x8a, 0xb3, 0x16, ++ 0x3b, 0xd0, 0x84, 0x8e, 0x67, 0xa6, 0xa3, 0x7d, ++ 0x78, 0xec, 0x00 ++}; ++static const u8 dec_assoc013[] __initconst = { ++ 0xb1, 0x69, 0x83, 0x87, 0x30, 0xaa, 0x5d, 0xb8, ++ 0x77, 0xe8, 0x21, 0xff, 0x06, 0x59, 0x35, 0xce, ++ 0x75, 0xfe, 0x38, 0xef, 0xb8, 0x91, 0x43, 0x8c, ++ 0xcf, 0x70, 0xdd, 0x0a, 0x68, 0xbf, 0xd4, 0xbc, ++ 0x16, 0x76, 0x99, 0x36, 0x1e, 0x58, 0x79, 0x5e, ++ 0xd4, 0x29, 0xf7, 0x33, 0x93, 0x48, 0xdb, 0x5f, ++ 0x01, 0xae, 0x9c, 0xb6, 0xe4, 0x88, 0x6d, 0x2b, ++ 0x76, 0x75, 0xe0, 0xf3, 0x74, 0xe2, 0xc9 ++}; ++static const u8 dec_nonce013[] __initconst = { ++ 0x05, 0xa3, 0x93, 0xed, 0x30, 0xc5, 0xa2, 0x06 ++}; ++static const u8 dec_key013[] __initconst = { ++ 0xb3, 0x35, 0x50, 0x03, 0x54, 0x2e, 0x40, 0x5e, ++ 0x8f, 0x59, 0x8e, 0xc5, 0x90, 0xd5, 0x27, 0x2d, ++ 0xba, 0x29, 0x2e, 0xcb, 0x1b, 0x70, 0x44, 0x1e, ++ 0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64 ++}; ++ ++static const struct chacha20poly1305_testvec ++chacha20poly1305_dec_vectors[] __initconst = { ++ { dec_input001, dec_output001, dec_assoc001, dec_nonce001, dec_key001, ++ sizeof(dec_input001), sizeof(dec_assoc001), sizeof(dec_nonce001) }, ++ { dec_input002, dec_output002, dec_assoc002, dec_nonce002, dec_key002, ++ sizeof(dec_input002), sizeof(dec_assoc002), sizeof(dec_nonce002) }, ++ { dec_input003, dec_output003, dec_assoc003, dec_nonce003, dec_key003, ++ sizeof(dec_input003), sizeof(dec_assoc003), sizeof(dec_nonce003) }, ++ { dec_input004, dec_output004, dec_assoc004, dec_nonce004, dec_key004, ++ sizeof(dec_input004), sizeof(dec_assoc004), sizeof(dec_nonce004) }, ++ { dec_input005, dec_output005, dec_assoc005, dec_nonce005, dec_key005, ++ sizeof(dec_input005), sizeof(dec_assoc005), sizeof(dec_nonce005) }, ++ { dec_input006, dec_output006, dec_assoc006, dec_nonce006, dec_key006, ++ sizeof(dec_input006), sizeof(dec_assoc006), sizeof(dec_nonce006) }, ++ { dec_input007, dec_output007, dec_assoc007, dec_nonce007, dec_key007, ++ sizeof(dec_input007), sizeof(dec_assoc007), sizeof(dec_nonce007) }, ++ { dec_input008, dec_output008, dec_assoc008, dec_nonce008, dec_key008, ++ sizeof(dec_input008), sizeof(dec_assoc008), sizeof(dec_nonce008) }, ++ { dec_input009, dec_output009, dec_assoc009, dec_nonce009, dec_key009, ++ sizeof(dec_input009), sizeof(dec_assoc009), sizeof(dec_nonce009) }, ++ { dec_input010, dec_output010, dec_assoc010, dec_nonce010, dec_key010, ++ sizeof(dec_input010), sizeof(dec_assoc010), sizeof(dec_nonce010) }, ++ { dec_input011, dec_output011, dec_assoc011, dec_nonce011, dec_key011, ++ sizeof(dec_input011), sizeof(dec_assoc011), sizeof(dec_nonce011) }, ++ { dec_input012, dec_output012, dec_assoc012, dec_nonce012, dec_key012, ++ sizeof(dec_input012), sizeof(dec_assoc012), sizeof(dec_nonce012) }, ++ { dec_input013, dec_output013, dec_assoc013, dec_nonce013, dec_key013, ++ sizeof(dec_input013), sizeof(dec_assoc013), sizeof(dec_nonce013), ++ true } ++}; ++ ++static const u8 xenc_input001[] __initconst = { ++ 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, ++ 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, ++ 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66, ++ 0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69, ++ 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, ++ 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, ++ 0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d, ++ 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e, ++ 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, ++ 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, ++ 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, ++ 0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, ++ 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64, ++ 0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65, ++ 0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, ++ 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, ++ 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, ++ 0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, ++ 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, ++ 0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, ++ 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, ++ 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72, ++ 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, ++ 0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, ++ 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, ++ 0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, ++ 0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, ++ 0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20, ++ 0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, ++ 0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, ++ 0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80, ++ 0x9d ++}; ++static const u8 xenc_output001[] __initconst = { ++ 0x1a, 0x6e, 0x3a, 0xd9, 0xfd, 0x41, 0x3f, 0x77, ++ 0x54, 0x72, 0x0a, 0x70, 0x9a, 0xa0, 0x29, 0x92, ++ 0x2e, 0xed, 0x93, 0xcf, 0x0f, 0x71, 0x88, 0x18, ++ 0x7a, 0x9d, 0x2d, 0x24, 0xe0, 0xf5, 0xea, 0x3d, ++ 0x55, 0x64, 0xd7, 0xad, 0x2a, 0x1a, 0x1f, 0x7e, ++ 0x86, 0x6d, 0xb0, 0xce, 0x80, 0x41, 0x72, 0x86, ++ 0x26, 0xee, 0x84, 0xd7, 0xef, 0x82, 0x9e, 0xe2, ++ 0x60, 0x9d, 0x5a, 0xfc, 0xf0, 0xe4, 0x19, 0x85, ++ 0xea, 0x09, 0xc6, 0xfb, 0xb3, 0xa9, 0x50, 0x09, ++ 0xec, 0x5e, 0x11, 0x90, 0xa1, 0xc5, 0x4e, 0x49, ++ 0xef, 0x50, 0xd8, 0x8f, 0xe0, 0x78, 0xd7, 0xfd, ++ 0xb9, 0x3b, 0xc9, 0xf2, 0x91, 0xc8, 0x25, 0xc8, ++ 0xa7, 0x63, 0x60, 0xce, 0x10, 0xcd, 0xc6, 0x7f, ++ 0xf8, 0x16, 0xf8, 0xe1, 0x0a, 0xd9, 0xde, 0x79, ++ 0x50, 0x33, 0xf2, 0x16, 0x0f, 0x17, 0xba, 0xb8, ++ 0x5d, 0xd8, 0xdf, 0x4e, 0x51, 0xa8, 0x39, 0xd0, ++ 0x85, 0xca, 0x46, 0x6a, 0x10, 0xa7, 0xa3, 0x88, ++ 0xef, 0x79, 0xb9, 0xf8, 0x24, 0xf3, 0xe0, 0x71, ++ 0x7b, 0x76, 0x28, 0x46, 0x3a, 0x3a, 0x1b, 0x91, ++ 0xb6, 0xd4, 0x3e, 0x23, 0xe5, 0x44, 0x15, 0xbf, ++ 0x60, 0x43, 0x9d, 0xa4, 0xbb, 0xd5, 0x5f, 0x89, ++ 0xeb, 0xef, 0x8e, 0xfd, 0xdd, 0xb4, 0x0d, 0x46, ++ 0xf0, 0x69, 0x23, 0x63, 0xae, 0x94, 0xf5, 0x5e, ++ 0xa5, 0xad, 0x13, 0x1c, 0x41, 0x76, 0xe6, 0x90, ++ 0xd6, 0x6d, 0xa2, 0x8f, 0x97, 0x4c, 0xa8, 0x0b, ++ 0xcf, 0x8d, 0x43, 0x2b, 0x9c, 0x9b, 0xc5, 0x58, ++ 0xa5, 0xb6, 0x95, 0x9a, 0xbf, 0x81, 0xc6, 0x54, ++ 0xc9, 0x66, 0x0c, 0xe5, 0x4f, 0x6a, 0x53, 0xa1, ++ 0xe5, 0x0c, 0xba, 0x31, 0xde, 0x34, 0x64, 0x73, ++ 0x8a, 0x3b, 0xbd, 0x92, 0x01, 0xdb, 0x71, 0x69, ++ 0xf3, 0x58, 0x99, 0xbc, 0xd1, 0xcb, 0x4a, 0x05, ++ 0xe2, 0x58, 0x9c, 0x25, 0x17, 0xcd, 0xdc, 0x83, ++ 0xb7, 0xff, 0xfb, 0x09, 0x61, 0xad, 0xbf, 0x13, ++ 0x5b, 0x5e, 0xed, 0x46, 0x82, 0x6f, 0x22, 0xd8, ++ 0x93, 0xa6, 0x85, 0x5b, 0x40, 0x39, 0x5c, 0xc5, ++ 0x9c ++}; ++static const u8 xenc_assoc001[] __initconst = { ++ 0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x4e, 0x91 ++}; ++static const u8 xenc_nonce001[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 ++}; ++static const u8 xenc_key001[] __initconst = { ++ 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, ++ 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, ++ 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, ++ 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 ++}; ++ ++static const struct chacha20poly1305_testvec ++xchacha20poly1305_enc_vectors[] __initconst = { ++ { xenc_input001, xenc_output001, xenc_assoc001, xenc_nonce001, xenc_key001, ++ sizeof(xenc_input001), sizeof(xenc_assoc001), sizeof(xenc_nonce001) } ++}; ++ ++static const u8 xdec_input001[] __initconst = { ++ 0x1a, 0x6e, 0x3a, 0xd9, 0xfd, 0x41, 0x3f, 0x77, ++ 0x54, 0x72, 0x0a, 0x70, 0x9a, 0xa0, 0x29, 0x92, ++ 0x2e, 0xed, 0x93, 0xcf, 0x0f, 0x71, 0x88, 0x18, ++ 0x7a, 0x9d, 0x2d, 0x24, 0xe0, 0xf5, 0xea, 0x3d, ++ 0x55, 0x64, 0xd7, 0xad, 0x2a, 0x1a, 0x1f, 0x7e, ++ 0x86, 0x6d, 0xb0, 0xce, 0x80, 0x41, 0x72, 0x86, ++ 0x26, 0xee, 0x84, 0xd7, 0xef, 0x82, 0x9e, 0xe2, ++ 0x60, 0x9d, 0x5a, 0xfc, 0xf0, 0xe4, 0x19, 0x85, ++ 0xea, 0x09, 0xc6, 0xfb, 0xb3, 0xa9, 0x50, 0x09, ++ 0xec, 0x5e, 0x11, 0x90, 0xa1, 0xc5, 0x4e, 0x49, ++ 0xef, 0x50, 0xd8, 0x8f, 0xe0, 0x78, 0xd7, 0xfd, ++ 0xb9, 0x3b, 0xc9, 0xf2, 0x91, 0xc8, 0x25, 0xc8, ++ 0xa7, 0x63, 0x60, 0xce, 0x10, 0xcd, 0xc6, 0x7f, ++ 0xf8, 0x16, 0xf8, 0xe1, 0x0a, 0xd9, 0xde, 0x79, ++ 0x50, 0x33, 0xf2, 0x16, 0x0f, 0x17, 0xba, 0xb8, ++ 0x5d, 0xd8, 0xdf, 0x4e, 0x51, 0xa8, 0x39, 0xd0, ++ 0x85, 0xca, 0x46, 0x6a, 0x10, 0xa7, 0xa3, 0x88, ++ 0xef, 0x79, 0xb9, 0xf8, 0x24, 0xf3, 0xe0, 0x71, ++ 0x7b, 0x76, 0x28, 0x46, 0x3a, 0x3a, 0x1b, 0x91, ++ 0xb6, 0xd4, 0x3e, 0x23, 0xe5, 0x44, 0x15, 0xbf, ++ 0x60, 0x43, 0x9d, 0xa4, 0xbb, 0xd5, 0x5f, 0x89, ++ 0xeb, 0xef, 0x8e, 0xfd, 0xdd, 0xb4, 0x0d, 0x46, ++ 0xf0, 0x69, 0x23, 0x63, 0xae, 0x94, 0xf5, 0x5e, ++ 0xa5, 0xad, 0x13, 0x1c, 0x41, 0x76, 0xe6, 0x90, ++ 0xd6, 0x6d, 0xa2, 0x8f, 0x97, 0x4c, 0xa8, 0x0b, ++ 0xcf, 0x8d, 0x43, 0x2b, 0x9c, 0x9b, 0xc5, 0x58, ++ 0xa5, 0xb6, 0x95, 0x9a, 0xbf, 0x81, 0xc6, 0x54, ++ 0xc9, 0x66, 0x0c, 0xe5, 0x4f, 0x6a, 0x53, 0xa1, ++ 0xe5, 0x0c, 0xba, 0x31, 0xde, 0x34, 0x64, 0x73, ++ 0x8a, 0x3b, 0xbd, 0x92, 0x01, 0xdb, 0x71, 0x69, ++ 0xf3, 0x58, 0x99, 0xbc, 0xd1, 0xcb, 0x4a, 0x05, ++ 0xe2, 0x58, 0x9c, 0x25, 0x17, 0xcd, 0xdc, 0x83, ++ 0xb7, 0xff, 0xfb, 0x09, 0x61, 0xad, 0xbf, 0x13, ++ 0x5b, 0x5e, 0xed, 0x46, 0x82, 0x6f, 0x22, 0xd8, ++ 0x93, 0xa6, 0x85, 0x5b, 0x40, 0x39, 0x5c, 0xc5, ++ 0x9c ++}; ++static const u8 xdec_output001[] __initconst = { ++ 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, ++ 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, ++ 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66, ++ 0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69, ++ 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, ++ 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, ++ 0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d, ++ 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e, ++ 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, ++ 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, ++ 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, ++ 0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, ++ 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64, ++ 0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65, ++ 0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, ++ 0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, ++ 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, ++ 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, ++ 0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, ++ 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, ++ 0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, ++ 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, ++ 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72, ++ 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, ++ 0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, ++ 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, ++ 0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, ++ 0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, ++ 0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20, ++ 0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, ++ 0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, ++ 0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80, ++ 0x9d ++}; ++static const u8 xdec_assoc001[] __initconst = { ++ 0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x4e, 0x91 ++}; ++static const u8 xdec_nonce001[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 ++}; ++static const u8 xdec_key001[] __initconst = { ++ 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, ++ 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, ++ 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, ++ 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 ++}; ++ ++static const struct chacha20poly1305_testvec ++xchacha20poly1305_dec_vectors[] __initconst = { ++ { xdec_input001, xdec_output001, xdec_assoc001, xdec_nonce001, xdec_key001, ++ sizeof(xdec_input001), sizeof(xdec_assoc001), sizeof(xdec_nonce001) } ++}; ++ ++static void __init ++chacha20poly1305_selftest_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 *nonce, const size_t nonce_len, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ if (nonce_len == 8) ++ chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, ++ get_unaligned_le64(nonce), key); ++ else ++ BUG(); ++} ++ ++static bool __init ++decryption_success(bool func_ret, bool expect_failure, int memcmp_result) ++{ ++ if (expect_failure) ++ return !func_ret; ++ return func_ret && !memcmp_result; ++} ++ ++bool __init chacha20poly1305_selftest(void) ++{ ++ enum { MAXIMUM_TEST_BUFFER_LEN = 1UL << 12 }; ++ size_t i; ++ u8 *computed_output = NULL, *heap_src = NULL; ++ bool success = true, ret; ++ ++ heap_src = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL); ++ computed_output = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL); ++ if (!heap_src || !computed_output) { ++ pr_err("chacha20poly1305 self-test malloc: FAIL\n"); ++ success = false; ++ goto out; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) { ++ memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); ++ chacha20poly1305_selftest_encrypt(computed_output, ++ chacha20poly1305_enc_vectors[i].input, ++ chacha20poly1305_enc_vectors[i].ilen, ++ chacha20poly1305_enc_vectors[i].assoc, ++ chacha20poly1305_enc_vectors[i].alen, ++ chacha20poly1305_enc_vectors[i].nonce, ++ chacha20poly1305_enc_vectors[i].nlen, ++ chacha20poly1305_enc_vectors[i].key); ++ if (memcmp(computed_output, ++ chacha20poly1305_enc_vectors[i].output, ++ chacha20poly1305_enc_vectors[i].ilen + ++ POLY1305_DIGEST_SIZE)) { ++ pr_err("chacha20poly1305 encryption self-test %zu: FAIL\n", ++ i + 1); ++ success = false; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) { ++ memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); ++ ret = chacha20poly1305_decrypt(computed_output, ++ chacha20poly1305_dec_vectors[i].input, ++ chacha20poly1305_dec_vectors[i].ilen, ++ chacha20poly1305_dec_vectors[i].assoc, ++ chacha20poly1305_dec_vectors[i].alen, ++ get_unaligned_le64(chacha20poly1305_dec_vectors[i].nonce), ++ chacha20poly1305_dec_vectors[i].key); ++ if (!decryption_success(ret, ++ chacha20poly1305_dec_vectors[i].failure, ++ memcmp(computed_output, ++ chacha20poly1305_dec_vectors[i].output, ++ chacha20poly1305_dec_vectors[i].ilen - ++ POLY1305_DIGEST_SIZE))) { ++ pr_err("chacha20poly1305 decryption self-test %zu: FAIL\n", ++ i + 1); ++ success = false; ++ } ++ } ++ ++ ++ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_enc_vectors); ++i) { ++ memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); ++ xchacha20poly1305_encrypt(computed_output, ++ xchacha20poly1305_enc_vectors[i].input, ++ xchacha20poly1305_enc_vectors[i].ilen, ++ xchacha20poly1305_enc_vectors[i].assoc, ++ xchacha20poly1305_enc_vectors[i].alen, ++ xchacha20poly1305_enc_vectors[i].nonce, ++ xchacha20poly1305_enc_vectors[i].key); ++ if (memcmp(computed_output, ++ xchacha20poly1305_enc_vectors[i].output, ++ xchacha20poly1305_enc_vectors[i].ilen + ++ POLY1305_DIGEST_SIZE)) { ++ pr_err("xchacha20poly1305 encryption self-test %zu: FAIL\n", ++ i + 1); ++ success = false; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_dec_vectors); ++i) { ++ memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); ++ ret = xchacha20poly1305_decrypt(computed_output, ++ xchacha20poly1305_dec_vectors[i].input, ++ xchacha20poly1305_dec_vectors[i].ilen, ++ xchacha20poly1305_dec_vectors[i].assoc, ++ xchacha20poly1305_dec_vectors[i].alen, ++ xchacha20poly1305_dec_vectors[i].nonce, ++ xchacha20poly1305_dec_vectors[i].key); ++ if (!decryption_success(ret, ++ xchacha20poly1305_dec_vectors[i].failure, ++ memcmp(computed_output, ++ xchacha20poly1305_dec_vectors[i].output, ++ xchacha20poly1305_dec_vectors[i].ilen - ++ POLY1305_DIGEST_SIZE))) { ++ pr_err("xchacha20poly1305 decryption self-test %zu: FAIL\n", ++ i + 1); ++ success = false; ++ } ++ } ++ ++out: ++ kfree(heap_src); ++ kfree(computed_output); ++ return success; ++} +--- /dev/null ++++ b/lib/crypto/chacha20poly1305.c +@@ -0,0 +1,219 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is an implementation of the ChaCha20Poly1305 AEAD construction. ++ * ++ * Information: https://tools.ietf.org/html/rfc8439 ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define CHACHA_KEY_WORDS (CHACHA_KEY_SIZE / sizeof(u32)) ++ ++bool __init chacha20poly1305_selftest(void); ++ ++static void chacha_load_key(u32 *k, const u8 *in) ++{ ++ k[0] = get_unaligned_le32(in); ++ k[1] = get_unaligned_le32(in + 4); ++ k[2] = get_unaligned_le32(in + 8); ++ k[3] = get_unaligned_le32(in + 12); ++ k[4] = get_unaligned_le32(in + 16); ++ k[5] = get_unaligned_le32(in + 20); ++ k[6] = get_unaligned_le32(in + 24); ++ k[7] = get_unaligned_le32(in + 28); ++} ++ ++static void xchacha_init(u32 *chacha_state, const u8 *key, const u8 *nonce) ++{ ++ u32 k[CHACHA_KEY_WORDS]; ++ u8 iv[CHACHA_IV_SIZE]; ++ ++ memset(iv, 0, 8); ++ memcpy(iv + 8, nonce + 16, 8); ++ ++ chacha_load_key(k, key); ++ ++ /* Compute the subkey given the original key and first 128 nonce bits */ ++ chacha_init(chacha_state, k, nonce); ++ hchacha_block(chacha_state, k, 20); ++ ++ chacha_init(chacha_state, k, iv); ++ ++ memzero_explicit(k, sizeof(k)); ++ memzero_explicit(iv, sizeof(iv)); ++} ++ ++static void ++__chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, u32 *chacha_state) ++{ ++ const u8 *pad0 = page_address(ZERO_PAGE(0)); ++ struct poly1305_desc_ctx poly1305_state; ++ union { ++ u8 block0[POLY1305_KEY_SIZE]; ++ __le64 lens[2]; ++ } b; ++ ++ chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20); ++ poly1305_init(&poly1305_state, b.block0); ++ ++ poly1305_update(&poly1305_state, ad, ad_len); ++ if (ad_len & 0xf) ++ poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); ++ ++ chacha_crypt(chacha_state, dst, src, src_len, 20); ++ ++ poly1305_update(&poly1305_state, dst, src_len); ++ if (src_len & 0xf) ++ poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf)); ++ ++ b.lens[0] = cpu_to_le64(ad_len); ++ b.lens[1] = cpu_to_le64(src_len); ++ poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); ++ ++ poly1305_final(&poly1305_state, dst + src_len); ++ ++ memzero_explicit(chacha_state, CHACHA_STATE_WORDS * sizeof(u32)); ++ memzero_explicit(&b, sizeof(b)); ++} ++ ++void chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ u32 chacha_state[CHACHA_STATE_WORDS]; ++ u32 k[CHACHA_KEY_WORDS]; ++ __le64 iv[2]; ++ ++ chacha_load_key(k, key); ++ ++ iv[0] = 0; ++ iv[1] = cpu_to_le64(nonce); ++ ++ chacha_init(chacha_state, k, (u8 *)iv); ++ __chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state); ++ ++ memzero_explicit(iv, sizeof(iv)); ++ memzero_explicit(k, sizeof(k)); ++} ++EXPORT_SYMBOL(chacha20poly1305_encrypt); ++ ++void xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ u32 chacha_state[CHACHA_STATE_WORDS]; ++ ++ xchacha_init(chacha_state, key, nonce); ++ __chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, chacha_state); ++} ++EXPORT_SYMBOL(xchacha20poly1305_encrypt); ++ ++static bool ++__chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, u32 *chacha_state) ++{ ++ const u8 *pad0 = page_address(ZERO_PAGE(0)); ++ struct poly1305_desc_ctx poly1305_state; ++ size_t dst_len; ++ int ret; ++ union { ++ u8 block0[POLY1305_KEY_SIZE]; ++ u8 mac[POLY1305_DIGEST_SIZE]; ++ __le64 lens[2]; ++ } b; ++ ++ if (unlikely(src_len < POLY1305_DIGEST_SIZE)) ++ return false; ++ ++ chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20); ++ poly1305_init(&poly1305_state, b.block0); ++ ++ poly1305_update(&poly1305_state, ad, ad_len); ++ if (ad_len & 0xf) ++ poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); ++ ++ dst_len = src_len - POLY1305_DIGEST_SIZE; ++ poly1305_update(&poly1305_state, src, dst_len); ++ if (dst_len & 0xf) ++ poly1305_update(&poly1305_state, pad0, 0x10 - (dst_len & 0xf)); ++ ++ b.lens[0] = cpu_to_le64(ad_len); ++ b.lens[1] = cpu_to_le64(dst_len); ++ poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); ++ ++ poly1305_final(&poly1305_state, b.mac); ++ ++ ret = crypto_memneq(b.mac, src + dst_len, POLY1305_DIGEST_SIZE); ++ if (likely(!ret)) ++ chacha_crypt(chacha_state, dst, src, dst_len, 20); ++ ++ memzero_explicit(&b, sizeof(b)); ++ ++ return !ret; ++} ++ ++bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ u32 chacha_state[CHACHA_STATE_WORDS]; ++ u32 k[CHACHA_KEY_WORDS]; ++ __le64 iv[2]; ++ bool ret; ++ ++ chacha_load_key(k, key); ++ ++ iv[0] = 0; ++ iv[1] = cpu_to_le64(nonce); ++ ++ chacha_init(chacha_state, k, (u8 *)iv); ++ ret = __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, ++ chacha_state); ++ ++ memzero_explicit(chacha_state, sizeof(chacha_state)); ++ memzero_explicit(iv, sizeof(iv)); ++ memzero_explicit(k, sizeof(k)); ++ return ret; ++} ++EXPORT_SYMBOL(chacha20poly1305_decrypt); ++ ++bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ u32 chacha_state[CHACHA_STATE_WORDS]; ++ ++ xchacha_init(chacha_state, key, nonce); ++ return __chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, ++ chacha_state); ++} ++EXPORT_SYMBOL(xchacha20poly1305_decrypt); ++ ++static int __init mod_init(void) ++{ ++ if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && ++ WARN_ON(!chacha20poly1305_selftest())) ++ return -ENODEV; ++ return 0; ++} ++ ++module_init(mod_init); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction"); ++MODULE_AUTHOR("Jason A. Donenfeld "); diff --git a/ipq806x/backport-5.4/080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch b/ipq806x/backport-5.4/080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch new file mode 100644 index 0000000..e4b2b58 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0033-crypto-lib-chacha20poly1305-reimplement-crypt_from_s.patch @@ -0,0 +1,295 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 8 Nov 2019 13:22:40 +0100 +Subject: [PATCH] crypto: lib/chacha20poly1305 - reimplement crypt_from_sg() + routine + +commit d95312a3ccc0cd544d374be2fc45aeaa803e5fd9 upstream. + +Reimplement the library routines to perform chacha20poly1305 en/decryption +on scatterlists, without [ab]using the [deprecated] blkcipher interface, +which is rather heavyweight and does things we don't really need. + +Instead, we use the sg_miter API in a novel and clever way, to iterate +over the scatterlist in-place (i.e., source == destination, which is the +only way this library is expected to be used). That way, we don't have to +iterate over two scatterlists in parallel. + +Another optimization is that, instead of relying on the blkcipher walker +to present the input in suitable chunks, we recognize that ChaCha is a +streamcipher, and so we can simply deal with partial blocks by keeping a +block of cipherstream on the stack and use crypto_xor() to mix it with +the in/output. + +Finally, we omit the scatterwalk_and_copy() call if the last element of +the scatterlist covers the MAC as well (which is the common case), +avoiding the need to walk the scatterlist and kmap() the page twice. + +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + include/crypto/chacha20poly1305.h | 11 ++ + lib/crypto/chacha20poly1305-selftest.c | 45 ++++++++ + lib/crypto/chacha20poly1305.c | 150 +++++++++++++++++++++++++ + 3 files changed, 206 insertions(+) + +--- a/include/crypto/chacha20poly1305.h ++++ b/include/crypto/chacha20poly1305.h +@@ -7,6 +7,7 @@ + #define __CHACHA20POLY1305_H + + #include ++#include + + enum chacha20poly1305_lengths { + XCHACHA20POLY1305_NONCE_SIZE = 24, +@@ -34,4 +35,14 @@ bool __must_check xchacha20poly1305_decr + const size_t ad_len, const u8 nonce[XCHACHA20POLY1305_NONCE_SIZE], + const u8 key[CHACHA20POLY1305_KEY_SIZE]); + ++bool chacha20poly1305_encrypt_sg_inplace(struct scatterlist *src, size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]); ++ ++bool chacha20poly1305_decrypt_sg_inplace(struct scatterlist *src, size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]); ++ + #endif /* __CHACHA20POLY1305_H */ +--- a/lib/crypto/chacha20poly1305-selftest.c ++++ b/lib/crypto/chacha20poly1305-selftest.c +@@ -7250,6 +7250,7 @@ bool __init chacha20poly1305_selftest(vo + enum { MAXIMUM_TEST_BUFFER_LEN = 1UL << 12 }; + size_t i; + u8 *computed_output = NULL, *heap_src = NULL; ++ struct scatterlist sg_src; + bool success = true, ret; + + heap_src = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL); +@@ -7280,6 +7281,29 @@ bool __init chacha20poly1305_selftest(vo + } + } + ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) { ++ if (chacha20poly1305_enc_vectors[i].nlen != 8) ++ continue; ++ memcpy(heap_src, chacha20poly1305_enc_vectors[i].input, ++ chacha20poly1305_enc_vectors[i].ilen); ++ sg_init_one(&sg_src, heap_src, ++ chacha20poly1305_enc_vectors[i].ilen + POLY1305_DIGEST_SIZE); ++ chacha20poly1305_encrypt_sg_inplace(&sg_src, ++ chacha20poly1305_enc_vectors[i].ilen, ++ chacha20poly1305_enc_vectors[i].assoc, ++ chacha20poly1305_enc_vectors[i].alen, ++ get_unaligned_le64(chacha20poly1305_enc_vectors[i].nonce), ++ chacha20poly1305_enc_vectors[i].key); ++ if (memcmp(heap_src, ++ chacha20poly1305_enc_vectors[i].output, ++ chacha20poly1305_enc_vectors[i].ilen + ++ POLY1305_DIGEST_SIZE)) { ++ pr_err("chacha20poly1305 sg encryption self-test %zu: FAIL\n", ++ i + 1); ++ success = false; ++ } ++ } ++ + for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) { + memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); + ret = chacha20poly1305_decrypt(computed_output, +@@ -7301,6 +7325,27 @@ bool __init chacha20poly1305_selftest(vo + } + } + ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) { ++ memcpy(heap_src, chacha20poly1305_dec_vectors[i].input, ++ chacha20poly1305_dec_vectors[i].ilen); ++ sg_init_one(&sg_src, heap_src, ++ chacha20poly1305_dec_vectors[i].ilen); ++ ret = chacha20poly1305_decrypt_sg_inplace(&sg_src, ++ chacha20poly1305_dec_vectors[i].ilen, ++ chacha20poly1305_dec_vectors[i].assoc, ++ chacha20poly1305_dec_vectors[i].alen, ++ get_unaligned_le64(chacha20poly1305_dec_vectors[i].nonce), ++ chacha20poly1305_dec_vectors[i].key); ++ if (!decryption_success(ret, ++ chacha20poly1305_dec_vectors[i].failure, ++ memcmp(heap_src, chacha20poly1305_dec_vectors[i].output, ++ chacha20poly1305_dec_vectors[i].ilen - ++ POLY1305_DIGEST_SIZE))) { ++ pr_err("chacha20poly1305 sg decryption self-test %zu: FAIL\n", ++ i + 1); ++ success = false; ++ } ++ } + + for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_enc_vectors); ++i) { + memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); +--- a/lib/crypto/chacha20poly1305.c ++++ b/lib/crypto/chacha20poly1305.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -205,6 +206,155 @@ bool xchacha20poly1305_decrypt(u8 *dst, + } + EXPORT_SYMBOL(xchacha20poly1305_decrypt); + ++static ++bool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src, ++ const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE], ++ int encrypt) ++{ ++ const u8 *pad0 = page_address(ZERO_PAGE(0)); ++ struct poly1305_desc_ctx poly1305_state; ++ u32 chacha_state[CHACHA_STATE_WORDS]; ++ struct sg_mapping_iter miter; ++ size_t partial = 0; ++ unsigned int flags; ++ bool ret = true; ++ int sl; ++ union { ++ struct { ++ u32 k[CHACHA_KEY_WORDS]; ++ __le64 iv[2]; ++ }; ++ u8 block0[POLY1305_KEY_SIZE]; ++ u8 chacha_stream[CHACHA_BLOCK_SIZE]; ++ struct { ++ u8 mac[2][POLY1305_DIGEST_SIZE]; ++ }; ++ __le64 lens[2]; ++ } b __aligned(16); ++ ++ chacha_load_key(b.k, key); ++ ++ b.iv[0] = 0; ++ b.iv[1] = cpu_to_le64(nonce); ++ ++ chacha_init(chacha_state, b.k, (u8 *)b.iv); ++ chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20); ++ poly1305_init(&poly1305_state, b.block0); ++ ++ if (unlikely(ad_len)) { ++ poly1305_update(&poly1305_state, ad, ad_len); ++ if (ad_len & 0xf) ++ poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); ++ } ++ ++ flags = SG_MITER_TO_SG; ++ if (!preemptible()) ++ flags |= SG_MITER_ATOMIC; ++ ++ sg_miter_start(&miter, src, sg_nents(src), flags); ++ ++ for (sl = src_len; sl > 0 && sg_miter_next(&miter); sl -= miter.length) { ++ u8 *addr = miter.addr; ++ size_t length = min_t(size_t, sl, miter.length); ++ ++ if (!encrypt) ++ poly1305_update(&poly1305_state, addr, length); ++ ++ if (unlikely(partial)) { ++ size_t l = min(length, CHACHA_BLOCK_SIZE - partial); ++ ++ crypto_xor(addr, b.chacha_stream + partial, l); ++ partial = (partial + l) & (CHACHA_BLOCK_SIZE - 1); ++ ++ addr += l; ++ length -= l; ++ } ++ ++ if (likely(length >= CHACHA_BLOCK_SIZE || length == sl)) { ++ size_t l = length; ++ ++ if (unlikely(length < sl)) ++ l &= ~(CHACHA_BLOCK_SIZE - 1); ++ chacha_crypt(chacha_state, addr, addr, l, 20); ++ addr += l; ++ length -= l; ++ } ++ ++ if (unlikely(length > 0)) { ++ chacha_crypt(chacha_state, b.chacha_stream, pad0, ++ CHACHA_BLOCK_SIZE, 20); ++ crypto_xor(addr, b.chacha_stream, length); ++ partial = length; ++ } ++ ++ if (encrypt) ++ poly1305_update(&poly1305_state, miter.addr, ++ min_t(size_t, sl, miter.length)); ++ } ++ ++ if (src_len & 0xf) ++ poly1305_update(&poly1305_state, pad0, 0x10 - (src_len & 0xf)); ++ ++ b.lens[0] = cpu_to_le64(ad_len); ++ b.lens[1] = cpu_to_le64(src_len); ++ poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); ++ ++ if (likely(sl <= -POLY1305_DIGEST_SIZE)) { ++ if (encrypt) { ++ poly1305_final(&poly1305_state, ++ miter.addr + miter.length + sl); ++ ret = true; ++ } else { ++ poly1305_final(&poly1305_state, b.mac[0]); ++ ret = !crypto_memneq(b.mac[0], ++ miter.addr + miter.length + sl, ++ POLY1305_DIGEST_SIZE); ++ } ++ } ++ ++ sg_miter_stop(&miter); ++ ++ if (unlikely(sl > -POLY1305_DIGEST_SIZE)) { ++ poly1305_final(&poly1305_state, b.mac[1]); ++ scatterwalk_map_and_copy(b.mac[encrypt], src, src_len, ++ sizeof(b.mac[1]), encrypt); ++ ret = encrypt || ++ !crypto_memneq(b.mac[0], b.mac[1], POLY1305_DIGEST_SIZE); ++ } ++ ++ memzero_explicit(chacha_state, sizeof(chacha_state)); ++ memzero_explicit(&b, sizeof(b)); ++ ++ return ret; ++} ++ ++bool chacha20poly1305_encrypt_sg_inplace(struct scatterlist *src, size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ return chacha20poly1305_crypt_sg_inplace(src, src_len, ad, ad_len, ++ nonce, key, 1); ++} ++EXPORT_SYMBOL(chacha20poly1305_encrypt_sg_inplace); ++ ++bool chacha20poly1305_decrypt_sg_inplace(struct scatterlist *src, size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ if (unlikely(src_len < POLY1305_DIGEST_SIZE)) ++ return false; ++ ++ return chacha20poly1305_crypt_sg_inplace(src, ++ src_len - POLY1305_DIGEST_SIZE, ++ ad, ad_len, nonce, key, 0); ++} ++EXPORT_SYMBOL(chacha20poly1305_decrypt_sg_inplace); ++ + static int __init mod_init(void) + { + if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && diff --git a/ipq806x/backport-5.4/080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch b/ipq806x/backport-5.4/080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch new file mode 100644 index 0000000..709b1fb --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0034-crypto-chacha_generic-remove-unnecessary-setkey-func.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 17 Nov 2019 23:21:29 -0800 +Subject: [PATCH] crypto: chacha_generic - remove unnecessary setkey() + functions + +commit 2043323a799a660bc84bbee404cf7a2617ec6157 upstream. + +Use chacha20_setkey() and chacha12_setkey() from + instead of defining them again in +chacha_generic.c. + +Signed-off-by: Eric Biggers +Acked-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/chacha_generic.c | 18 +++--------------- + 1 file changed, 3 insertions(+), 15 deletions(-) + +--- a/crypto/chacha_generic.c ++++ b/crypto/chacha_generic.c +@@ -37,18 +37,6 @@ static int chacha_stream_xor(struct skci + return err; + } + +-static int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize) +-{ +- return chacha_setkey(tfm, key, keysize, 20); +-} +- +-static int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, +- unsigned int keysize) +-{ +- return chacha_setkey(tfm, key, keysize, 12); +-} +- + static int crypto_chacha_crypt(struct skcipher_request *req) + { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +@@ -91,7 +79,7 @@ static struct skcipher_alg algs[] = { + .max_keysize = CHACHA_KEY_SIZE, + .ivsize = CHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, ++ .setkey = chacha20_setkey, + .encrypt = crypto_chacha_crypt, + .decrypt = crypto_chacha_crypt, + }, { +@@ -106,7 +94,7 @@ static struct skcipher_alg algs[] = { + .max_keysize = CHACHA_KEY_SIZE, + .ivsize = XCHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha20_setkey, ++ .setkey = chacha20_setkey, + .encrypt = crypto_xchacha_crypt, + .decrypt = crypto_xchacha_crypt, + }, { +@@ -121,7 +109,7 @@ static struct skcipher_alg algs[] = { + .max_keysize = CHACHA_KEY_SIZE, + .ivsize = XCHACHA_IV_SIZE, + .chunksize = CHACHA_BLOCK_SIZE, +- .setkey = crypto_chacha12_setkey, ++ .setkey = chacha12_setkey, + .encrypt = crypto_xchacha_crypt, + .decrypt = crypto_xchacha_crypt, + } diff --git a/ipq806x/backport-5.4/080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch b/ipq806x/backport-5.4/080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch new file mode 100644 index 0000000..4554ea8 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0035-crypto-x86-chacha-only-unregister-algorithms-if-regi.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 17 Nov 2019 23:21:58 -0800 +Subject: [PATCH] crypto: x86/chacha - only unregister algorithms if registered + +commit b62755aed3a3f5ca9edd2718339ccea3b6bbbe57 upstream. + +It's not valid to call crypto_unregister_skciphers() without a prior +call to crypto_register_skciphers(). + +Fixes: 84e03fa39fbe ("crypto: x86/chacha - expose SIMD ChaCha routine as library function") +Signed-off-by: Eric Biggers +Acked-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/chacha_glue.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/x86/crypto/chacha_glue.c ++++ b/arch/x86/crypto/chacha_glue.c +@@ -304,7 +304,8 @@ static int __init chacha_simd_mod_init(v + + static void __exit chacha_simd_mod_fini(void) + { +- crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); ++ if (boot_cpu_has(X86_FEATURE_SSSE3)) ++ crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); + } + + module_init(chacha_simd_mod_init); diff --git a/ipq806x/backport-5.4/080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch b/ipq806x/backport-5.4/080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch new file mode 100644 index 0000000..6ad20b9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0036-crypto-lib-chacha20poly1305-use-chacha20_crypt.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Sun, 17 Nov 2019 23:22:16 -0800 +Subject: [PATCH] crypto: lib/chacha20poly1305 - use chacha20_crypt() + +commit 413808b71e6204b0cc1eeaa77960f7c3cd381d33 upstream. + +Use chacha20_crypt() instead of chacha_crypt(), since it's not really +appropriate for users of the ChaCha library API to be passing the number +of rounds as an argument. + +Signed-off-by: Eric Biggers +Acked-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + lib/crypto/chacha20poly1305.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +--- a/lib/crypto/chacha20poly1305.c ++++ b/lib/crypto/chacha20poly1305.c +@@ -66,14 +66,14 @@ __chacha20poly1305_encrypt(u8 *dst, cons + __le64 lens[2]; + } b; + +- chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20); ++ chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); + poly1305_init(&poly1305_state, b.block0); + + poly1305_update(&poly1305_state, ad, ad_len); + if (ad_len & 0xf) + poly1305_update(&poly1305_state, pad0, 0x10 - (ad_len & 0xf)); + +- chacha_crypt(chacha_state, dst, src, src_len, 20); ++ chacha20_crypt(chacha_state, dst, src, src_len); + + poly1305_update(&poly1305_state, dst, src_len); + if (src_len & 0xf) +@@ -140,7 +140,7 @@ __chacha20poly1305_decrypt(u8 *dst, cons + if (unlikely(src_len < POLY1305_DIGEST_SIZE)) + return false; + +- chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20); ++ chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); + poly1305_init(&poly1305_state, b.block0); + + poly1305_update(&poly1305_state, ad, ad_len); +@@ -160,7 +160,7 @@ __chacha20poly1305_decrypt(u8 *dst, cons + + ret = crypto_memneq(b.mac, src + dst_len, POLY1305_DIGEST_SIZE); + if (likely(!ret)) +- chacha_crypt(chacha_state, dst, src, dst_len, 20); ++ chacha20_crypt(chacha_state, dst, src, dst_len); + + memzero_explicit(&b, sizeof(b)); + +@@ -241,7 +241,7 @@ bool chacha20poly1305_crypt_sg_inplace(s + b.iv[1] = cpu_to_le64(nonce); + + chacha_init(chacha_state, b.k, (u8 *)b.iv); +- chacha_crypt(chacha_state, b.block0, pad0, sizeof(b.block0), 20); ++ chacha20_crypt(chacha_state, b.block0, pad0, sizeof(b.block0)); + poly1305_init(&poly1305_state, b.block0); + + if (unlikely(ad_len)) { +@@ -278,14 +278,14 @@ bool chacha20poly1305_crypt_sg_inplace(s + + if (unlikely(length < sl)) + l &= ~(CHACHA_BLOCK_SIZE - 1); +- chacha_crypt(chacha_state, addr, addr, l, 20); ++ chacha20_crypt(chacha_state, addr, addr, l); + addr += l; + length -= l; + } + + if (unlikely(length > 0)) { +- chacha_crypt(chacha_state, b.chacha_stream, pad0, +- CHACHA_BLOCK_SIZE, 20); ++ chacha20_crypt(chacha_state, b.chacha_stream, pad0, ++ CHACHA_BLOCK_SIZE); + crypto_xor(addr, b.chacha_stream, length); + partial = length; + } diff --git a/ipq806x/backport-5.4/080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch b/ipq806x/backport-5.4/080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch new file mode 100644 index 0000000..d510438 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0037-crypto-arch-conditionalize-crypto-api-in-arch-glue-f.patch @@ -0,0 +1,275 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 25 Nov 2019 11:31:12 +0100 +Subject: [PATCH] crypto: arch - conditionalize crypto api in arch glue for lib + code + +commit 8394bfec51e0e565556101bcc4e2fe7551104cd8 upstream. + +For glue code that's used by Zinc, the actual Crypto API functions might +not necessarily exist, and don't need to exist either. Before this +patch, there are valid build configurations that lead to a unbuildable +kernel. This fixes it to conditionalize those symbols on the existence +of the proper config entry. + +Signed-off-by: Jason A. Donenfeld +Acked-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/chacha-glue.c | 26 ++++++++++++++++---------- + arch/arm/crypto/curve25519-glue.c | 5 +++-- + arch/arm/crypto/poly1305-glue.c | 9 ++++++--- + arch/arm64/crypto/chacha-neon-glue.c | 5 +++-- + arch/arm64/crypto/poly1305-glue.c | 5 +++-- + arch/mips/crypto/chacha-glue.c | 6 ++++-- + arch/mips/crypto/poly1305-glue.c | 6 ++++-- + arch/x86/crypto/blake2s-glue.c | 6 ++++-- + arch/x86/crypto/chacha_glue.c | 5 +++-- + arch/x86/crypto/curve25519-x86_64.c | 7 ++++--- + arch/x86/crypto/poly1305_glue.c | 5 +++-- + 11 files changed, 53 insertions(+), 32 deletions(-) + +--- a/arch/arm/crypto/chacha-glue.c ++++ b/arch/arm/crypto/chacha-glue.c +@@ -286,11 +286,13 @@ static struct skcipher_alg neon_algs[] = + + static int __init chacha_simd_mod_init(void) + { +- int err; ++ int err = 0; + +- err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); +- if (err) +- return err; ++ if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER)) { ++ err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); ++ if (err) ++ return err; ++ } + + if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) { + int i; +@@ -310,18 +312,22 @@ static int __init chacha_simd_mod_init(v + static_branch_enable(&use_neon); + } + +- err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs)); +- if (err) +- crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); ++ if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER)) { ++ err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs)); ++ if (err) ++ crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); ++ } + } + return err; + } + + static void __exit chacha_simd_mod_fini(void) + { +- crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); +- if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) +- crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs)); ++ if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER)) { ++ crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs)); ++ if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) ++ crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs)); ++ } + } + + module_init(chacha_simd_mod_init); +--- a/arch/arm/crypto/curve25519-glue.c ++++ b/arch/arm/crypto/curve25519-glue.c +@@ -108,14 +108,15 @@ static int __init mod_init(void) + { + if (elf_hwcap & HWCAP_NEON) { + static_branch_enable(&have_neon); +- return crypto_register_kpp(&curve25519_alg); ++ return IS_REACHABLE(CONFIG_CRYPTO_KPP) ? ++ crypto_register_kpp(&curve25519_alg) : 0; + } + return 0; + } + + static void __exit mod_exit(void) + { +- if (elf_hwcap & HWCAP_NEON) ++ if (IS_REACHABLE(CONFIG_CRYPTO_KPP) && elf_hwcap & HWCAP_NEON) + crypto_unregister_kpp(&curve25519_alg); + } + +--- a/arch/arm/crypto/poly1305-glue.c ++++ b/arch/arm/crypto/poly1305-glue.c +@@ -249,16 +249,19 @@ static int __init arm_poly1305_mod_init( + if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && + (elf_hwcap & HWCAP_NEON)) + static_branch_enable(&have_neon); +- else ++ else if (IS_REACHABLE(CONFIG_CRYPTO_HASH)) + /* register only the first entry */ + return crypto_register_shash(&arm_poly1305_algs[0]); + +- return crypto_register_shashes(arm_poly1305_algs, +- ARRAY_SIZE(arm_poly1305_algs)); ++ return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? ++ crypto_register_shashes(arm_poly1305_algs, ++ ARRAY_SIZE(arm_poly1305_algs)) : 0; + } + + static void __exit arm_poly1305_mod_exit(void) + { ++ if (!IS_REACHABLE(CONFIG_CRYPTO_HASH)) ++ return; + if (!static_branch_likely(&have_neon)) { + crypto_unregister_shash(&arm_poly1305_algs[0]); + return; +--- a/arch/arm64/crypto/chacha-neon-glue.c ++++ b/arch/arm64/crypto/chacha-neon-glue.c +@@ -211,12 +211,13 @@ static int __init chacha_simd_mod_init(v + + static_branch_enable(&have_neon); + +- return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); ++ return IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) ? ++ crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0; + } + + static void __exit chacha_simd_mod_fini(void) + { +- if (cpu_have_named_feature(ASIMD)) ++ if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) && cpu_have_named_feature(ASIMD)) + crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); + } + +--- a/arch/arm64/crypto/poly1305-glue.c ++++ b/arch/arm64/crypto/poly1305-glue.c +@@ -220,12 +220,13 @@ static int __init neon_poly1305_mod_init + + static_branch_enable(&have_neon); + +- return crypto_register_shash(&neon_poly1305_alg); ++ return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? ++ crypto_register_shash(&neon_poly1305_alg) : 0; + } + + static void __exit neon_poly1305_mod_exit(void) + { +- if (cpu_have_named_feature(ASIMD)) ++ if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && cpu_have_named_feature(ASIMD)) + crypto_unregister_shash(&neon_poly1305_alg); + } + +--- a/arch/mips/crypto/chacha-glue.c ++++ b/arch/mips/crypto/chacha-glue.c +@@ -128,12 +128,14 @@ static struct skcipher_alg algs[] = { + + static int __init chacha_simd_mod_init(void) + { +- return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); ++ return IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) ? ++ crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0; + } + + static void __exit chacha_simd_mod_fini(void) + { +- crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); ++ if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER)) ++ crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); + } + + module_init(chacha_simd_mod_init); +--- a/arch/mips/crypto/poly1305-glue.c ++++ b/arch/mips/crypto/poly1305-glue.c +@@ -187,12 +187,14 @@ static struct shash_alg mips_poly1305_al + + static int __init mips_poly1305_mod_init(void) + { +- return crypto_register_shash(&mips_poly1305_alg); ++ return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? ++ crypto_register_shash(&mips_poly1305_alg) : 0; + } + + static void __exit mips_poly1305_mod_exit(void) + { +- crypto_unregister_shash(&mips_poly1305_alg); ++ if (IS_REACHABLE(CONFIG_CRYPTO_HASH)) ++ crypto_unregister_shash(&mips_poly1305_alg); + } + + module_init(mips_poly1305_mod_init); +--- a/arch/x86/crypto/blake2s-glue.c ++++ b/arch/x86/crypto/blake2s-glue.c +@@ -210,12 +210,14 @@ static int __init blake2s_mod_init(void) + XFEATURE_MASK_AVX512, NULL)) + static_branch_enable(&blake2s_use_avx512); + +- return crypto_register_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); ++ return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? ++ crypto_register_shashes(blake2s_algs, ++ ARRAY_SIZE(blake2s_algs)) : 0; + } + + static void __exit blake2s_mod_exit(void) + { +- if (boot_cpu_has(X86_FEATURE_SSSE3)) ++ if (IS_REACHABLE(CONFIG_CRYPTO_HASH) && boot_cpu_has(X86_FEATURE_SSSE3)) + crypto_unregister_shashes(blake2s_algs, ARRAY_SIZE(blake2s_algs)); + } + +--- a/arch/x86/crypto/chacha_glue.c ++++ b/arch/x86/crypto/chacha_glue.c +@@ -299,12 +299,13 @@ static int __init chacha_simd_mod_init(v + boot_cpu_has(X86_FEATURE_AVX512BW)) /* kmovq */ + static_branch_enable(&chacha_use_avx512vl); + } +- return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); ++ return IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) ? ++ crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0; + } + + static void __exit chacha_simd_mod_fini(void) + { +- if (boot_cpu_has(X86_FEATURE_SSSE3)) ++ if (IS_REACHABLE(CONFIG_CRYPTO_BLKCIPHER) && boot_cpu_has(X86_FEATURE_SSSE3)) + crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); + } + +--- a/arch/x86/crypto/curve25519-x86_64.c ++++ b/arch/x86/crypto/curve25519-x86_64.c +@@ -2457,13 +2457,14 @@ static int __init curve25519_mod_init(vo + static_branch_enable(&curve25519_use_adx); + else + return 0; +- return crypto_register_kpp(&curve25519_alg); ++ return IS_REACHABLE(CONFIG_CRYPTO_KPP) ? ++ crypto_register_kpp(&curve25519_alg) : 0; + } + + static void __exit curve25519_mod_exit(void) + { +- if (boot_cpu_has(X86_FEATURE_BMI2) || +- boot_cpu_has(X86_FEATURE_ADX)) ++ if (IS_REACHABLE(CONFIG_CRYPTO_KPP) && ++ (boot_cpu_has(X86_FEATURE_BMI2) || boot_cpu_has(X86_FEATURE_ADX))) + crypto_unregister_kpp(&curve25519_alg); + } + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -224,12 +224,13 @@ static int __init poly1305_simd_mod_init + cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) + static_branch_enable(&poly1305_use_avx2); + +- return crypto_register_shash(&alg); ++ return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? crypto_register_shash(&alg) : 0; + } + + static void __exit poly1305_simd_mod_exit(void) + { +- crypto_unregister_shash(&alg); ++ if (IS_REACHABLE(CONFIG_CRYPTO_HASH)) ++ crypto_unregister_shash(&alg); + } + + module_init(poly1305_simd_mod_init); diff --git a/ipq806x/backport-5.4/080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch b/ipq806x/backport-5.4/080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch new file mode 100644 index 0000000..ccd03e3 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0038-crypto-chacha-fix-warning-message-in-header-file.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Valdis=20Kl=C4=93tnieks?= +Date: Thu, 5 Dec 2019 20:58:36 -0500 +Subject: [PATCH] crypto: chacha - fix warning message in header file + +commit 579d705cd64e44f3fcda1a6cfd5f37468a5ddf63 upstream. + +Building with W=1 causes a warning: + + CC [M] arch/x86/crypto/chacha_glue.o +In file included from arch/x86/crypto/chacha_glue.c:10: +./include/crypto/internal/chacha.h:37:1: warning: 'inline' is not at beginning of declaration [-Wold-style-declaration] + 37 | static int inline chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, + | ^~~~~~ + +Straighten out the order to match the rest of the header file. + +Signed-off-by: Valdis Kletnieks +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + include/crypto/internal/chacha.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/crypto/internal/chacha.h ++++ b/include/crypto/internal/chacha.h +@@ -34,7 +34,7 @@ static inline int chacha20_setkey(struct + return chacha_setkey(tfm, key, keysize, 20); + } + +-static int inline chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, ++static inline int chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key, + unsigned int keysize) + { + return chacha_setkey(tfm, key, keysize, 12); diff --git a/ipq806x/backport-5.4/080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch b/ipq806x/backport-5.4/080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch new file mode 100644 index 0000000..67de22d --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0039-crypto-arm-curve25519-add-arch-specific-key-generati.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 11 Dec 2019 10:26:39 +0100 +Subject: [PATCH] crypto: arm/curve25519 - add arch-specific key generation + function + +commit 84faa307249b341f6ad8de3e1869d77a65e26669 upstream. + +Somehow this was forgotten when Zinc was being split into oddly shaped +pieces, resulting in linker errors. The x86_64 glue has a specific key +generation implementation, but the Arm one does not. However, it can +still receive the NEON speedups by calling the ordinary DH function +using the base point. + +Signed-off-by: Jason A. Donenfeld +Acked-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/curve25519-glue.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/arch/arm/crypto/curve25519-glue.c ++++ b/arch/arm/crypto/curve25519-glue.c +@@ -38,6 +38,13 @@ void curve25519_arch(u8 out[CURVE25519_K + } + EXPORT_SYMBOL(curve25519_arch); + ++void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], ++ const u8 secret[CURVE25519_KEY_SIZE]) ++{ ++ return curve25519_arch(pub, secret, curve25519_base_point); ++} ++EXPORT_SYMBOL(curve25519_base_arch); ++ + static int curve25519_set_secret(struct crypto_kpp *tfm, const void *buf, + unsigned int len) + { diff --git a/ipq806x/backport-5.4/080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch b/ipq806x/backport-5.4/080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch new file mode 100644 index 0000000..e43d196 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0040-crypto-lib-curve25519-re-add-selftests.patch @@ -0,0 +1,1387 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 16 Dec 2019 19:53:26 +0100 +Subject: [PATCH] crypto: lib/curve25519 - re-add selftests + +commit aa127963f1cab2b93c74c9b128a84610203fb674 upstream. + +Somehow these were dropped when Zinc was being integrated, which is +problematic, because testing the library interface for Curve25519 is +important.. This commit simply adds them back and wires them in in the +same way that the blake2s selftests are wired in. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + lib/crypto/Makefile | 1 + + lib/crypto/curve25519-selftest.c | 1321 ++++++++++++++++++++++++++++++ + lib/crypto/curve25519.c | 17 + + 3 files changed, 1339 insertions(+) + create mode 100644 lib/crypto/curve25519-selftest.c + +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -36,4 +36,5 @@ libsha256-y := sha256.o + ifneq ($(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS),y) + libblake2s-y += blake2s-selftest.o + libchacha20poly1305-y += chacha20poly1305-selftest.o ++libcurve25519-y += curve25519-selftest.o + endif +--- /dev/null ++++ b/lib/crypto/curve25519-selftest.c +@@ -0,0 +1,1321 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include ++ ++struct curve25519_test_vector { ++ u8 private[CURVE25519_KEY_SIZE]; ++ u8 public[CURVE25519_KEY_SIZE]; ++ u8 result[CURVE25519_KEY_SIZE]; ++ bool valid; ++}; ++static const struct curve25519_test_vector curve25519_test_vectors[] __initconst = { ++ { ++ .private = { 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, ++ 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, ++ 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, ++ 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a }, ++ .public = { 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, ++ 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, ++ 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, ++ 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f }, ++ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, ++ 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, ++ 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, ++ 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 }, ++ .valid = true ++ }, ++ { ++ .private = { 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, ++ 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, ++ 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, ++ 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb }, ++ .public = { 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, ++ 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, ++ 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, ++ 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a }, ++ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, ++ 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, ++ 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, ++ 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 }, ++ .valid = true ++ }, ++ { ++ .private = { 1 }, ++ .public = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x3c, 0x77, 0x77, 0xca, 0xf9, 0x97, 0xb2, 0x64, ++ 0x41, 0x60, 0x77, 0x66, 0x5b, 0x4e, 0x22, 0x9d, ++ 0x0b, 0x95, 0x48, 0xdc, 0x0c, 0xd8, 0x19, 0x98, ++ 0xdd, 0xcd, 0xc5, 0xc8, 0x53, 0x3c, 0x79, 0x7f }, ++ .valid = true ++ }, ++ { ++ .private = { 1 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0xb3, 0x2d, 0x13, 0x62, 0xc2, 0x48, 0xd6, 0x2f, ++ 0xe6, 0x26, 0x19, 0xcf, 0xf0, 0x4d, 0xd4, 0x3d, ++ 0xb7, 0x3f, 0xfc, 0x1b, 0x63, 0x08, 0xed, 0xe3, ++ 0x0b, 0x78, 0xd8, 0x73, 0x80, 0xf1, 0xe8, 0x34 }, ++ .valid = true ++ }, ++ { ++ .private = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, ++ 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, ++ 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, ++ 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 }, ++ .public = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, ++ 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, ++ 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, ++ 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c }, ++ .result = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, ++ 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, ++ 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, ++ 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 }, ++ .valid = true ++ }, ++ { ++ .private = { 1, 2, 3, 4 }, ++ .public = { 0 }, ++ .result = { 0 }, ++ .valid = false ++ }, ++ { ++ .private = { 2, 4, 6, 8 }, ++ .public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, ++ 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, ++ 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, ++ 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8 }, ++ .result = { 0 }, ++ .valid = false ++ }, ++ { ++ .private = { 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0xfb, 0x9f }, ++ .result = { 0x77, 0x52, 0xb6, 0x18, 0xc1, 0x2d, 0x48, 0xd2, ++ 0xc6, 0x93, 0x46, 0x83, 0x81, 0x7c, 0xc6, 0x57, ++ 0xf3, 0x31, 0x03, 0x19, 0x49, 0x48, 0x20, 0x05, ++ 0x42, 0x2b, 0x4e, 0xae, 0x8d, 0x1d, 0x43, 0x23 }, ++ .valid = true ++ }, ++ { ++ .private = { 0x8e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .public = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x06 }, ++ .result = { 0x5a, 0xdf, 0xaa, 0x25, 0x86, 0x8e, 0x32, 0x3d, ++ 0xae, 0x49, 0x62, 0xc1, 0x01, 0x5c, 0xb3, 0x12, ++ 0xe1, 0xc5, 0xc7, 0x9e, 0x95, 0x3f, 0x03, 0x99, ++ 0xb0, 0xba, 0x16, 0x22, 0xf3, 0xb6, 0xf7, 0x0c }, ++ .valid = true ++ }, ++ /* wycheproof - normal case */ ++ { ++ .private = { 0x48, 0x52, 0x83, 0x4d, 0x9d, 0x6b, 0x77, 0xda, ++ 0xde, 0xab, 0xaa, 0xf2, 0xe1, 0x1d, 0xca, 0x66, ++ 0xd1, 0x9f, 0xe7, 0x49, 0x93, 0xa7, 0xbe, 0xc3, ++ 0x6c, 0x6e, 0x16, 0xa0, 0x98, 0x3f, 0xea, 0xba }, ++ .public = { 0x9c, 0x64, 0x7d, 0x9a, 0xe5, 0x89, 0xb9, 0xf5, ++ 0x8f, 0xdc, 0x3c, 0xa4, 0x94, 0x7e, 0xfb, 0xc9, ++ 0x15, 0xc4, 0xb2, 0xe0, 0x8e, 0x74, 0x4a, 0x0e, ++ 0xdf, 0x46, 0x9d, 0xac, 0x59, 0xc8, 0xf8, 0x5a }, ++ .result = { 0x87, 0xb7, 0xf2, 0x12, 0xb6, 0x27, 0xf7, 0xa5, ++ 0x4c, 0xa5, 0xe0, 0xbc, 0xda, 0xdd, 0xd5, 0x38, ++ 0x9d, 0x9d, 0xe6, 0x15, 0x6c, 0xdb, 0xcf, 0x8e, ++ 0xbe, 0x14, 0xff, 0xbc, 0xfb, 0x43, 0x65, 0x51 }, ++ .valid = true ++ }, ++ /* wycheproof - public key on twist */ ++ { ++ .private = { 0x58, 0x8c, 0x06, 0x1a, 0x50, 0x80, 0x4a, 0xc4, ++ 0x88, 0xad, 0x77, 0x4a, 0xc7, 0x16, 0xc3, 0xf5, ++ 0xba, 0x71, 0x4b, 0x27, 0x12, 0xe0, 0x48, 0x49, ++ 0x13, 0x79, 0xa5, 0x00, 0x21, 0x19, 0x98, 0xa8 }, ++ .public = { 0x63, 0xaa, 0x40, 0xc6, 0xe3, 0x83, 0x46, 0xc5, ++ 0xca, 0xf2, 0x3a, 0x6d, 0xf0, 0xa5, 0xe6, 0xc8, ++ 0x08, 0x89, 0xa0, 0x86, 0x47, 0xe5, 0x51, 0xb3, ++ 0x56, 0x34, 0x49, 0xbe, 0xfc, 0xfc, 0x97, 0x33 }, ++ .result = { 0xb1, 0xa7, 0x07, 0x51, 0x94, 0x95, 0xff, 0xff, ++ 0xb2, 0x98, 0xff, 0x94, 0x17, 0x16, 0xb0, 0x6d, ++ 0xfa, 0xb8, 0x7c, 0xf8, 0xd9, 0x11, 0x23, 0xfe, ++ 0x2b, 0xe9, 0xa2, 0x33, 0xdd, 0xa2, 0x22, 0x12 }, ++ .valid = true ++ }, ++ /* wycheproof - public key on twist */ ++ { ++ .private = { 0xb0, 0x5b, 0xfd, 0x32, 0xe5, 0x53, 0x25, 0xd9, ++ 0xfd, 0x64, 0x8c, 0xb3, 0x02, 0x84, 0x80, 0x39, ++ 0x00, 0x0b, 0x39, 0x0e, 0x44, 0xd5, 0x21, 0xe5, ++ 0x8a, 0xab, 0x3b, 0x29, 0xa6, 0x96, 0x0b, 0xa8 }, ++ .public = { 0x0f, 0x83, 0xc3, 0x6f, 0xde, 0xd9, 0xd3, 0x2f, ++ 0xad, 0xf4, 0xef, 0xa3, 0xae, 0x93, 0xa9, 0x0b, ++ 0xb5, 0xcf, 0xa6, 0x68, 0x93, 0xbc, 0x41, 0x2c, ++ 0x43, 0xfa, 0x72, 0x87, 0xdb, 0xb9, 0x97, 0x79 }, ++ .result = { 0x67, 0xdd, 0x4a, 0x6e, 0x16, 0x55, 0x33, 0x53, ++ 0x4c, 0x0e, 0x3f, 0x17, 0x2e, 0x4a, 0xb8, 0x57, ++ 0x6b, 0xca, 0x92, 0x3a, 0x5f, 0x07, 0xb2, 0xc0, ++ 0x69, 0xb4, 0xc3, 0x10, 0xff, 0x2e, 0x93, 0x5b }, ++ .valid = true ++ }, ++ /* wycheproof - public key on twist */ ++ { ++ .private = { 0x70, 0xe3, 0x4b, 0xcb, 0xe1, 0xf4, 0x7f, 0xbc, ++ 0x0f, 0xdd, 0xfd, 0x7c, 0x1e, 0x1a, 0xa5, 0x3d, ++ 0x57, 0xbf, 0xe0, 0xf6, 0x6d, 0x24, 0x30, 0x67, ++ 0xb4, 0x24, 0xbb, 0x62, 0x10, 0xbe, 0xd1, 0x9c }, ++ .public = { 0x0b, 0x82, 0x11, 0xa2, 0xb6, 0x04, 0x90, 0x97, ++ 0xf6, 0x87, 0x1c, 0x6c, 0x05, 0x2d, 0x3c, 0x5f, ++ 0xc1, 0xba, 0x17, 0xda, 0x9e, 0x32, 0xae, 0x45, ++ 0x84, 0x03, 0xb0, 0x5b, 0xb2, 0x83, 0x09, 0x2a }, ++ .result = { 0x4a, 0x06, 0x38, 0xcf, 0xaa, 0x9e, 0xf1, 0x93, ++ 0x3b, 0x47, 0xf8, 0x93, 0x92, 0x96, 0xa6, 0xb2, ++ 0x5b, 0xe5, 0x41, 0xef, 0x7f, 0x70, 0xe8, 0x44, ++ 0xc0, 0xbc, 0xc0, 0x0b, 0x13, 0x4d, 0xe6, 0x4a }, ++ .valid = true ++ }, ++ /* wycheproof - public key on twist */ ++ { ++ .private = { 0x68, 0xc1, 0xf3, 0xa6, 0x53, 0xa4, 0xcd, 0xb1, ++ 0xd3, 0x7b, 0xba, 0x94, 0x73, 0x8f, 0x8b, 0x95, ++ 0x7a, 0x57, 0xbe, 0xb2, 0x4d, 0x64, 0x6e, 0x99, ++ 0x4d, 0xc2, 0x9a, 0x27, 0x6a, 0xad, 0x45, 0x8d }, ++ .public = { 0x34, 0x3a, 0xc2, 0x0a, 0x3b, 0x9c, 0x6a, 0x27, ++ 0xb1, 0x00, 0x81, 0x76, 0x50, 0x9a, 0xd3, 0x07, ++ 0x35, 0x85, 0x6e, 0xc1, 0xc8, 0xd8, 0xfc, 0xae, ++ 0x13, 0x91, 0x2d, 0x08, 0xd1, 0x52, 0xf4, 0x6c }, ++ .result = { 0x39, 0x94, 0x91, 0xfc, 0xe8, 0xdf, 0xab, 0x73, ++ 0xb4, 0xf9, 0xf6, 0x11, 0xde, 0x8e, 0xa0, 0xb2, ++ 0x7b, 0x28, 0xf8, 0x59, 0x94, 0x25, 0x0b, 0x0f, ++ 0x47, 0x5d, 0x58, 0x5d, 0x04, 0x2a, 0xc2, 0x07 }, ++ .valid = true ++ }, ++ /* wycheproof - public key on twist */ ++ { ++ .private = { 0xd8, 0x77, 0xb2, 0x6d, 0x06, 0xdf, 0xf9, 0xd9, ++ 0xf7, 0xfd, 0x4c, 0x5b, 0x37, 0x69, 0xf8, 0xcd, ++ 0xd5, 0xb3, 0x05, 0x16, 0xa5, 0xab, 0x80, 0x6b, ++ 0xe3, 0x24, 0xff, 0x3e, 0xb6, 0x9e, 0xa0, 0xb2 }, ++ .public = { 0xfa, 0x69, 0x5f, 0xc7, 0xbe, 0x8d, 0x1b, 0xe5, ++ 0xbf, 0x70, 0x48, 0x98, 0xf3, 0x88, 0xc4, 0x52, ++ 0xba, 0xfd, 0xd3, 0xb8, 0xea, 0xe8, 0x05, 0xf8, ++ 0x68, 0x1a, 0x8d, 0x15, 0xc2, 0xd4, 0xe1, 0x42 }, ++ .result = { 0x2c, 0x4f, 0xe1, 0x1d, 0x49, 0x0a, 0x53, 0x86, ++ 0x17, 0x76, 0xb1, 0x3b, 0x43, 0x54, 0xab, 0xd4, ++ 0xcf, 0x5a, 0x97, 0x69, 0x9d, 0xb6, 0xe6, 0xc6, ++ 0x8c, 0x16, 0x26, 0xd0, 0x76, 0x62, 0xf7, 0x58 }, ++ .valid = true ++ }, ++ /* wycheproof - public key = 0 */ ++ { ++ .private = { 0x20, 0x74, 0x94, 0x03, 0x8f, 0x2b, 0xb8, 0x11, ++ 0xd4, 0x78, 0x05, 0xbc, 0xdf, 0x04, 0xa2, 0xac, ++ 0x58, 0x5a, 0xda, 0x7f, 0x2f, 0x23, 0x38, 0x9b, ++ 0xfd, 0x46, 0x58, 0xf9, 0xdd, 0xd4, 0xde, 0xbc }, ++ .public = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key = 1 */ ++ { ++ .private = { 0x20, 0x2e, 0x89, 0x72, 0xb6, 0x1c, 0x7e, 0x61, ++ 0x93, 0x0e, 0xb9, 0x45, 0x0b, 0x50, 0x70, 0xea, ++ 0xe1, 0xc6, 0x70, 0x47, 0x56, 0x85, 0x54, 0x1f, ++ 0x04, 0x76, 0x21, 0x7e, 0x48, 0x18, 0xcf, 0xab }, ++ .public = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - edge case on twist */ ++ { ++ .private = { 0x38, 0xdd, 0xe9, 0xf3, 0xe7, 0xb7, 0x99, 0x04, ++ 0x5f, 0x9a, 0xc3, 0x79, 0x3d, 0x4a, 0x92, 0x77, ++ 0xda, 0xde, 0xad, 0xc4, 0x1b, 0xec, 0x02, 0x90, ++ 0xf8, 0x1f, 0x74, 0x4f, 0x73, 0x77, 0x5f, 0x84 }, ++ .public = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x9a, 0x2c, 0xfe, 0x84, 0xff, 0x9c, 0x4a, 0x97, ++ 0x39, 0x62, 0x5c, 0xae, 0x4a, 0x3b, 0x82, 0xa9, ++ 0x06, 0x87, 0x7a, 0x44, 0x19, 0x46, 0xf8, 0xd7, ++ 0xb3, 0xd7, 0x95, 0xfe, 0x8f, 0x5d, 0x16, 0x39 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case on twist */ ++ { ++ .private = { 0x98, 0x57, 0xa9, 0x14, 0xe3, 0xc2, 0x90, 0x36, ++ 0xfd, 0x9a, 0x44, 0x2b, 0xa5, 0x26, 0xb5, 0xcd, ++ 0xcd, 0xf2, 0x82, 0x16, 0x15, 0x3e, 0x63, 0x6c, ++ 0x10, 0x67, 0x7a, 0xca, 0xb6, 0xbd, 0x6a, 0xa5 }, ++ .public = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x4d, 0xa4, 0xe0, 0xaa, 0x07, 0x2c, 0x23, 0x2e, ++ 0xe2, 0xf0, 0xfa, 0x4e, 0x51, 0x9a, 0xe5, 0x0b, ++ 0x52, 0xc1, 0xed, 0xd0, 0x8a, 0x53, 0x4d, 0x4e, ++ 0xf3, 0x46, 0xc2, 0xe1, 0x06, 0xd2, 0x1d, 0x60 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case on twist */ ++ { ++ .private = { 0x48, 0xe2, 0x13, 0x0d, 0x72, 0x33, 0x05, 0xed, ++ 0x05, 0xe6, 0xe5, 0x89, 0x4d, 0x39, 0x8a, 0x5e, ++ 0x33, 0x36, 0x7a, 0x8c, 0x6a, 0xac, 0x8f, 0xcd, ++ 0xf0, 0xa8, 0x8e, 0x4b, 0x42, 0x82, 0x0d, 0xb7 }, ++ .public = { 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0xf8, 0xff, ++ 0xff, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00, ++ 0x00, 0xf0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00 }, ++ .result = { 0x9e, 0xd1, 0x0c, 0x53, 0x74, 0x7f, 0x64, 0x7f, ++ 0x82, 0xf4, 0x51, 0x25, 0xd3, 0xde, 0x15, 0xa1, ++ 0xe6, 0xb8, 0x24, 0x49, 0x6a, 0xb4, 0x04, 0x10, ++ 0xff, 0xcc, 0x3c, 0xfe, 0x95, 0x76, 0x0f, 0x3b }, ++ .valid = true ++ }, ++ /* wycheproof - edge case on twist */ ++ { ++ .private = { 0x28, 0xf4, 0x10, 0x11, 0x69, 0x18, 0x51, 0xb3, ++ 0xa6, 0x2b, 0x64, 0x15, 0x53, 0xb3, 0x0d, 0x0d, ++ 0xfd, 0xdc, 0xb8, 0xff, 0xfc, 0xf5, 0x37, 0x00, ++ 0xa7, 0xbe, 0x2f, 0x6a, 0x87, 0x2e, 0x9f, 0xb0 }, ++ .public = { 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x07, 0x00, ++ 0x00, 0xe0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8, 0xff, ++ 0xff, 0x0f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x7f }, ++ .result = { 0xcf, 0x72, 0xb4, 0xaa, 0x6a, 0xa1, 0xc9, 0xf8, ++ 0x94, 0xf4, 0x16, 0x5b, 0x86, 0x10, 0x9a, 0xa4, ++ 0x68, 0x51, 0x76, 0x48, 0xe1, 0xf0, 0xcc, 0x70, ++ 0xe1, 0xab, 0x08, 0x46, 0x01, 0x76, 0x50, 0x6b }, ++ .valid = true ++ }, ++ /* wycheproof - edge case on twist */ ++ { ++ .private = { 0x18, 0xa9, 0x3b, 0x64, 0x99, 0xb9, 0xf6, 0xb3, ++ 0x22, 0x5c, 0xa0, 0x2f, 0xef, 0x41, 0x0e, 0x0a, ++ 0xde, 0xc2, 0x35, 0x32, 0x32, 0x1d, 0x2d, 0x8e, ++ 0xf1, 0xa6, 0xd6, 0x02, 0xa8, 0xc6, 0x5b, 0x83 }, ++ .public = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x5d, 0x50, 0xb6, 0x28, 0x36, 0xbb, 0x69, 0x57, ++ 0x94, 0x10, 0x38, 0x6c, 0xf7, 0xbb, 0x81, 0x1c, ++ 0x14, 0xbf, 0x85, 0xb1, 0xc7, 0xb1, 0x7e, 0x59, ++ 0x24, 0xc7, 0xff, 0xea, 0x91, 0xef, 0x9e, 0x12 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case on twist */ ++ { ++ .private = { 0xc0, 0x1d, 0x13, 0x05, 0xa1, 0x33, 0x8a, 0x1f, ++ 0xca, 0xc2, 0xba, 0x7e, 0x2e, 0x03, 0x2b, 0x42, ++ 0x7e, 0x0b, 0x04, 0x90, 0x31, 0x65, 0xac, 0xa9, ++ 0x57, 0xd8, 0xd0, 0x55, 0x3d, 0x87, 0x17, 0xb0 }, ++ .public = { 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x19, 0x23, 0x0e, 0xb1, 0x48, 0xd5, 0xd6, 0x7c, ++ 0x3c, 0x22, 0xab, 0x1d, 0xae, 0xff, 0x80, 0xa5, ++ 0x7e, 0xae, 0x42, 0x65, 0xce, 0x28, 0x72, 0x65, ++ 0x7b, 0x2c, 0x80, 0x99, 0xfc, 0x69, 0x8e, 0x50 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for public key */ ++ { ++ .private = { 0x38, 0x6f, 0x7f, 0x16, 0xc5, 0x07, 0x31, 0xd6, ++ 0x4f, 0x82, 0xe6, 0xa1, 0x70, 0xb1, 0x42, 0xa4, ++ 0xe3, 0x4f, 0x31, 0xfd, 0x77, 0x68, 0xfc, 0xb8, ++ 0x90, 0x29, 0x25, 0xe7, 0xd1, 0xe2, 0x1a, 0xbe }, ++ .public = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x0f, 0xca, 0xb5, 0xd8, 0x42, 0xa0, 0x78, 0xd7, ++ 0xa7, 0x1f, 0xc5, 0x9b, 0x57, 0xbf, 0xb4, 0xca, ++ 0x0b, 0xe6, 0x87, 0x3b, 0x49, 0xdc, 0xdb, 0x9f, ++ 0x44, 0xe1, 0x4a, 0xe8, 0xfb, 0xdf, 0xa5, 0x42 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for public key */ ++ { ++ .private = { 0xe0, 0x23, 0xa2, 0x89, 0xbd, 0x5e, 0x90, 0xfa, ++ 0x28, 0x04, 0xdd, 0xc0, 0x19, 0xa0, 0x5e, 0xf3, ++ 0xe7, 0x9d, 0x43, 0x4b, 0xb6, 0xea, 0x2f, 0x52, ++ 0x2e, 0xcb, 0x64, 0x3a, 0x75, 0x29, 0x6e, 0x95 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x54, 0xce, 0x8f, 0x22, 0x75, 0xc0, 0x77, 0xe3, ++ 0xb1, 0x30, 0x6a, 0x39, 0x39, 0xc5, 0xe0, 0x3e, ++ 0xef, 0x6b, 0xbb, 0x88, 0x06, 0x05, 0x44, 0x75, ++ 0x8d, 0x9f, 0xef, 0x59, 0xb0, 0xbc, 0x3e, 0x4f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for public key */ ++ { ++ .private = { 0x68, 0xf0, 0x10, 0xd6, 0x2e, 0xe8, 0xd9, 0x26, ++ 0x05, 0x3a, 0x36, 0x1c, 0x3a, 0x75, 0xc6, 0xea, ++ 0x4e, 0xbd, 0xc8, 0x60, 0x6a, 0xb2, 0x85, 0x00, ++ 0x3a, 0x6f, 0x8f, 0x40, 0x76, 0xb0, 0x1e, 0x83 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 }, ++ .result = { 0xf1, 0x36, 0x77, 0x5c, 0x5b, 0xeb, 0x0a, 0xf8, ++ 0x11, 0x0a, 0xf1, 0x0b, 0x20, 0x37, 0x23, 0x32, ++ 0x04, 0x3c, 0xab, 0x75, 0x24, 0x19, 0x67, 0x87, ++ 0x75, 0xa2, 0x23, 0xdf, 0x57, 0xc9, 0xd3, 0x0d }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for public key */ ++ { ++ .private = { 0x58, 0xeb, 0xcb, 0x35, 0xb0, 0xf8, 0x84, 0x5c, ++ 0xaf, 0x1e, 0xc6, 0x30, 0xf9, 0x65, 0x76, 0xb6, ++ 0x2c, 0x4b, 0x7b, 0x6c, 0x36, 0xb2, 0x9d, 0xeb, ++ 0x2c, 0xb0, 0x08, 0x46, 0x51, 0x75, 0x5c, 0x96 }, ++ .public = { 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xfb, 0xff, ++ 0xff, 0xdf, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, ++ 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xf7, 0xff, ++ 0xff, 0xf7, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x3f }, ++ .result = { 0xbf, 0x9a, 0xff, 0xd0, 0x6b, 0x84, 0x40, 0x85, ++ 0x58, 0x64, 0x60, 0x96, 0x2e, 0xf2, 0x14, 0x6f, ++ 0xf3, 0xd4, 0x53, 0x3d, 0x94, 0x44, 0xaa, 0xb0, ++ 0x06, 0xeb, 0x88, 0xcc, 0x30, 0x54, 0x40, 0x7d }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for public key */ ++ { ++ .private = { 0x18, 0x8c, 0x4b, 0xc5, 0xb9, 0xc4, 0x4b, 0x38, ++ 0xbb, 0x65, 0x8b, 0x9b, 0x2a, 0xe8, 0x2d, 0x5b, ++ 0x01, 0x01, 0x5e, 0x09, 0x31, 0x84, 0xb1, 0x7c, ++ 0xb7, 0x86, 0x35, 0x03, 0xa7, 0x83, 0xe1, 0xbb }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .result = { 0xd4, 0x80, 0xde, 0x04, 0xf6, 0x99, 0xcb, 0x3b, ++ 0xe0, 0x68, 0x4a, 0x9c, 0xc2, 0xe3, 0x12, 0x81, ++ 0xea, 0x0b, 0xc5, 0xa9, 0xdc, 0xc1, 0x57, 0xd3, ++ 0xd2, 0x01, 0x58, 0xd4, 0x6c, 0xa5, 0x24, 0x6d }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for public key */ ++ { ++ .private = { 0xe0, 0x6c, 0x11, 0xbb, 0x2e, 0x13, 0xce, 0x3d, ++ 0xc7, 0x67, 0x3f, 0x67, 0xf5, 0x48, 0x22, 0x42, ++ 0x90, 0x94, 0x23, 0xa9, 0xae, 0x95, 0xee, 0x98, ++ 0x6a, 0x98, 0x8d, 0x98, 0xfa, 0xee, 0x23, 0xa2 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f }, ++ .result = { 0x4c, 0x44, 0x01, 0xcc, 0xe6, 0xb5, 0x1e, 0x4c, ++ 0xb1, 0x8f, 0x27, 0x90, 0x24, 0x6c, 0x9b, 0xf9, ++ 0x14, 0xdb, 0x66, 0x77, 0x50, 0xa1, 0xcb, 0x89, ++ 0x06, 0x90, 0x92, 0xaf, 0x07, 0x29, 0x22, 0x76 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for public key */ ++ { ++ .private = { 0xc0, 0x65, 0x8c, 0x46, 0xdd, 0xe1, 0x81, 0x29, ++ 0x29, 0x38, 0x77, 0x53, 0x5b, 0x11, 0x62, 0xb6, ++ 0xf9, 0xf5, 0x41, 0x4a, 0x23, 0xcf, 0x4d, 0x2c, ++ 0xbc, 0x14, 0x0a, 0x4d, 0x99, 0xda, 0x2b, 0x8f }, ++ .public = { 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x57, 0x8b, 0xa8, 0xcc, 0x2d, 0xbd, 0xc5, 0x75, ++ 0xaf, 0xcf, 0x9d, 0xf2, 0xb3, 0xee, 0x61, 0x89, ++ 0xf5, 0x33, 0x7d, 0x68, 0x54, 0xc7, 0x9b, 0x4c, ++ 0xe1, 0x65, 0xea, 0x12, 0x29, 0x3b, 0x3a, 0x0f }, ++ .valid = true ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x10, 0x25, 0x5c, 0x92, 0x30, 0xa9, 0x7a, 0x30, ++ 0xa4, 0x58, 0xca, 0x28, 0x4a, 0x62, 0x96, 0x69, ++ 0x29, 0x3a, 0x31, 0x89, 0x0c, 0xda, 0x9d, 0x14, ++ 0x7f, 0xeb, 0xc7, 0xd1, 0xe2, 0x2d, 0x6b, 0xb1 }, ++ .public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, ++ 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, ++ 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, ++ 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x78, 0xf1, 0xe8, 0xed, 0xf1, 0x44, 0x81, 0xb3, ++ 0x89, 0x44, 0x8d, 0xac, 0x8f, 0x59, 0xc7, 0x0b, ++ 0x03, 0x8e, 0x7c, 0xf9, 0x2e, 0xf2, 0xc7, 0xef, ++ 0xf5, 0x7a, 0x72, 0x46, 0x6e, 0x11, 0x52, 0x96 }, ++ .public = { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, ++ 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, ++ 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, ++ 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0xa0, 0xa0, 0x5a, 0x3e, 0x8f, 0x9f, 0x44, 0x20, ++ 0x4d, 0x5f, 0x80, 0x59, 0xa9, 0x4a, 0xc7, 0xdf, ++ 0xc3, 0x9a, 0x49, 0xac, 0x01, 0x6d, 0xd7, 0x43, ++ 0xdb, 0xfa, 0x43, 0xc5, 0xd6, 0x71, 0xfd, 0x88 }, ++ .public = { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0xd0, 0xdb, 0xb3, 0xed, 0x19, 0x06, 0x66, 0x3f, ++ 0x15, 0x42, 0x0a, 0xf3, 0x1f, 0x4e, 0xaf, 0x65, ++ 0x09, 0xd9, 0xa9, 0x94, 0x97, 0x23, 0x50, 0x06, ++ 0x05, 0xad, 0x7c, 0x1c, 0x6e, 0x74, 0x50, 0xa9 }, ++ .public = { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0xc0, 0xb1, 0xd0, 0xeb, 0x22, 0xb2, 0x44, 0xfe, ++ 0x32, 0x91, 0x14, 0x00, 0x72, 0xcd, 0xd9, 0xd9, ++ 0x89, 0xb5, 0xf0, 0xec, 0xd9, 0x6c, 0x10, 0x0f, ++ 0xeb, 0x5b, 0xca, 0x24, 0x1c, 0x1d, 0x9f, 0x8f }, ++ .public = { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x48, 0x0b, 0xf4, 0x5f, 0x59, 0x49, 0x42, 0xa8, ++ 0xbc, 0x0f, 0x33, 0x53, 0xc6, 0xe8, 0xb8, 0x85, ++ 0x3d, 0x77, 0xf3, 0x51, 0xf1, 0xc2, 0xca, 0x6c, ++ 0x2d, 0x1a, 0xbf, 0x8a, 0x00, 0xb4, 0x22, 0x9c }, ++ .public = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x30, 0xf9, 0x93, 0xfc, 0xf8, 0x51, 0x4f, 0xc8, ++ 0x9b, 0xd8, 0xdb, 0x14, 0xcd, 0x43, 0xba, 0x0d, ++ 0x4b, 0x25, 0x30, 0xe7, 0x3c, 0x42, 0x76, 0xa0, ++ 0x5e, 0x1b, 0x14, 0x5d, 0x42, 0x0c, 0xed, 0xb4 }, ++ .public = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0xc0, 0x49, 0x74, 0xb7, 0x58, 0x38, 0x0e, 0x2a, ++ 0x5b, 0x5d, 0xf6, 0xeb, 0x09, 0xbb, 0x2f, 0x6b, ++ 0x34, 0x34, 0xf9, 0x82, 0x72, 0x2a, 0x8e, 0x67, ++ 0x6d, 0x3d, 0xa2, 0x51, 0xd1, 0xb3, 0xde, 0x83 }, ++ .public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, ++ 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, ++ 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, ++ 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x50, 0x2a, 0x31, 0x37, 0x3d, 0xb3, 0x24, 0x46, ++ 0x84, 0x2f, 0xe5, 0xad, 0xd3, 0xe0, 0x24, 0x02, ++ 0x2e, 0xa5, 0x4f, 0x27, 0x41, 0x82, 0xaf, 0xc3, ++ 0xd9, 0xf1, 0xbb, 0x3d, 0x39, 0x53, 0x4e, 0xb5 }, ++ .public = { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, ++ 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, ++ 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, ++ 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x90, 0xfa, 0x64, 0x17, 0xb0, 0xe3, 0x70, 0x30, ++ 0xfd, 0x6e, 0x43, 0xef, 0xf2, 0xab, 0xae, 0xf1, ++ 0x4c, 0x67, 0x93, 0x11, 0x7a, 0x03, 0x9c, 0xf6, ++ 0x21, 0x31, 0x8b, 0xa9, 0x0f, 0x4e, 0x98, 0xbe }, ++ .public = { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x78, 0xad, 0x3f, 0x26, 0x02, 0x7f, 0x1c, 0x9f, ++ 0xdd, 0x97, 0x5a, 0x16, 0x13, 0xb9, 0x47, 0x77, ++ 0x9b, 0xad, 0x2c, 0xf2, 0xb7, 0x41, 0xad, 0xe0, ++ 0x18, 0x40, 0x88, 0x5a, 0x30, 0xbb, 0x97, 0x9c }, ++ .public = { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key with low order */ ++ { ++ .private = { 0x98, 0xe2, 0x3d, 0xe7, 0xb1, 0xe0, 0x92, 0x6e, ++ 0xd9, 0xc8, 0x7e, 0x7b, 0x14, 0xba, 0xf5, 0x5f, ++ 0x49, 0x7a, 0x1d, 0x70, 0x96, 0xf9, 0x39, 0x77, ++ 0x68, 0x0e, 0x44, 0xdc, 0x1c, 0x7b, 0x7b, 0x8b }, ++ .public = { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = false ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0xf0, 0x1e, 0x48, 0xda, 0xfa, 0xc9, 0xd7, 0xbc, ++ 0xf5, 0x89, 0xcb, 0xc3, 0x82, 0xc8, 0x78, 0xd1, ++ 0x8b, 0xda, 0x35, 0x50, 0x58, 0x9f, 0xfb, 0x5d, ++ 0x50, 0xb5, 0x23, 0xbe, 0xbe, 0x32, 0x9d, 0xae }, ++ .public = { 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0xbd, 0x36, 0xa0, 0x79, 0x0e, 0xb8, 0x83, 0x09, ++ 0x8c, 0x98, 0x8b, 0x21, 0x78, 0x67, 0x73, 0xde, ++ 0x0b, 0x3a, 0x4d, 0xf1, 0x62, 0x28, 0x2c, 0xf1, ++ 0x10, 0xde, 0x18, 0xdd, 0x48, 0x4c, 0xe7, 0x4b }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x28, 0x87, 0x96, 0xbc, 0x5a, 0xff, 0x4b, 0x81, ++ 0xa3, 0x75, 0x01, 0x75, 0x7b, 0xc0, 0x75, 0x3a, ++ 0x3c, 0x21, 0x96, 0x47, 0x90, 0xd3, 0x86, 0x99, ++ 0x30, 0x8d, 0xeb, 0xc1, 0x7a, 0x6e, 0xaf, 0x8d }, ++ .public = { 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0xb4, 0xe0, 0xdd, 0x76, 0xda, 0x7b, 0x07, 0x17, ++ 0x28, 0xb6, 0x1f, 0x85, 0x67, 0x71, 0xaa, 0x35, ++ 0x6e, 0x57, 0xed, 0xa7, 0x8a, 0x5b, 0x16, 0x55, ++ 0xcc, 0x38, 0x20, 0xfb, 0x5f, 0x85, 0x4c, 0x5c }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x98, 0xdf, 0x84, 0x5f, 0x66, 0x51, 0xbf, 0x11, ++ 0x38, 0x22, 0x1f, 0x11, 0x90, 0x41, 0xf7, 0x2b, ++ 0x6d, 0xbc, 0x3c, 0x4a, 0xce, 0x71, 0x43, 0xd9, ++ 0x9f, 0xd5, 0x5a, 0xd8, 0x67, 0x48, 0x0d, 0xa8 }, ++ .public = { 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x6f, 0xdf, 0x6c, 0x37, 0x61, 0x1d, 0xbd, 0x53, ++ 0x04, 0xdc, 0x0f, 0x2e, 0xb7, 0xc9, 0x51, 0x7e, ++ 0xb3, 0xc5, 0x0e, 0x12, 0xfd, 0x05, 0x0a, 0xc6, ++ 0xde, 0xc2, 0x70, 0x71, 0xd4, 0xbf, 0xc0, 0x34 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0xf0, 0x94, 0x98, 0xe4, 0x6f, 0x02, 0xf8, 0x78, ++ 0x82, 0x9e, 0x78, 0xb8, 0x03, 0xd3, 0x16, 0xa2, ++ 0xed, 0x69, 0x5d, 0x04, 0x98, 0xa0, 0x8a, 0xbd, ++ 0xf8, 0x27, 0x69, 0x30, 0xe2, 0x4e, 0xdc, 0xb0 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .result = { 0x4c, 0x8f, 0xc4, 0xb1, 0xc6, 0xab, 0x88, 0xfb, ++ 0x21, 0xf1, 0x8f, 0x6d, 0x4c, 0x81, 0x02, 0x40, ++ 0xd4, 0xe9, 0x46, 0x51, 0xba, 0x44, 0xf7, 0xa2, ++ 0xc8, 0x63, 0xce, 0xc7, 0xdc, 0x56, 0x60, 0x2d }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x18, 0x13, 0xc1, 0x0a, 0x5c, 0x7f, 0x21, 0xf9, ++ 0x6e, 0x17, 0xf2, 0x88, 0xc0, 0xcc, 0x37, 0x60, ++ 0x7c, 0x04, 0xc5, 0xf5, 0xae, 0xa2, 0xdb, 0x13, ++ 0x4f, 0x9e, 0x2f, 0xfc, 0x66, 0xbd, 0x9d, 0xb8 }, ++ .public = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .result = { 0x1c, 0xd0, 0xb2, 0x82, 0x67, 0xdc, 0x54, 0x1c, ++ 0x64, 0x2d, 0x6d, 0x7d, 0xca, 0x44, 0xa8, 0xb3, ++ 0x8a, 0x63, 0x73, 0x6e, 0xef, 0x5c, 0x4e, 0x65, ++ 0x01, 0xff, 0xbb, 0xb1, 0x78, 0x0c, 0x03, 0x3c }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x78, 0x57, 0xfb, 0x80, 0x86, 0x53, 0x64, 0x5a, ++ 0x0b, 0xeb, 0x13, 0x8a, 0x64, 0xf5, 0xf4, 0xd7, ++ 0x33, 0xa4, 0x5e, 0xa8, 0x4c, 0x3c, 0xda, 0x11, ++ 0xa9, 0xc0, 0x6f, 0x7e, 0x71, 0x39, 0x14, 0x9e }, ++ .public = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .result = { 0x87, 0x55, 0xbe, 0x01, 0xc6, 0x0a, 0x7e, 0x82, ++ 0x5c, 0xff, 0x3e, 0x0e, 0x78, 0xcb, 0x3a, 0xa4, ++ 0x33, 0x38, 0x61, 0x51, 0x6a, 0xa5, 0x9b, 0x1c, ++ 0x51, 0xa8, 0xb2, 0xa5, 0x43, 0xdf, 0xa8, 0x22 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0xe0, 0x3a, 0xa8, 0x42, 0xe2, 0xab, 0xc5, 0x6e, ++ 0x81, 0xe8, 0x7b, 0x8b, 0x9f, 0x41, 0x7b, 0x2a, ++ 0x1e, 0x59, 0x13, 0xc7, 0x23, 0xee, 0xd2, 0x8d, ++ 0x75, 0x2f, 0x8d, 0x47, 0xa5, 0x9f, 0x49, 0x8f }, ++ .public = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, ++ .result = { 0x54, 0xc9, 0xa1, 0xed, 0x95, 0xe5, 0x46, 0xd2, ++ 0x78, 0x22, 0xa3, 0x60, 0x93, 0x1d, 0xda, 0x60, ++ 0xa1, 0xdf, 0x04, 0x9d, 0xa6, 0xf9, 0x04, 0x25, ++ 0x3c, 0x06, 0x12, 0xbb, 0xdc, 0x08, 0x74, 0x76 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0xf8, 0xf7, 0x07, 0xb7, 0x99, 0x9b, 0x18, 0xcb, ++ 0x0d, 0x6b, 0x96, 0x12, 0x4f, 0x20, 0x45, 0x97, ++ 0x2c, 0xa2, 0x74, 0xbf, 0xc1, 0x54, 0xad, 0x0c, ++ 0x87, 0x03, 0x8c, 0x24, 0xc6, 0xd0, 0xd4, 0xb2 }, ++ .public = { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0xcc, 0x1f, 0x40, 0xd7, 0x43, 0xcd, 0xc2, 0x23, ++ 0x0e, 0x10, 0x43, 0xda, 0xba, 0x8b, 0x75, 0xe8, ++ 0x10, 0xf1, 0xfb, 0xab, 0x7f, 0x25, 0x52, 0x69, ++ 0xbd, 0x9e, 0xbb, 0x29, 0xe6, 0xbf, 0x49, 0x4f }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0xa0, 0x34, 0xf6, 0x84, 0xfa, 0x63, 0x1e, 0x1a, ++ 0x34, 0x81, 0x18, 0xc1, 0xce, 0x4c, 0x98, 0x23, ++ 0x1f, 0x2d, 0x9e, 0xec, 0x9b, 0xa5, 0x36, 0x5b, ++ 0x4a, 0x05, 0xd6, 0x9a, 0x78, 0x5b, 0x07, 0x96 }, ++ .public = { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x54, 0x99, 0x8e, 0xe4, 0x3a, 0x5b, 0x00, 0x7b, ++ 0xf4, 0x99, 0xf0, 0x78, 0xe7, 0x36, 0x52, 0x44, ++ 0x00, 0xa8, 0xb5, 0xc7, 0xe9, 0xb9, 0xb4, 0x37, ++ 0x71, 0x74, 0x8c, 0x7c, 0xdf, 0x88, 0x04, 0x12 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x30, 0xb6, 0xc6, 0xa0, 0xf2, 0xff, 0xa6, 0x80, ++ 0x76, 0x8f, 0x99, 0x2b, 0xa8, 0x9e, 0x15, 0x2d, ++ 0x5b, 0xc9, 0x89, 0x3d, 0x38, 0xc9, 0x11, 0x9b, ++ 0xe4, 0xf7, 0x67, 0xbf, 0xab, 0x6e, 0x0c, 0xa5 }, ++ .public = { 0xdc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0xea, 0xd9, 0xb3, 0x8e, 0xfd, 0xd7, 0x23, 0x63, ++ 0x79, 0x34, 0xe5, 0x5a, 0xb7, 0x17, 0xa7, 0xae, ++ 0x09, 0xeb, 0x86, 0xa2, 0x1d, 0xc3, 0x6a, 0x3f, ++ 0xee, 0xb8, 0x8b, 0x75, 0x9e, 0x39, 0x1e, 0x09 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x90, 0x1b, 0x9d, 0xcf, 0x88, 0x1e, 0x01, 0xe0, ++ 0x27, 0x57, 0x50, 0x35, 0xd4, 0x0b, 0x43, 0xbd, ++ 0xc1, 0xc5, 0x24, 0x2e, 0x03, 0x08, 0x47, 0x49, ++ 0x5b, 0x0c, 0x72, 0x86, 0x46, 0x9b, 0x65, 0x91 }, ++ .public = { 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x60, 0x2f, 0xf4, 0x07, 0x89, 0xb5, 0x4b, 0x41, ++ 0x80, 0x59, 0x15, 0xfe, 0x2a, 0x62, 0x21, 0xf0, ++ 0x7a, 0x50, 0xff, 0xc2, 0xc3, 0xfc, 0x94, 0xcf, ++ 0x61, 0xf1, 0x3d, 0x79, 0x04, 0xe8, 0x8e, 0x0e }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x80, 0x46, 0x67, 0x7c, 0x28, 0xfd, 0x82, 0xc9, ++ 0xa1, 0xbd, 0xb7, 0x1a, 0x1a, 0x1a, 0x34, 0xfa, ++ 0xba, 0x12, 0x25, 0xe2, 0x50, 0x7f, 0xe3, 0xf5, ++ 0x4d, 0x10, 0xbd, 0x5b, 0x0d, 0x86, 0x5f, 0x8e }, ++ .public = { 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0xe0, 0x0a, 0xe8, 0xb1, 0x43, 0x47, 0x12, 0x47, ++ 0xba, 0x24, 0xf1, 0x2c, 0x88, 0x55, 0x36, 0xc3, ++ 0xcb, 0x98, 0x1b, 0x58, 0xe1, 0xe5, 0x6b, 0x2b, ++ 0xaf, 0x35, 0xc1, 0x2a, 0xe1, 0xf7, 0x9c, 0x26 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x60, 0x2f, 0x7e, 0x2f, 0x68, 0xa8, 0x46, 0xb8, ++ 0x2c, 0xc2, 0x69, 0xb1, 0xd4, 0x8e, 0x93, 0x98, ++ 0x86, 0xae, 0x54, 0xfd, 0x63, 0x6c, 0x1f, 0xe0, ++ 0x74, 0xd7, 0x10, 0x12, 0x7d, 0x47, 0x24, 0x91 }, ++ .public = { 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x98, 0xcb, 0x9b, 0x50, 0xdd, 0x3f, 0xc2, 0xb0, ++ 0xd4, 0xf2, 0xd2, 0xbf, 0x7c, 0x5c, 0xfd, 0xd1, ++ 0x0c, 0x8f, 0xcd, 0x31, 0xfc, 0x40, 0xaf, 0x1a, ++ 0xd4, 0x4f, 0x47, 0xc1, 0x31, 0x37, 0x63, 0x62 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x60, 0x88, 0x7b, 0x3d, 0xc7, 0x24, 0x43, 0x02, ++ 0x6e, 0xbe, 0xdb, 0xbb, 0xb7, 0x06, 0x65, 0xf4, ++ 0x2b, 0x87, 0xad, 0xd1, 0x44, 0x0e, 0x77, 0x68, ++ 0xfb, 0xd7, 0xe8, 0xe2, 0xce, 0x5f, 0x63, 0x9d }, ++ .public = { 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x38, 0xd6, 0x30, 0x4c, 0x4a, 0x7e, 0x6d, 0x9f, ++ 0x79, 0x59, 0x33, 0x4f, 0xb5, 0x24, 0x5b, 0xd2, ++ 0xc7, 0x54, 0x52, 0x5d, 0x4c, 0x91, 0xdb, 0x95, ++ 0x02, 0x06, 0x92, 0x62, 0x34, 0xc1, 0xf6, 0x33 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0x78, 0xd3, 0x1d, 0xfa, 0x85, 0x44, 0x97, 0xd7, ++ 0x2d, 0x8d, 0xef, 0x8a, 0x1b, 0x7f, 0xb0, 0x06, ++ 0xce, 0xc2, 0xd8, 0xc4, 0x92, 0x46, 0x47, 0xc9, ++ 0x38, 0x14, 0xae, 0x56, 0xfa, 0xed, 0xa4, 0x95 }, ++ .public = { 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x78, 0x6c, 0xd5, 0x49, 0x96, 0xf0, 0x14, 0xa5, ++ 0xa0, 0x31, 0xec, 0x14, 0xdb, 0x81, 0x2e, 0xd0, ++ 0x83, 0x55, 0x06, 0x1f, 0xdb, 0x5d, 0xe6, 0x80, ++ 0xa8, 0x00, 0xac, 0x52, 0x1f, 0x31, 0x8e, 0x23 }, ++ .valid = true ++ }, ++ /* wycheproof - public key >= p */ ++ { ++ .private = { 0xc0, 0x4c, 0x5b, 0xae, 0xfa, 0x83, 0x02, 0xdd, ++ 0xde, 0xd6, 0xa4, 0xbb, 0x95, 0x77, 0x61, 0xb4, ++ 0xeb, 0x97, 0xae, 0xfa, 0x4f, 0xc3, 0xb8, 0x04, ++ 0x30, 0x85, 0xf9, 0x6a, 0x56, 0x59, 0xb3, 0xa5 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0x29, 0xae, 0x8b, 0xc7, 0x3e, 0x9b, 0x10, 0xa0, ++ 0x8b, 0x4f, 0x68, 0x1c, 0x43, 0xc3, 0xe0, 0xac, ++ 0x1a, 0x17, 0x1d, 0x31, 0xb3, 0x8f, 0x1a, 0x48, ++ 0xef, 0xba, 0x29, 0xae, 0x63, 0x9e, 0xa1, 0x34 }, ++ .valid = true ++ }, ++ /* wycheproof - RFC 7748 */ ++ { ++ .private = { 0xa0, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, ++ 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, ++ 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, ++ 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0x44 }, ++ .public = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, ++ 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, ++ 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, ++ 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c }, ++ .result = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, ++ 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, ++ 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, ++ 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 }, ++ .valid = true ++ }, ++ /* wycheproof - RFC 7748 */ ++ { ++ .private = { 0x48, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, ++ 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, ++ 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, ++ 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x4d }, ++ .public = { 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, ++ 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, ++ 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, ++ 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x13 }, ++ .result = { 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, ++ 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8, ++ 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, ++ 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x0a, 0xb4, 0xe7, 0x63, 0x80, 0xd8, 0x4d, 0xde, ++ 0x4f, 0x68, 0x33, 0xc5, 0x8f, 0x2a, 0x9f, 0xb8, ++ 0xf8, 0x3b, 0xb0, 0x16, 0x9b, 0x17, 0x2b, 0xe4, ++ 0xb6, 0xe0, 0x59, 0x28, 0x87, 0x74, 0x1a, 0x36 }, ++ .result = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x89, 0xe1, 0x0d, 0x57, 0x01, 0xb4, 0x33, 0x7d, ++ 0x2d, 0x03, 0x21, 0x81, 0x53, 0x8b, 0x10, 0x64, ++ 0xbd, 0x40, 0x84, 0x40, 0x1c, 0xec, 0xa1, 0xfd, ++ 0x12, 0x66, 0x3a, 0x19, 0x59, 0x38, 0x80, 0x00 }, ++ .result = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x2b, 0x55, 0xd3, 0xaa, 0x4a, 0x8f, 0x80, 0xc8, ++ 0xc0, 0xb2, 0xae, 0x5f, 0x93, 0x3e, 0x85, 0xaf, ++ 0x49, 0xbe, 0xac, 0x36, 0xc2, 0xfa, 0x73, 0x94, ++ 0xba, 0xb7, 0x6c, 0x89, 0x33, 0xf8, 0xf8, 0x1d }, ++ .result = { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x63, 0xe5, 0xb1, 0xfe, 0x96, 0x01, 0xfe, 0x84, ++ 0x38, 0x5d, 0x88, 0x66, 0xb0, 0x42, 0x12, 0x62, ++ 0xf7, 0x8f, 0xbf, 0xa5, 0xaf, 0xf9, 0x58, 0x5e, ++ 0x62, 0x66, 0x79, 0xb1, 0x85, 0x47, 0xd9, 0x59 }, ++ .result = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0xe4, 0x28, 0xf3, 0xda, 0xc1, 0x78, 0x09, 0xf8, ++ 0x27, 0xa5, 0x22, 0xce, 0x32, 0x35, 0x50, 0x58, ++ 0xd0, 0x73, 0x69, 0x36, 0x4a, 0xa7, 0x89, 0x02, ++ 0xee, 0x10, 0x13, 0x9b, 0x9f, 0x9d, 0xd6, 0x53 }, ++ .result = { 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0xb3, 0xb5, 0x0e, 0x3e, 0xd3, 0xa4, 0x07, 0xb9, ++ 0x5d, 0xe9, 0x42, 0xef, 0x74, 0x57, 0x5b, 0x5a, ++ 0xb8, 0xa1, 0x0c, 0x09, 0xee, 0x10, 0x35, 0x44, ++ 0xd6, 0x0b, 0xdf, 0xed, 0x81, 0x38, 0xab, 0x2b }, ++ .result = { 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x21, 0x3f, 0xff, 0xe9, 0x3d, 0x5e, 0xa8, 0xcd, ++ 0x24, 0x2e, 0x46, 0x28, 0x44, 0x02, 0x99, 0x22, ++ 0xc4, 0x3c, 0x77, 0xc9, 0xe3, 0xe4, 0x2f, 0x56, ++ 0x2f, 0x48, 0x5d, 0x24, 0xc5, 0x01, 0xa2, 0x0b }, ++ .result = { 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x91, 0xb2, 0x32, 0xa1, 0x78, 0xb3, 0xcd, 0x53, ++ 0x09, 0x32, 0x44, 0x1e, 0x61, 0x39, 0x41, 0x8f, ++ 0x72, 0x17, 0x22, 0x92, 0xf1, 0xda, 0x4c, 0x18, ++ 0x34, 0xfc, 0x5e, 0xbf, 0xef, 0xb5, 0x1e, 0x3f }, ++ .result = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x04, 0x5c, 0x6e, 0x11, 0xc5, 0xd3, 0x32, 0x55, ++ 0x6c, 0x78, 0x22, 0xfe, 0x94, 0xeb, 0xf8, 0x9b, ++ 0x56, 0xa3, 0x87, 0x8d, 0xc2, 0x7c, 0xa0, 0x79, ++ 0x10, 0x30, 0x58, 0x84, 0x9f, 0xab, 0xcb, 0x4f }, ++ .result = { 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x1c, 0xa2, 0x19, 0x0b, 0x71, 0x16, 0x35, 0x39, ++ 0x06, 0x3c, 0x35, 0x77, 0x3b, 0xda, 0x0c, 0x9c, ++ 0x92, 0x8e, 0x91, 0x36, 0xf0, 0x62, 0x0a, 0xeb, ++ 0x09, 0x3f, 0x09, 0x91, 0x97, 0xb7, 0xf7, 0x4e }, ++ .result = { 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0xf7, 0x6e, 0x90, 0x10, 0xac, 0x33, 0xc5, 0x04, ++ 0x3b, 0x2d, 0x3b, 0x76, 0xa8, 0x42, 0x17, 0x10, ++ 0x00, 0xc4, 0x91, 0x62, 0x22, 0xe9, 0xe8, 0x58, ++ 0x97, 0xa0, 0xae, 0xc7, 0xf6, 0x35, 0x0b, 0x3c }, ++ .result = { 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0xbb, 0x72, 0x68, 0x8d, 0x8f, 0x8a, 0xa7, 0xa3, ++ 0x9c, 0xd6, 0x06, 0x0c, 0xd5, 0xc8, 0x09, 0x3c, ++ 0xde, 0xc6, 0xfe, 0x34, 0x19, 0x37, 0xc3, 0x88, ++ 0x6a, 0x99, 0x34, 0x6c, 0xd0, 0x7f, 0xaa, 0x55 }, ++ .result = { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x88, 0xfd, 0xde, 0xa1, 0x93, 0x39, 0x1c, 0x6a, ++ 0x59, 0x33, 0xef, 0x9b, 0x71, 0x90, 0x15, 0x49, ++ 0x44, 0x72, 0x05, 0xaa, 0xe9, 0xda, 0x92, 0x8a, ++ 0x6b, 0x91, 0xa3, 0x52, 0xba, 0x10, 0xf4, 0x1f }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }, ++ .valid = true ++ }, ++ /* wycheproof - edge case for shared secret */ ++ { ++ .private = { 0xa0, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b, 0xe4, ++ 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84, 0xa3, ++ 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9, 0xcc, ++ 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0xbf, 0x63 }, ++ .public = { 0x30, 0x3b, 0x39, 0x2f, 0x15, 0x31, 0x16, 0xca, ++ 0xd9, 0xcc, 0x68, 0x2a, 0x00, 0xcc, 0xc4, 0x4c, ++ 0x95, 0xff, 0x0d, 0x3b, 0xbe, 0x56, 0x8b, 0xeb, ++ 0x6c, 0x4e, 0x73, 0x9b, 0xaf, 0xdc, 0x2c, 0x68 }, ++ .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }, ++ .valid = true ++ }, ++ /* wycheproof - checking for overflow */ ++ { ++ .private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .public = { 0xfd, 0x30, 0x0a, 0xeb, 0x40, 0xe1, 0xfa, 0x58, ++ 0x25, 0x18, 0x41, 0x2b, 0x49, 0xb2, 0x08, 0xa7, ++ 0x84, 0x2b, 0x1e, 0x1f, 0x05, 0x6a, 0x04, 0x01, ++ 0x78, 0xea, 0x41, 0x41, 0x53, 0x4f, 0x65, 0x2d }, ++ .result = { 0xb7, 0x34, 0x10, 0x5d, 0xc2, 0x57, 0x58, 0x5d, ++ 0x73, 0xb5, 0x66, 0xcc, 0xb7, 0x6f, 0x06, 0x27, ++ 0x95, 0xcc, 0xbe, 0xc8, 0x91, 0x28, 0xe5, 0x2b, ++ 0x02, 0xf3, 0xe5, 0x96, 0x39, 0xf1, 0x3c, 0x46 }, ++ .valid = true ++ }, ++ /* wycheproof - checking for overflow */ ++ { ++ .private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .public = { 0xc8, 0xef, 0x79, 0xb5, 0x14, 0xd7, 0x68, 0x26, ++ 0x77, 0xbc, 0x79, 0x31, 0xe0, 0x6e, 0xe5, 0xc2, ++ 0x7c, 0x9b, 0x39, 0x2b, 0x4a, 0xe9, 0x48, 0x44, ++ 0x73, 0xf5, 0x54, 0xe6, 0x67, 0x8e, 0xcc, 0x2e }, ++ .result = { 0x64, 0x7a, 0x46, 0xb6, 0xfc, 0x3f, 0x40, 0xd6, ++ 0x21, 0x41, 0xee, 0x3c, 0xee, 0x70, 0x6b, 0x4d, ++ 0x7a, 0x92, 0x71, 0x59, 0x3a, 0x7b, 0x14, 0x3e, ++ 0x8e, 0x2e, 0x22, 0x79, 0x88, 0x3e, 0x45, 0x50 }, ++ .valid = true ++ }, ++ /* wycheproof - checking for overflow */ ++ { ++ .private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .public = { 0x64, 0xae, 0xac, 0x25, 0x04, 0x14, 0x48, 0x61, ++ 0x53, 0x2b, 0x7b, 0xbc, 0xb6, 0xc8, 0x7d, 0x67, ++ 0xdd, 0x4c, 0x1f, 0x07, 0xeb, 0xc2, 0xe0, 0x6e, ++ 0xff, 0xb9, 0x5a, 0xec, 0xc6, 0x17, 0x0b, 0x2c }, ++ .result = { 0x4f, 0xf0, 0x3d, 0x5f, 0xb4, 0x3c, 0xd8, 0x65, ++ 0x7a, 0x3c, 0xf3, 0x7c, 0x13, 0x8c, 0xad, 0xce, ++ 0xcc, 0xe5, 0x09, 0xe4, 0xeb, 0xa0, 0x89, 0xd0, ++ 0xef, 0x40, 0xb4, 0xe4, 0xfb, 0x94, 0x61, 0x55 }, ++ .valid = true ++ }, ++ /* wycheproof - checking for overflow */ ++ { ++ .private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .public = { 0xbf, 0x68, 0xe3, 0x5e, 0x9b, 0xdb, 0x7e, 0xee, ++ 0x1b, 0x50, 0x57, 0x02, 0x21, 0x86, 0x0f, 0x5d, ++ 0xcd, 0xad, 0x8a, 0xcb, 0xab, 0x03, 0x1b, 0x14, ++ 0x97, 0x4c, 0xc4, 0x90, 0x13, 0xc4, 0x98, 0x31 }, ++ .result = { 0x21, 0xce, 0xe5, 0x2e, 0xfd, 0xbc, 0x81, 0x2e, ++ 0x1d, 0x02, 0x1a, 0x4a, 0xf1, 0xe1, 0xd8, 0xbc, ++ 0x4d, 0xb3, 0xc4, 0x00, 0xe4, 0xd2, 0xa2, 0xc5, ++ 0x6a, 0x39, 0x26, 0xdb, 0x4d, 0x99, 0xc6, 0x5b }, ++ .valid = true ++ }, ++ /* wycheproof - checking for overflow */ ++ { ++ .private = { 0xc8, 0x17, 0x24, 0x70, 0x40, 0x00, 0xb2, 0x6d, ++ 0x31, 0x70, 0x3c, 0xc9, 0x7e, 0x3a, 0x37, 0x8d, ++ 0x56, 0xfa, 0xd8, 0x21, 0x93, 0x61, 0xc8, 0x8c, ++ 0xca, 0x8b, 0xd7, 0xc5, 0x71, 0x9b, 0x12, 0xb2 }, ++ .public = { 0x53, 0x47, 0xc4, 0x91, 0x33, 0x1a, 0x64, 0xb4, ++ 0x3d, 0xdc, 0x68, 0x30, 0x34, 0xe6, 0x77, 0xf5, ++ 0x3d, 0xc3, 0x2b, 0x52, 0xa5, 0x2a, 0x57, 0x7c, ++ 0x15, 0xa8, 0x3b, 0xf2, 0x98, 0xe9, 0x9f, 0x19 }, ++ .result = { 0x18, 0xcb, 0x89, 0xe4, 0xe2, 0x0c, 0x0c, 0x2b, ++ 0xd3, 0x24, 0x30, 0x52, 0x45, 0x26, 0x6c, 0x93, ++ 0x27, 0x69, 0x0b, 0xbe, 0x79, 0xac, 0xb8, 0x8f, ++ 0x5b, 0x8f, 0xb3, 0xf7, 0x4e, 0xca, 0x3e, 0x52 }, ++ .valid = true ++ }, ++ /* wycheproof - private key == -1 (mod order) */ ++ { ++ .private = { 0xa0, 0x23, 0xcd, 0xd0, 0x83, 0xef, 0x5b, 0xb8, ++ 0x2f, 0x10, 0xd6, 0x2e, 0x59, 0xe1, 0x5a, 0x68, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50 }, ++ .public = { 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e, ++ 0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57, ++ 0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f, ++ 0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 }, ++ .result = { 0x25, 0x8e, 0x04, 0x52, 0x3b, 0x8d, 0x25, 0x3e, ++ 0xe6, 0x57, 0x19, 0xfc, 0x69, 0x06, 0xc6, 0x57, ++ 0x19, 0x2d, 0x80, 0x71, 0x7e, 0xdc, 0x82, 0x8f, ++ 0xa0, 0xaf, 0x21, 0x68, 0x6e, 0x2f, 0xaa, 0x75 }, ++ .valid = true ++ }, ++ /* wycheproof - private key == 1 (mod order) on twist */ ++ { ++ .private = { 0x58, 0x08, 0x3d, 0xd2, 0x61, 0xad, 0x91, 0xef, ++ 0xf9, 0x52, 0x32, 0x2e, 0xc8, 0x24, 0xc6, 0x82, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5f }, ++ .public = { 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f, ++ 0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6, ++ 0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64, ++ 0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 }, ++ .result = { 0x2e, 0xae, 0x5e, 0xc3, 0xdd, 0x49, 0x4e, 0x9f, ++ 0x2d, 0x37, 0xd2, 0x58, 0xf8, 0x73, 0xa8, 0xe6, ++ 0xe9, 0xd0, 0xdb, 0xd1, 0xe3, 0x83, 0xef, 0x64, ++ 0xd9, 0x8b, 0xb9, 0x1b, 0x3e, 0x0b, 0xe0, 0x35 }, ++ .valid = true ++ } ++}; ++ ++bool __init curve25519_selftest(void) ++{ ++ bool success = true, ret, ret2; ++ size_t i = 0, j; ++ u8 in[CURVE25519_KEY_SIZE]; ++ u8 out[CURVE25519_KEY_SIZE], out2[CURVE25519_KEY_SIZE], ++ out3[CURVE25519_KEY_SIZE]; ++ ++ for (i = 0; i < ARRAY_SIZE(curve25519_test_vectors); ++i) { ++ memset(out, 0, CURVE25519_KEY_SIZE); ++ ret = curve25519(out, curve25519_test_vectors[i].private, ++ curve25519_test_vectors[i].public); ++ if (ret != curve25519_test_vectors[i].valid || ++ memcmp(out, curve25519_test_vectors[i].result, ++ CURVE25519_KEY_SIZE)) { ++ pr_err("curve25519 self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ ++ for (i = 0; i < 5; ++i) { ++ get_random_bytes(in, sizeof(in)); ++ ret = curve25519_generate_public(out, in); ++ ret2 = curve25519(out2, in, (u8[CURVE25519_KEY_SIZE]){ 9 }); ++ curve25519_generic(out3, in, (u8[CURVE25519_KEY_SIZE]){ 9 }); ++ if (ret != ret2 || ++ memcmp(out, out2, CURVE25519_KEY_SIZE) || ++ memcmp(out, out3, CURVE25519_KEY_SIZE)) { ++ pr_err("curve25519 basepoint self-test %zu: FAIL: input - 0x", ++ i + 1); ++ for (j = CURVE25519_KEY_SIZE; j-- > 0;) ++ printk(KERN_CONT "%02x", in[j]); ++ printk(KERN_CONT "\n"); ++ success = false; ++ } ++ } ++ ++ return success; ++} +--- a/lib/crypto/curve25519.c ++++ b/lib/crypto/curve25519.c +@@ -13,6 +13,8 @@ + #include + #include + ++bool curve25519_selftest(void); ++ + const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 }; + const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 }; + +@@ -20,6 +22,21 @@ EXPORT_SYMBOL(curve25519_null_point); + EXPORT_SYMBOL(curve25519_base_point); + EXPORT_SYMBOL(curve25519_generic); + ++static int __init mod_init(void) ++{ ++ if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && ++ WARN_ON(!curve25519_selftest())) ++ return -ENODEV; ++ return 0; ++} ++ ++static void __exit mod_exit(void) ++{ ++} ++ ++module_init(mod_init); ++module_exit(mod_exit); ++ + MODULE_LICENSE("GPL v2"); + MODULE_DESCRIPTION("Curve25519 scalar multiplication"); + MODULE_AUTHOR("Jason A. Donenfeld "); diff --git a/ipq806x/backport-5.4/080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch b/ipq806x/backport-5.4/080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch new file mode 100644 index 0000000..c41ef55 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0041-crypto-poly1305-add-new-32-and-64-bit-generic-versio.patch @@ -0,0 +1,1164 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 5 Jan 2020 22:40:46 -0500 +Subject: [PATCH] crypto: poly1305 - add new 32 and 64-bit generic versions + +commit 1c08a104360f3e18f4ee6346c21cc3923efb952e upstream. + +These two C implementations from Zinc -- a 32x32 one and a 64x64 one, +depending on the platform -- come from Andrew Moon's public domain +poly1305-donna portable code, modified for usage in the kernel. The +precomputation in the 32-bit version and the use of 64x64 multiplies in +the 64-bit version make these perform better than the code it replaces. +Moon's code is also very widespread and has received many eyeballs of +scrutiny. + +There's a bit of interference between the x86 implementation, which +relies on internal details of the old scalar implementation. In the next +commit, the x86 implementation will be replaced with a faster one that +doesn't rely on this, so none of this matters much. But for now, to keep +this passing the tests, we inline the bits of the old implementation +that the x86 implementation relied on. Also, since we now support a +slightly larger key space, via the union, some offsets had to be fixed +up. + +Nonce calculation was folded in with the emit function, to take +advantage of 64x64 arithmetic. However, Adiantum appeared to rely on no +nonce handling in emit, so this path was conditionalized. We also +introduced a new struct, poly1305_core_key, to represent the precise +amount of space that particular implementation uses. + +Testing with kbench9000, depending on the CPU, the update function for +the 32x32 version has been improved by 4%-7%, and for the 64x64 by +19%-30%. The 32x32 gains are small, but I think there's great value in +having a parallel implementation to the 64x64 one so that the two can be +compared side-by-side as nice stand-alone units. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305-avx2-x86_64.S | 20 +-- + arch/x86/crypto/poly1305_glue.c | 215 +++++++++++++++++++++++-- + crypto/adiantum.c | 4 +- + crypto/nhpoly1305.c | 2 +- + crypto/poly1305_generic.c | 25 ++- + include/crypto/internal/poly1305.h | 45 ++---- + include/crypto/nhpoly1305.h | 4 +- + include/crypto/poly1305.h | 26 ++- + lib/crypto/Makefile | 4 +- + lib/crypto/poly1305-donna32.c | 204 +++++++++++++++++++++++ + lib/crypto/poly1305-donna64.c | 185 +++++++++++++++++++++ + lib/crypto/poly1305.c | 169 +------------------ + 12 files changed, 675 insertions(+), 228 deletions(-) + create mode 100644 lib/crypto/poly1305-donna32.c + create mode 100644 lib/crypto/poly1305-donna64.c + +--- a/arch/x86/crypto/poly1305-avx2-x86_64.S ++++ b/arch/x86/crypto/poly1305-avx2-x86_64.S +@@ -34,16 +34,16 @@ ORMASK: .octa 0x000000000100000000000000 + #define u2 0x08(%r8) + #define u3 0x0c(%r8) + #define u4 0x10(%r8) +-#define w0 0x14(%r8) +-#define w1 0x18(%r8) +-#define w2 0x1c(%r8) +-#define w3 0x20(%r8) +-#define w4 0x24(%r8) +-#define y0 0x28(%r8) +-#define y1 0x2c(%r8) +-#define y2 0x30(%r8) +-#define y3 0x34(%r8) +-#define y4 0x38(%r8) ++#define w0 0x18(%r8) ++#define w1 0x1c(%r8) ++#define w2 0x20(%r8) ++#define w3 0x24(%r8) ++#define w4 0x28(%r8) ++#define y0 0x30(%r8) ++#define y1 0x34(%r8) ++#define y2 0x38(%r8) ++#define y3 0x3c(%r8) ++#define y4 0x40(%r8) + #define m %rsi + #define hc0 %ymm0 + #define hc1 %ymm1 +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -25,6 +25,21 @@ asmlinkage void poly1305_4block_avx2(u32 + static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_simd); + static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx2); + ++static inline u64 mlt(u64 a, u64 b) ++{ ++ return a * b; ++} ++ ++static inline u32 sr(u64 v, u_char n) ++{ ++ return v >> n; ++} ++ ++static inline u32 and(u32 v, u32 mask) ++{ ++ return v & mask; ++} ++ + static void poly1305_simd_mult(u32 *a, const u32 *b) + { + u8 m[POLY1305_BLOCK_SIZE]; +@@ -36,6 +51,168 @@ static void poly1305_simd_mult(u32 *a, c + poly1305_block_sse2(a, m, b, 1); + } + ++static void poly1305_integer_setkey(struct poly1305_key *key, const u8 *raw_key) ++{ ++ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ ++ key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff; ++ key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03; ++ key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff; ++ key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff; ++ key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff; ++} ++ ++static void poly1305_integer_blocks(struct poly1305_state *state, ++ const struct poly1305_key *key, ++ const void *src, ++ unsigned int nblocks, u32 hibit) ++{ ++ u32 r0, r1, r2, r3, r4; ++ u32 s1, s2, s3, s4; ++ u32 h0, h1, h2, h3, h4; ++ u64 d0, d1, d2, d3, d4; ++ ++ if (!nblocks) ++ return; ++ ++ r0 = key->r[0]; ++ r1 = key->r[1]; ++ r2 = key->r[2]; ++ r3 = key->r[3]; ++ r4 = key->r[4]; ++ ++ s1 = r1 * 5; ++ s2 = r2 * 5; ++ s3 = r3 * 5; ++ s4 = r4 * 5; ++ ++ h0 = state->h[0]; ++ h1 = state->h[1]; ++ h2 = state->h[2]; ++ h3 = state->h[3]; ++ h4 = state->h[4]; ++ ++ do { ++ /* h += m[i] */ ++ h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff; ++ h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; ++ h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff; ++ h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff; ++ h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24); ++ ++ /* h *= r */ ++ d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + ++ mlt(h3, s2) + mlt(h4, s1); ++ d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + ++ mlt(h3, s3) + mlt(h4, s2); ++ d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + ++ mlt(h3, s4) + mlt(h4, s3); ++ d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + ++ mlt(h3, r0) + mlt(h4, s4); ++ d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + ++ mlt(h3, r1) + mlt(h4, r0); ++ ++ /* (partial) h %= p */ ++ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff); ++ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff); ++ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff); ++ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff); ++ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff); ++ h1 += h0 >> 26; h0 = h0 & 0x3ffffff; ++ ++ src += POLY1305_BLOCK_SIZE; ++ } while (--nblocks); ++ ++ state->h[0] = h0; ++ state->h[1] = h1; ++ state->h[2] = h2; ++ state->h[3] = h3; ++ state->h[4] = h4; ++} ++ ++static void poly1305_integer_emit(const struct poly1305_state *state, void *dst) ++{ ++ u32 h0, h1, h2, h3, h4; ++ u32 g0, g1, g2, g3, g4; ++ u32 mask; ++ ++ /* fully carry h */ ++ h0 = state->h[0]; ++ h1 = state->h[1]; ++ h2 = state->h[2]; ++ h3 = state->h[3]; ++ h4 = state->h[4]; ++ ++ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; ++ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; ++ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff; ++ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff; ++ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff; ++ ++ /* compute h + -p */ ++ g0 = h0 + 5; ++ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff; ++ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff; ++ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff; ++ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff; ++ ++ /* select h if h < p, or h + -p if h >= p */ ++ mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; ++ g0 &= mask; ++ g1 &= mask; ++ g2 &= mask; ++ g3 &= mask; ++ g4 &= mask; ++ mask = ~mask; ++ h0 = (h0 & mask) | g0; ++ h1 = (h1 & mask) | g1; ++ h2 = (h2 & mask) | g2; ++ h3 = (h3 & mask) | g3; ++ h4 = (h4 & mask) | g4; ++ ++ /* h = h % (2^128) */ ++ put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0); ++ put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4); ++ put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8); ++ put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12); ++} ++ ++void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key) ++{ ++ poly1305_integer_setkey(desc->opaque_r, key); ++ desc->s[0] = get_unaligned_le32(key + 16); ++ desc->s[1] = get_unaligned_le32(key + 20); ++ desc->s[2] = get_unaligned_le32(key + 24); ++ desc->s[3] = get_unaligned_le32(key + 28); ++ poly1305_core_init(&desc->h); ++ desc->buflen = 0; ++ desc->sset = true; ++ desc->rset = 1; ++} ++EXPORT_SYMBOL_GPL(poly1305_init_arch); ++ ++static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, ++ const u8 *src, unsigned int srclen) ++{ ++ if (!dctx->sset) { ++ if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { ++ poly1305_integer_setkey(dctx->r, src); ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ dctx->rset = 1; ++ } ++ if (srclen >= POLY1305_BLOCK_SIZE) { ++ dctx->s[0] = get_unaligned_le32(src + 0); ++ dctx->s[1] = get_unaligned_le32(src + 4); ++ dctx->s[2] = get_unaligned_le32(src + 8); ++ dctx->s[3] = get_unaligned_le32(src + 12); ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ dctx->sset = true; ++ } ++ } ++ return srclen; ++} ++ + static unsigned int poly1305_scalar_blocks(struct poly1305_desc_ctx *dctx, + const u8 *src, unsigned int srclen) + { +@@ -47,8 +224,8 @@ static unsigned int poly1305_scalar_bloc + srclen = datalen; + } + if (srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_core_blocks(&dctx->h, dctx->r, src, +- srclen / POLY1305_BLOCK_SIZE, 1); ++ poly1305_integer_blocks(&dctx->h, dctx->opaque_r, src, ++ srclen / POLY1305_BLOCK_SIZE, 1); + srclen %= POLY1305_BLOCK_SIZE; + } + return srclen; +@@ -105,12 +282,6 @@ static unsigned int poly1305_simd_blocks + return srclen; + } + +-void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key) +-{ +- poly1305_init_generic(desc, key); +-} +-EXPORT_SYMBOL(poly1305_init_arch); +- + void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src, + unsigned int srclen) + { +@@ -158,9 +329,31 @@ void poly1305_update_arch(struct poly130 + } + EXPORT_SYMBOL(poly1305_update_arch); + +-void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *digest) ++void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *dst) + { +- poly1305_final_generic(desc, digest); ++ __le32 digest[4]; ++ u64 f = 0; ++ ++ if (unlikely(desc->buflen)) { ++ desc->buf[desc->buflen++] = 1; ++ memset(desc->buf + desc->buflen, 0, ++ POLY1305_BLOCK_SIZE - desc->buflen); ++ poly1305_integer_blocks(&desc->h, desc->opaque_r, desc->buf, 1, 0); ++ } ++ ++ poly1305_integer_emit(&desc->h, digest); ++ ++ /* mac = (h + s) % (2^128) */ ++ f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0]; ++ put_unaligned_le32(f, dst + 0); ++ f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1]; ++ put_unaligned_le32(f, dst + 4); ++ f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2]; ++ put_unaligned_le32(f, dst + 8); ++ f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3]; ++ put_unaligned_le32(f, dst + 12); ++ ++ *desc = (struct poly1305_desc_ctx){}; + } + EXPORT_SYMBOL(poly1305_final_arch); + +@@ -183,7 +376,7 @@ static int crypto_poly1305_final(struct + if (unlikely(!dctx->sset)) + return -ENOKEY; + +- poly1305_final_generic(dctx, dst); ++ poly1305_final_arch(dctx, dst); + return 0; + } + +--- a/crypto/adiantum.c ++++ b/crypto/adiantum.c +@@ -72,7 +72,7 @@ struct adiantum_tfm_ctx { + struct crypto_skcipher *streamcipher; + struct crypto_cipher *blockcipher; + struct crypto_shash *hash; +- struct poly1305_key header_hash_key; ++ struct poly1305_core_key header_hash_key; + }; + + struct adiantum_request_ctx { +@@ -249,7 +249,7 @@ static void adiantum_hash_header(struct + poly1305_core_blocks(&state, &tctx->header_hash_key, req->iv, + TWEAK_SIZE / POLY1305_BLOCK_SIZE, 1); + +- poly1305_core_emit(&state, &rctx->header_hash); ++ poly1305_core_emit(&state, NULL, &rctx->header_hash); + } + + /* Hash the left-hand part (the "bulk") of the message using NHPoly1305 */ +--- a/crypto/nhpoly1305.c ++++ b/crypto/nhpoly1305.c +@@ -210,7 +210,7 @@ int crypto_nhpoly1305_final_helper(struc + if (state->nh_remaining) + process_nh_hash_value(state, key); + +- poly1305_core_emit(&state->poly_state, dst); ++ poly1305_core_emit(&state->poly_state, NULL, dst); + return 0; + } + EXPORT_SYMBOL(crypto_nhpoly1305_final_helper); +--- a/crypto/poly1305_generic.c ++++ b/crypto/poly1305_generic.c +@@ -31,6 +31,29 @@ static int crypto_poly1305_init(struct s + return 0; + } + ++static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, ++ const u8 *src, unsigned int srclen) ++{ ++ if (!dctx->sset) { ++ if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { ++ poly1305_core_setkey(&dctx->core_r, src); ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ dctx->rset = 2; ++ } ++ if (srclen >= POLY1305_BLOCK_SIZE) { ++ dctx->s[0] = get_unaligned_le32(src + 0); ++ dctx->s[1] = get_unaligned_le32(src + 4); ++ dctx->s[2] = get_unaligned_le32(src + 8); ++ dctx->s[3] = get_unaligned_le32(src + 12); ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ dctx->sset = true; ++ } ++ } ++ return srclen; ++} ++ + static void poly1305_blocks(struct poly1305_desc_ctx *dctx, const u8 *src, + unsigned int srclen) + { +@@ -42,7 +65,7 @@ static void poly1305_blocks(struct poly1 + srclen = datalen; + } + +- poly1305_core_blocks(&dctx->h, dctx->r, src, ++ poly1305_core_blocks(&dctx->h, &dctx->core_r, src, + srclen / POLY1305_BLOCK_SIZE, 1); + } + +--- a/include/crypto/internal/poly1305.h ++++ b/include/crypto/internal/poly1305.h +@@ -11,48 +11,23 @@ + #include + + /* +- * Poly1305 core functions. These implement the ε-almost-∆-universal hash +- * function underlying the Poly1305 MAC, i.e. they don't add an encrypted nonce +- * ("s key") at the end. They also only support block-aligned inputs. ++ * Poly1305 core functions. These only accept whole blocks; the caller must ++ * handle any needed block buffering and padding. 'hibit' must be 1 for any ++ * full blocks, or 0 for the final block if it had to be padded. If 'nonce' is ++ * non-NULL, then it's added at the end to compute the Poly1305 MAC. Otherwise, ++ * only the ε-almost-∆-universal hash function (not the full MAC) is computed. + */ +-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key); ++ ++void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key); + static inline void poly1305_core_init(struct poly1305_state *state) + { + *state = (struct poly1305_state){}; + } + + void poly1305_core_blocks(struct poly1305_state *state, +- const struct poly1305_key *key, const void *src, ++ const struct poly1305_core_key *key, const void *src, + unsigned int nblocks, u32 hibit); +-void poly1305_core_emit(const struct poly1305_state *state, void *dst); +- +-/* +- * Poly1305 requires a unique key for each tag, which implies that we can't set +- * it on the tfm that gets accessed by multiple users simultaneously. Instead we +- * expect the key as the first 32 bytes in the update() call. +- */ +-static inline +-unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, +- const u8 *src, unsigned int srclen) +-{ +- if (!dctx->sset) { +- if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_core_setkey(dctx->r, src); +- src += POLY1305_BLOCK_SIZE; +- srclen -= POLY1305_BLOCK_SIZE; +- dctx->rset = 1; +- } +- if (srclen >= POLY1305_BLOCK_SIZE) { +- dctx->s[0] = get_unaligned_le32(src + 0); +- dctx->s[1] = get_unaligned_le32(src + 4); +- dctx->s[2] = get_unaligned_le32(src + 8); +- dctx->s[3] = get_unaligned_le32(src + 12); +- src += POLY1305_BLOCK_SIZE; +- srclen -= POLY1305_BLOCK_SIZE; +- dctx->sset = true; +- } +- } +- return srclen; +-} ++void poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4], ++ void *dst); + + #endif +--- a/include/crypto/nhpoly1305.h ++++ b/include/crypto/nhpoly1305.h +@@ -7,7 +7,7 @@ + #define _NHPOLY1305_H + + #include +-#include ++#include + + /* NH parameterization: */ + +@@ -33,7 +33,7 @@ + #define NHPOLY1305_KEY_SIZE (POLY1305_BLOCK_SIZE + NH_KEY_BYTES) + + struct nhpoly1305_key { +- struct poly1305_key poly_key; ++ struct poly1305_core_key poly_key; + u32 nh_key[NH_KEY_WORDS]; + }; + +--- a/include/crypto/poly1305.h ++++ b/include/crypto/poly1305.h +@@ -13,12 +13,29 @@ + #define POLY1305_KEY_SIZE 32 + #define POLY1305_DIGEST_SIZE 16 + ++/* The poly1305_key and poly1305_state types are mostly opaque and ++ * implementation-defined. Limbs might be in base 2^64 or base 2^26, or ++ * different yet. The union type provided keeps these 64-bit aligned for the ++ * case in which this is implemented using 64x64 multiplies. ++ */ ++ + struct poly1305_key { +- u32 r[5]; /* key, base 2^26 */ ++ union { ++ u32 r[5]; ++ u64 r64[3]; ++ }; ++}; ++ ++struct poly1305_core_key { ++ struct poly1305_key key; ++ struct poly1305_key precomputed_s; + }; + + struct poly1305_state { +- u32 h[5]; /* accumulator, base 2^26 */ ++ union { ++ u32 h[5]; ++ u64 h64[3]; ++ }; + }; + + struct poly1305_desc_ctx { +@@ -35,7 +52,10 @@ struct poly1305_desc_ctx { + /* accumulator */ + struct poly1305_state h; + /* key */ +- struct poly1305_key r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE]; ++ union { ++ struct poly1305_key opaque_r[CONFIG_CRYPTO_LIB_POLY1305_RSIZE]; ++ struct poly1305_core_key core_r; ++ }; + }; + + void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key); +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -28,7 +28,9 @@ obj-$(CONFIG_CRYPTO_LIB_DES) += libdes + libdes-y := des.o + + obj-$(CONFIG_CRYPTO_LIB_POLY1305_GENERIC) += libpoly1305.o +-libpoly1305-y := poly1305.o ++libpoly1305-y := poly1305-donna32.o ++libpoly1305-$(CONFIG_ARCH_SUPPORTS_INT128) := poly1305-donna64.o ++libpoly1305-y += poly1305.o + + obj-$(CONFIG_CRYPTO_LIB_SHA256) += libsha256.o + libsha256-y := sha256.o +--- /dev/null ++++ b/lib/crypto/poly1305-donna32.c +@@ -0,0 +1,204 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is based in part on Andrew Moon's poly1305-donna, which is in the ++ * public domain. ++ */ ++ ++#include ++#include ++#include ++ ++void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16]) ++{ ++ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ ++ key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff; ++ key->key.r[1] = (get_unaligned_le32(&raw_key[3]) >> 2) & 0x3ffff03; ++ key->key.r[2] = (get_unaligned_le32(&raw_key[6]) >> 4) & 0x3ffc0ff; ++ key->key.r[3] = (get_unaligned_le32(&raw_key[9]) >> 6) & 0x3f03fff; ++ key->key.r[4] = (get_unaligned_le32(&raw_key[12]) >> 8) & 0x00fffff; ++ ++ /* s = 5*r */ ++ key->precomputed_s.r[0] = key->key.r[1] * 5; ++ key->precomputed_s.r[1] = key->key.r[2] * 5; ++ key->precomputed_s.r[2] = key->key.r[3] * 5; ++ key->precomputed_s.r[3] = key->key.r[4] * 5; ++} ++EXPORT_SYMBOL(poly1305_core_setkey); ++ ++void poly1305_core_blocks(struct poly1305_state *state, ++ const struct poly1305_core_key *key, const void *src, ++ unsigned int nblocks, u32 hibit) ++{ ++ const u8 *input = src; ++ u32 r0, r1, r2, r3, r4; ++ u32 s1, s2, s3, s4; ++ u32 h0, h1, h2, h3, h4; ++ u64 d0, d1, d2, d3, d4; ++ u32 c; ++ ++ if (!nblocks) ++ return; ++ ++ hibit <<= 24; ++ ++ r0 = key->key.r[0]; ++ r1 = key->key.r[1]; ++ r2 = key->key.r[2]; ++ r3 = key->key.r[3]; ++ r4 = key->key.r[4]; ++ ++ s1 = key->precomputed_s.r[0]; ++ s2 = key->precomputed_s.r[1]; ++ s3 = key->precomputed_s.r[2]; ++ s4 = key->precomputed_s.r[3]; ++ ++ h0 = state->h[0]; ++ h1 = state->h[1]; ++ h2 = state->h[2]; ++ h3 = state->h[3]; ++ h4 = state->h[4]; ++ ++ do { ++ /* h += m[i] */ ++ h0 += (get_unaligned_le32(&input[0])) & 0x3ffffff; ++ h1 += (get_unaligned_le32(&input[3]) >> 2) & 0x3ffffff; ++ h2 += (get_unaligned_le32(&input[6]) >> 4) & 0x3ffffff; ++ h3 += (get_unaligned_le32(&input[9]) >> 6) & 0x3ffffff; ++ h4 += (get_unaligned_le32(&input[12]) >> 8) | hibit; ++ ++ /* h *= r */ ++ d0 = ((u64)h0 * r0) + ((u64)h1 * s4) + ++ ((u64)h2 * s3) + ((u64)h3 * s2) + ++ ((u64)h4 * s1); ++ d1 = ((u64)h0 * r1) + ((u64)h1 * r0) + ++ ((u64)h2 * s4) + ((u64)h3 * s3) + ++ ((u64)h4 * s2); ++ d2 = ((u64)h0 * r2) + ((u64)h1 * r1) + ++ ((u64)h2 * r0) + ((u64)h3 * s4) + ++ ((u64)h4 * s3); ++ d3 = ((u64)h0 * r3) + ((u64)h1 * r2) + ++ ((u64)h2 * r1) + ((u64)h3 * r0) + ++ ((u64)h4 * s4); ++ d4 = ((u64)h0 * r4) + ((u64)h1 * r3) + ++ ((u64)h2 * r2) + ((u64)h3 * r1) + ++ ((u64)h4 * r0); ++ ++ /* (partial) h %= p */ ++ c = (u32)(d0 >> 26); ++ h0 = (u32)d0 & 0x3ffffff; ++ d1 += c; ++ c = (u32)(d1 >> 26); ++ h1 = (u32)d1 & 0x3ffffff; ++ d2 += c; ++ c = (u32)(d2 >> 26); ++ h2 = (u32)d2 & 0x3ffffff; ++ d3 += c; ++ c = (u32)(d3 >> 26); ++ h3 = (u32)d3 & 0x3ffffff; ++ d4 += c; ++ c = (u32)(d4 >> 26); ++ h4 = (u32)d4 & 0x3ffffff; ++ h0 += c * 5; ++ c = (h0 >> 26); ++ h0 = h0 & 0x3ffffff; ++ h1 += c; ++ ++ input += POLY1305_BLOCK_SIZE; ++ } while (--nblocks); ++ ++ state->h[0] = h0; ++ state->h[1] = h1; ++ state->h[2] = h2; ++ state->h[3] = h3; ++ state->h[4] = h4; ++} ++EXPORT_SYMBOL(poly1305_core_blocks); ++ ++void poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4], ++ void *dst) ++{ ++ u8 *mac = dst; ++ u32 h0, h1, h2, h3, h4, c; ++ u32 g0, g1, g2, g3, g4; ++ u64 f; ++ u32 mask; ++ ++ /* fully carry h */ ++ h0 = state->h[0]; ++ h1 = state->h[1]; ++ h2 = state->h[2]; ++ h3 = state->h[3]; ++ h4 = state->h[4]; ++ ++ c = h1 >> 26; ++ h1 = h1 & 0x3ffffff; ++ h2 += c; ++ c = h2 >> 26; ++ h2 = h2 & 0x3ffffff; ++ h3 += c; ++ c = h3 >> 26; ++ h3 = h3 & 0x3ffffff; ++ h4 += c; ++ c = h4 >> 26; ++ h4 = h4 & 0x3ffffff; ++ h0 += c * 5; ++ c = h0 >> 26; ++ h0 = h0 & 0x3ffffff; ++ h1 += c; ++ ++ /* compute h + -p */ ++ g0 = h0 + 5; ++ c = g0 >> 26; ++ g0 &= 0x3ffffff; ++ g1 = h1 + c; ++ c = g1 >> 26; ++ g1 &= 0x3ffffff; ++ g2 = h2 + c; ++ c = g2 >> 26; ++ g2 &= 0x3ffffff; ++ g3 = h3 + c; ++ c = g3 >> 26; ++ g3 &= 0x3ffffff; ++ g4 = h4 + c - (1UL << 26); ++ ++ /* select h if h < p, or h + -p if h >= p */ ++ mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; ++ g0 &= mask; ++ g1 &= mask; ++ g2 &= mask; ++ g3 &= mask; ++ g4 &= mask; ++ mask = ~mask; ++ ++ h0 = (h0 & mask) | g0; ++ h1 = (h1 & mask) | g1; ++ h2 = (h2 & mask) | g2; ++ h3 = (h3 & mask) | g3; ++ h4 = (h4 & mask) | g4; ++ ++ /* h = h % (2^128) */ ++ h0 = ((h0) | (h1 << 26)) & 0xffffffff; ++ h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; ++ h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; ++ h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; ++ ++ if (likely(nonce)) { ++ /* mac = (h + nonce) % (2^128) */ ++ f = (u64)h0 + nonce[0]; ++ h0 = (u32)f; ++ f = (u64)h1 + nonce[1] + (f >> 32); ++ h1 = (u32)f; ++ f = (u64)h2 + nonce[2] + (f >> 32); ++ h2 = (u32)f; ++ f = (u64)h3 + nonce[3] + (f >> 32); ++ h3 = (u32)f; ++ } ++ ++ put_unaligned_le32(h0, &mac[0]); ++ put_unaligned_le32(h1, &mac[4]); ++ put_unaligned_le32(h2, &mac[8]); ++ put_unaligned_le32(h3, &mac[12]); ++} ++EXPORT_SYMBOL(poly1305_core_emit); +--- /dev/null ++++ b/lib/crypto/poly1305-donna64.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is based in part on Andrew Moon's poly1305-donna, which is in the ++ * public domain. ++ */ ++ ++#include ++#include ++#include ++ ++typedef __uint128_t u128; ++ ++void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16]) ++{ ++ u64 t0, t1; ++ ++ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ ++ t0 = get_unaligned_le64(&raw_key[0]); ++ t1 = get_unaligned_le64(&raw_key[8]); ++ ++ key->key.r64[0] = t0 & 0xffc0fffffffULL; ++ key->key.r64[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffffULL; ++ key->key.r64[2] = ((t1 >> 24)) & 0x00ffffffc0fULL; ++ ++ /* s = 20*r */ ++ key->precomputed_s.r64[0] = key->key.r64[1] * 20; ++ key->precomputed_s.r64[1] = key->key.r64[2] * 20; ++} ++EXPORT_SYMBOL(poly1305_core_setkey); ++ ++void poly1305_core_blocks(struct poly1305_state *state, ++ const struct poly1305_core_key *key, const void *src, ++ unsigned int nblocks, u32 hibit) ++{ ++ const u8 *input = src; ++ u64 hibit64; ++ u64 r0, r1, r2; ++ u64 s1, s2; ++ u64 h0, h1, h2; ++ u64 c; ++ u128 d0, d1, d2, d; ++ ++ if (!nblocks) ++ return; ++ ++ hibit64 = ((u64)hibit) << 40; ++ ++ r0 = key->key.r64[0]; ++ r1 = key->key.r64[1]; ++ r2 = key->key.r64[2]; ++ ++ h0 = state->h64[0]; ++ h1 = state->h64[1]; ++ h2 = state->h64[2]; ++ ++ s1 = key->precomputed_s.r64[0]; ++ s2 = key->precomputed_s.r64[1]; ++ ++ do { ++ u64 t0, t1; ++ ++ /* h += m[i] */ ++ t0 = get_unaligned_le64(&input[0]); ++ t1 = get_unaligned_le64(&input[8]); ++ ++ h0 += t0 & 0xfffffffffffULL; ++ h1 += ((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL; ++ h2 += (((t1 >> 24)) & 0x3ffffffffffULL) | hibit64; ++ ++ /* h *= r */ ++ d0 = (u128)h0 * r0; ++ d = (u128)h1 * s2; ++ d0 += d; ++ d = (u128)h2 * s1; ++ d0 += d; ++ d1 = (u128)h0 * r1; ++ d = (u128)h1 * r0; ++ d1 += d; ++ d = (u128)h2 * s2; ++ d1 += d; ++ d2 = (u128)h0 * r2; ++ d = (u128)h1 * r1; ++ d2 += d; ++ d = (u128)h2 * r0; ++ d2 += d; ++ ++ /* (partial) h %= p */ ++ c = (u64)(d0 >> 44); ++ h0 = (u64)d0 & 0xfffffffffffULL; ++ d1 += c; ++ c = (u64)(d1 >> 44); ++ h1 = (u64)d1 & 0xfffffffffffULL; ++ d2 += c; ++ c = (u64)(d2 >> 42); ++ h2 = (u64)d2 & 0x3ffffffffffULL; ++ h0 += c * 5; ++ c = h0 >> 44; ++ h0 = h0 & 0xfffffffffffULL; ++ h1 += c; ++ ++ input += POLY1305_BLOCK_SIZE; ++ } while (--nblocks); ++ ++ state->h64[0] = h0; ++ state->h64[1] = h1; ++ state->h64[2] = h2; ++} ++EXPORT_SYMBOL(poly1305_core_blocks); ++ ++void poly1305_core_emit(const struct poly1305_state *state, const u32 nonce[4], ++ void *dst) ++{ ++ u8 *mac = dst; ++ u64 h0, h1, h2, c; ++ u64 g0, g1, g2; ++ u64 t0, t1; ++ ++ /* fully carry h */ ++ h0 = state->h64[0]; ++ h1 = state->h64[1]; ++ h2 = state->h64[2]; ++ ++ c = h1 >> 44; ++ h1 &= 0xfffffffffffULL; ++ h2 += c; ++ c = h2 >> 42; ++ h2 &= 0x3ffffffffffULL; ++ h0 += c * 5; ++ c = h0 >> 44; ++ h0 &= 0xfffffffffffULL; ++ h1 += c; ++ c = h1 >> 44; ++ h1 &= 0xfffffffffffULL; ++ h2 += c; ++ c = h2 >> 42; ++ h2 &= 0x3ffffffffffULL; ++ h0 += c * 5; ++ c = h0 >> 44; ++ h0 &= 0xfffffffffffULL; ++ h1 += c; ++ ++ /* compute h + -p */ ++ g0 = h0 + 5; ++ c = g0 >> 44; ++ g0 &= 0xfffffffffffULL; ++ g1 = h1 + c; ++ c = g1 >> 44; ++ g1 &= 0xfffffffffffULL; ++ g2 = h2 + c - (1ULL << 42); ++ ++ /* select h if h < p, or h + -p if h >= p */ ++ c = (g2 >> ((sizeof(u64) * 8) - 1)) - 1; ++ g0 &= c; ++ g1 &= c; ++ g2 &= c; ++ c = ~c; ++ h0 = (h0 & c) | g0; ++ h1 = (h1 & c) | g1; ++ h2 = (h2 & c) | g2; ++ ++ if (likely(nonce)) { ++ /* h = (h + nonce) */ ++ t0 = ((u64)nonce[1] << 32) | nonce[0]; ++ t1 = ((u64)nonce[3] << 32) | nonce[2]; ++ ++ h0 += t0 & 0xfffffffffffULL; ++ c = h0 >> 44; ++ h0 &= 0xfffffffffffULL; ++ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffffULL) + c; ++ c = h1 >> 44; ++ h1 &= 0xfffffffffffULL; ++ h2 += (((t1 >> 24)) & 0x3ffffffffffULL) + c; ++ h2 &= 0x3ffffffffffULL; ++ } ++ ++ /* mac = h % (2^128) */ ++ h0 = h0 | (h1 << 44); ++ h1 = (h1 >> 20) | (h2 << 24); ++ ++ put_unaligned_le64(h0, &mac[0]); ++ put_unaligned_le64(h1, &mac[8]); ++} ++EXPORT_SYMBOL(poly1305_core_emit); +--- a/lib/crypto/poly1305.c ++++ b/lib/crypto/poly1305.c +@@ -12,151 +12,9 @@ + #include + #include + +-static inline u64 mlt(u64 a, u64 b) +-{ +- return a * b; +-} +- +-static inline u32 sr(u64 v, u_char n) +-{ +- return v >> n; +-} +- +-static inline u32 and(u32 v, u32 mask) +-{ +- return v & mask; +-} +- +-void poly1305_core_setkey(struct poly1305_key *key, const u8 *raw_key) +-{ +- /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ +- key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff; +- key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03; +- key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff; +- key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff; +- key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff; +-} +-EXPORT_SYMBOL_GPL(poly1305_core_setkey); +- +-void poly1305_core_blocks(struct poly1305_state *state, +- const struct poly1305_key *key, const void *src, +- unsigned int nblocks, u32 hibit) +-{ +- u32 r0, r1, r2, r3, r4; +- u32 s1, s2, s3, s4; +- u32 h0, h1, h2, h3, h4; +- u64 d0, d1, d2, d3, d4; +- +- if (!nblocks) +- return; +- +- r0 = key->r[0]; +- r1 = key->r[1]; +- r2 = key->r[2]; +- r3 = key->r[3]; +- r4 = key->r[4]; +- +- s1 = r1 * 5; +- s2 = r2 * 5; +- s3 = r3 * 5; +- s4 = r4 * 5; +- +- h0 = state->h[0]; +- h1 = state->h[1]; +- h2 = state->h[2]; +- h3 = state->h[3]; +- h4 = state->h[4]; +- +- do { +- /* h += m[i] */ +- h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff; +- h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; +- h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff; +- h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff; +- h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24); +- +- /* h *= r */ +- d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + +- mlt(h3, s2) + mlt(h4, s1); +- d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + +- mlt(h3, s3) + mlt(h4, s2); +- d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + +- mlt(h3, s4) + mlt(h4, s3); +- d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + +- mlt(h3, r0) + mlt(h4, s4); +- d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + +- mlt(h3, r1) + mlt(h4, r0); +- +- /* (partial) h %= p */ +- d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff); +- d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff); +- d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff); +- d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff); +- h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff); +- h1 += h0 >> 26; h0 = h0 & 0x3ffffff; +- +- src += POLY1305_BLOCK_SIZE; +- } while (--nblocks); +- +- state->h[0] = h0; +- state->h[1] = h1; +- state->h[2] = h2; +- state->h[3] = h3; +- state->h[4] = h4; +-} +-EXPORT_SYMBOL_GPL(poly1305_core_blocks); +- +-void poly1305_core_emit(const struct poly1305_state *state, void *dst) +-{ +- u32 h0, h1, h2, h3, h4; +- u32 g0, g1, g2, g3, g4; +- u32 mask; +- +- /* fully carry h */ +- h0 = state->h[0]; +- h1 = state->h[1]; +- h2 = state->h[2]; +- h3 = state->h[3]; +- h4 = state->h[4]; +- +- h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; +- h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; +- h4 += (h3 >> 26); h3 = h3 & 0x3ffffff; +- h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff; +- h1 += (h0 >> 26); h0 = h0 & 0x3ffffff; +- +- /* compute h + -p */ +- g0 = h0 + 5; +- g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff; +- g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff; +- g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff; +- g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff; +- +- /* select h if h < p, or h + -p if h >= p */ +- mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; +- g0 &= mask; +- g1 &= mask; +- g2 &= mask; +- g3 &= mask; +- g4 &= mask; +- mask = ~mask; +- h0 = (h0 & mask) | g0; +- h1 = (h1 & mask) | g1; +- h2 = (h2 & mask) | g2; +- h3 = (h3 & mask) | g3; +- h4 = (h4 & mask) | g4; +- +- /* h = h % (2^128) */ +- put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0); +- put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4); +- put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8); +- put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12); +-} +-EXPORT_SYMBOL_GPL(poly1305_core_emit); +- + void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key) + { +- poly1305_core_setkey(desc->r, key); ++ poly1305_core_setkey(&desc->core_r, key); + desc->s[0] = get_unaligned_le32(key + 16); + desc->s[1] = get_unaligned_le32(key + 20); + desc->s[2] = get_unaligned_le32(key + 24); +@@ -164,7 +22,7 @@ void poly1305_init_generic(struct poly13 + poly1305_core_init(&desc->h); + desc->buflen = 0; + desc->sset = true; +- desc->rset = 1; ++ desc->rset = 2; + } + EXPORT_SYMBOL_GPL(poly1305_init_generic); + +@@ -181,13 +39,14 @@ void poly1305_update_generic(struct poly + desc->buflen += bytes; + + if (desc->buflen == POLY1305_BLOCK_SIZE) { +- poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 1); ++ poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf, ++ 1, 1); + desc->buflen = 0; + } + } + + if (likely(nbytes >= POLY1305_BLOCK_SIZE)) { +- poly1305_core_blocks(&desc->h, desc->r, src, ++ poly1305_core_blocks(&desc->h, &desc->core_r, src, + nbytes / POLY1305_BLOCK_SIZE, 1); + src += nbytes - (nbytes % POLY1305_BLOCK_SIZE); + nbytes %= POLY1305_BLOCK_SIZE; +@@ -202,28 +61,14 @@ EXPORT_SYMBOL_GPL(poly1305_update_generi + + void poly1305_final_generic(struct poly1305_desc_ctx *desc, u8 *dst) + { +- __le32 digest[4]; +- u64 f = 0; +- + if (unlikely(desc->buflen)) { + desc->buf[desc->buflen++] = 1; + memset(desc->buf + desc->buflen, 0, + POLY1305_BLOCK_SIZE - desc->buflen); +- poly1305_core_blocks(&desc->h, desc->r, desc->buf, 1, 0); ++ poly1305_core_blocks(&desc->h, &desc->core_r, desc->buf, 1, 0); + } + +- poly1305_core_emit(&desc->h, digest); +- +- /* mac = (h + s) % (2^128) */ +- f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0]; +- put_unaligned_le32(f, dst + 0); +- f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1]; +- put_unaligned_le32(f, dst + 4); +- f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2]; +- put_unaligned_le32(f, dst + 8); +- f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3]; +- put_unaligned_le32(f, dst + 12); +- ++ poly1305_core_emit(&desc->h, desc->s, dst); + *desc = (struct poly1305_desc_ctx){}; + } + EXPORT_SYMBOL_GPL(poly1305_final_generic); diff --git a/ipq806x/backport-5.4/080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch b/ipq806x/backport-5.4/080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch new file mode 100644 index 0000000..8e52383 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0042-crypto-x86-poly1305-import-unmodified-cryptogams-imp.patch @@ -0,0 +1,4183 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 5 Jan 2020 22:40:47 -0500 +Subject: [PATCH] crypto: x86/poly1305 - import unmodified cryptogams + implementation + +commit 0896ca2a0cb6127e8a129f1f2a680d49b6b0f65c upstream. + +These x86_64 vectorized implementations come from Andy Polyakov's +CRYPTOGAMS implementation, and are included here in raw form without +modification, so that subsequent commits that fix these up for the +kernel can see how it has changed. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305-x86_64-cryptogams.pl | 4159 +++++++++++++++++ + 1 file changed, 4159 insertions(+) + create mode 100644 arch/x86/crypto/poly1305-x86_64-cryptogams.pl + +--- /dev/null ++++ b/arch/x86/crypto/poly1305-x86_64-cryptogams.pl +@@ -0,0 +1,4159 @@ ++#! /usr/bin/env perl ++# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. ++# ++# Licensed under the OpenSSL license (the "License"). You may not use ++# this file except in compliance with the License. You can obtain a copy ++# in the file LICENSE in the source distribution or at ++# https://www.openssl.org/source/license.html ++ ++# ++# ==================================================================== ++# Written by Andy Polyakov for the OpenSSL ++# project. The module is, however, dual licensed under OpenSSL and ++# CRYPTOGAMS licenses depending on where you obtain it. For further ++# details see http://www.openssl.org/~appro/cryptogams/. ++# ==================================================================== ++# ++# This module implements Poly1305 hash for x86_64. ++# ++# March 2015 ++# ++# Initial release. ++# ++# December 2016 ++# ++# Add AVX512F+VL+BW code path. ++# ++# November 2017 ++# ++# Convert AVX512F+VL+BW code path to pure AVX512F, so that it can be ++# executed even on Knights Landing. Trigger for modification was ++# observation that AVX512 code paths can negatively affect overall ++# Skylake-X system performance. Since we are likely to suppress ++# AVX512F capability flag [at least on Skylake-X], conversion serves ++# as kind of "investment protection". Note that next *lake processor, ++# Cannolake, has AVX512IFMA code path to execute... ++# ++# Numbers are cycles per processed byte with poly1305_blocks alone, ++# measured with rdtsc at fixed clock frequency. ++# ++# IALU/gcc-4.8(*) AVX(**) AVX2 AVX-512 ++# P4 4.46/+120% - ++# Core 2 2.41/+90% - ++# Westmere 1.88/+120% - ++# Sandy Bridge 1.39/+140% 1.10 ++# Haswell 1.14/+175% 1.11 0.65 ++# Skylake[-X] 1.13/+120% 0.96 0.51 [0.35] ++# Silvermont 2.83/+95% - ++# Knights L 3.60/? 1.65 1.10 0.41(***) ++# Goldmont 1.70/+180% - ++# VIA Nano 1.82/+150% - ++# Sledgehammer 1.38/+160% - ++# Bulldozer 2.30/+130% 0.97 ++# Ryzen 1.15/+200% 1.08 1.18 ++# ++# (*) improvement coefficients relative to clang are more modest and ++# are ~50% on most processors, in both cases we are comparing to ++# __int128 code; ++# (**) SSE2 implementation was attempted, but among non-AVX processors ++# it was faster than integer-only code only on older Intel P4 and ++# Core processors, 50-30%, less newer processor is, but slower on ++# contemporary ones, for example almost 2x slower on Atom, and as ++# former are naturally disappearing, SSE2 is deemed unnecessary; ++# (***) strangely enough performance seems to vary from core to core, ++# listed result is best case; ++ ++$flavour = shift; ++$output = shift; ++if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } ++ ++$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); ++ ++$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; ++( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or ++( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or ++die "can't locate x86_64-xlate.pl"; ++ ++if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` ++ =~ /GNU assembler version ([2-9]\.[0-9]+)/) { ++ $avx = ($1>=2.19) + ($1>=2.22) + ($1>=2.25) + ($1>=2.26); ++} ++ ++if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && ++ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/) { ++ $avx = ($1>=2.09) + ($1>=2.10) + 2 * ($1>=2.12); ++ $avx += 2 if ($1==2.11 && $2>=8); ++} ++ ++if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && ++ `ml64 2>&1` =~ /Version ([0-9]+)\./) { ++ $avx = ($1>=10) + ($1>=12); ++} ++ ++if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) { ++ $avx = ($2>=3.0) + ($2>3.0); ++} ++ ++open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""; ++*STDOUT=*OUT; ++ ++my ($ctx,$inp,$len,$padbit)=("%rdi","%rsi","%rdx","%rcx"); ++my ($mac,$nonce)=($inp,$len); # *_emit arguments ++my ($d1,$d2,$d3, $r0,$r1,$s1)=map("%r$_",(8..13)); ++my ($h0,$h1,$h2)=("%r14","%rbx","%rbp"); ++ ++sub poly1305_iteration { ++# input: copy of $r1 in %rax, $h0-$h2, $r0-$r1 ++# output: $h0-$h2 *= $r0-$r1 ++$code.=<<___; ++ mulq $h0 # h0*r1 ++ mov %rax,$d2 ++ mov $r0,%rax ++ mov %rdx,$d3 ++ ++ mulq $h0 # h0*r0 ++ mov %rax,$h0 # future $h0 ++ mov $r0,%rax ++ mov %rdx,$d1 ++ ++ mulq $h1 # h1*r0 ++ add %rax,$d2 ++ mov $s1,%rax ++ adc %rdx,$d3 ++ ++ mulq $h1 # h1*s1 ++ mov $h2,$h1 # borrow $h1 ++ add %rax,$h0 ++ adc %rdx,$d1 ++ ++ imulq $s1,$h1 # h2*s1 ++ add $h1,$d2 ++ mov $d1,$h1 ++ adc \$0,$d3 ++ ++ imulq $r0,$h2 # h2*r0 ++ add $d2,$h1 ++ mov \$-4,%rax # mask value ++ adc $h2,$d3 ++ ++ and $d3,%rax # last reduction step ++ mov $d3,$h2 ++ shr \$2,$d3 ++ and \$3,$h2 ++ add $d3,%rax ++ add %rax,$h0 ++ adc \$0,$h1 ++ adc \$0,$h2 ++___ ++} ++ ++######################################################################## ++# Layout of opaque area is following. ++# ++# unsigned __int64 h[3]; # current hash value base 2^64 ++# unsigned __int64 r[2]; # key value base 2^64 ++ ++$code.=<<___; ++.text ++ ++.extern OPENSSL_ia32cap_P ++ ++.globl poly1305_init ++.hidden poly1305_init ++.globl poly1305_blocks ++.hidden poly1305_blocks ++.globl poly1305_emit ++.hidden poly1305_emit ++ ++.type poly1305_init,\@function,3 ++.align 32 ++poly1305_init: ++ xor %rax,%rax ++ mov %rax,0($ctx) # initialize hash value ++ mov %rax,8($ctx) ++ mov %rax,16($ctx) ++ ++ cmp \$0,$inp ++ je .Lno_key ++ ++ lea poly1305_blocks(%rip),%r10 ++ lea poly1305_emit(%rip),%r11 ++___ ++$code.=<<___ if ($avx); ++ mov OPENSSL_ia32cap_P+4(%rip),%r9 ++ lea poly1305_blocks_avx(%rip),%rax ++ lea poly1305_emit_avx(%rip),%rcx ++ bt \$`60-32`,%r9 # AVX? ++ cmovc %rax,%r10 ++ cmovc %rcx,%r11 ++___ ++$code.=<<___ if ($avx>1); ++ lea poly1305_blocks_avx2(%rip),%rax ++ bt \$`5+32`,%r9 # AVX2? ++ cmovc %rax,%r10 ++___ ++$code.=<<___ if ($avx>3); ++ mov \$`(1<<31|1<<21|1<<16)`,%rax ++ shr \$32,%r9 ++ and %rax,%r9 ++ cmp %rax,%r9 ++ je .Linit_base2_44 ++___ ++$code.=<<___; ++ mov \$0x0ffffffc0fffffff,%rax ++ mov \$0x0ffffffc0ffffffc,%rcx ++ and 0($inp),%rax ++ and 8($inp),%rcx ++ mov %rax,24($ctx) ++ mov %rcx,32($ctx) ++___ ++$code.=<<___ if ($flavour !~ /elf32/); ++ mov %r10,0(%rdx) ++ mov %r11,8(%rdx) ++___ ++$code.=<<___ if ($flavour =~ /elf32/); ++ mov %r10d,0(%rdx) ++ mov %r11d,4(%rdx) ++___ ++$code.=<<___; ++ mov \$1,%eax ++.Lno_key: ++ ret ++.size poly1305_init,.-poly1305_init ++ ++.type poly1305_blocks,\@function,4 ++.align 32 ++poly1305_blocks: ++.cfi_startproc ++.Lblocks: ++ shr \$4,$len ++ jz .Lno_data # too short ++ ++ push %rbx ++.cfi_push %rbx ++ push %rbp ++.cfi_push %rbp ++ push %r12 ++.cfi_push %r12 ++ push %r13 ++.cfi_push %r13 ++ push %r14 ++.cfi_push %r14 ++ push %r15 ++.cfi_push %r15 ++.Lblocks_body: ++ ++ mov $len,%r15 # reassign $len ++ ++ mov 24($ctx),$r0 # load r ++ mov 32($ctx),$s1 ++ ++ mov 0($ctx),$h0 # load hash value ++ mov 8($ctx),$h1 ++ mov 16($ctx),$h2 ++ ++ mov $s1,$r1 ++ shr \$2,$s1 ++ mov $r1,%rax ++ add $r1,$s1 # s1 = r1 + (r1 >> 2) ++ jmp .Loop ++ ++.align 32 ++.Loop: ++ add 0($inp),$h0 # accumulate input ++ adc 8($inp),$h1 ++ lea 16($inp),$inp ++ adc $padbit,$h2 ++___ ++ &poly1305_iteration(); ++$code.=<<___; ++ mov $r1,%rax ++ dec %r15 # len-=16 ++ jnz .Loop ++ ++ mov $h0,0($ctx) # store hash value ++ mov $h1,8($ctx) ++ mov $h2,16($ctx) ++ ++ mov 0(%rsp),%r15 ++.cfi_restore %r15 ++ mov 8(%rsp),%r14 ++.cfi_restore %r14 ++ mov 16(%rsp),%r13 ++.cfi_restore %r13 ++ mov 24(%rsp),%r12 ++.cfi_restore %r12 ++ mov 32(%rsp),%rbp ++.cfi_restore %rbp ++ mov 40(%rsp),%rbx ++.cfi_restore %rbx ++ lea 48(%rsp),%rsp ++.cfi_adjust_cfa_offset -48 ++.Lno_data: ++.Lblocks_epilogue: ++ ret ++.cfi_endproc ++.size poly1305_blocks,.-poly1305_blocks ++ ++.type poly1305_emit,\@function,3 ++.align 32 ++poly1305_emit: ++.Lemit: ++ mov 0($ctx),%r8 # load hash value ++ mov 8($ctx),%r9 ++ mov 16($ctx),%r10 ++ ++ mov %r8,%rax ++ add \$5,%r8 # compare to modulus ++ mov %r9,%rcx ++ adc \$0,%r9 ++ adc \$0,%r10 ++ shr \$2,%r10 # did 130-bit value overflow? ++ cmovnz %r8,%rax ++ cmovnz %r9,%rcx ++ ++ add 0($nonce),%rax # accumulate nonce ++ adc 8($nonce),%rcx ++ mov %rax,0($mac) # write result ++ mov %rcx,8($mac) ++ ++ ret ++.size poly1305_emit,.-poly1305_emit ++___ ++if ($avx) { ++ ++######################################################################## ++# Layout of opaque area is following. ++# ++# unsigned __int32 h[5]; # current hash value base 2^26 ++# unsigned __int32 is_base2_26; ++# unsigned __int64 r[2]; # key value base 2^64 ++# unsigned __int64 pad; ++# struct { unsigned __int32 r^2, r^1, r^4, r^3; } r[9]; ++# ++# where r^n are base 2^26 digits of degrees of multiplier key. There are ++# 5 digits, but last four are interleaved with multiples of 5, totalling ++# in 9 elements: r0, r1, 5*r1, r2, 5*r2, r3, 5*r3, r4, 5*r4. ++ ++my ($H0,$H1,$H2,$H3,$H4, $T0,$T1,$T2,$T3,$T4, $D0,$D1,$D2,$D3,$D4, $MASK) = ++ map("%xmm$_",(0..15)); ++ ++$code.=<<___; ++.type __poly1305_block,\@abi-omnipotent ++.align 32 ++__poly1305_block: ++___ ++ &poly1305_iteration(); ++$code.=<<___; ++ ret ++.size __poly1305_block,.-__poly1305_block ++ ++.type __poly1305_init_avx,\@abi-omnipotent ++.align 32 ++__poly1305_init_avx: ++ mov $r0,$h0 ++ mov $r1,$h1 ++ xor $h2,$h2 ++ ++ lea 48+64($ctx),$ctx # size optimization ++ ++ mov $r1,%rax ++ call __poly1305_block # r^2 ++ ++ mov \$0x3ffffff,%eax # save interleaved r^2 and r base 2^26 ++ mov \$0x3ffffff,%edx ++ mov $h0,$d1 ++ and $h0#d,%eax ++ mov $r0,$d2 ++ and $r0#d,%edx ++ mov %eax,`16*0+0-64`($ctx) ++ shr \$26,$d1 ++ mov %edx,`16*0+4-64`($ctx) ++ shr \$26,$d2 ++ ++ mov \$0x3ffffff,%eax ++ mov \$0x3ffffff,%edx ++ and $d1#d,%eax ++ and $d2#d,%edx ++ mov %eax,`16*1+0-64`($ctx) ++ lea (%rax,%rax,4),%eax # *5 ++ mov %edx,`16*1+4-64`($ctx) ++ lea (%rdx,%rdx,4),%edx # *5 ++ mov %eax,`16*2+0-64`($ctx) ++ shr \$26,$d1 ++ mov %edx,`16*2+4-64`($ctx) ++ shr \$26,$d2 ++ ++ mov $h1,%rax ++ mov $r1,%rdx ++ shl \$12,%rax ++ shl \$12,%rdx ++ or $d1,%rax ++ or $d2,%rdx ++ and \$0x3ffffff,%eax ++ and \$0x3ffffff,%edx ++ mov %eax,`16*3+0-64`($ctx) ++ lea (%rax,%rax,4),%eax # *5 ++ mov %edx,`16*3+4-64`($ctx) ++ lea (%rdx,%rdx,4),%edx # *5 ++ mov %eax,`16*4+0-64`($ctx) ++ mov $h1,$d1 ++ mov %edx,`16*4+4-64`($ctx) ++ mov $r1,$d2 ++ ++ mov \$0x3ffffff,%eax ++ mov \$0x3ffffff,%edx ++ shr \$14,$d1 ++ shr \$14,$d2 ++ and $d1#d,%eax ++ and $d2#d,%edx ++ mov %eax,`16*5+0-64`($ctx) ++ lea (%rax,%rax,4),%eax # *5 ++ mov %edx,`16*5+4-64`($ctx) ++ lea (%rdx,%rdx,4),%edx # *5 ++ mov %eax,`16*6+0-64`($ctx) ++ shr \$26,$d1 ++ mov %edx,`16*6+4-64`($ctx) ++ shr \$26,$d2 ++ ++ mov $h2,%rax ++ shl \$24,%rax ++ or %rax,$d1 ++ mov $d1#d,`16*7+0-64`($ctx) ++ lea ($d1,$d1,4),$d1 # *5 ++ mov $d2#d,`16*7+4-64`($ctx) ++ lea ($d2,$d2,4),$d2 # *5 ++ mov $d1#d,`16*8+0-64`($ctx) ++ mov $d2#d,`16*8+4-64`($ctx) ++ ++ mov $r1,%rax ++ call __poly1305_block # r^3 ++ ++ mov \$0x3ffffff,%eax # save r^3 base 2^26 ++ mov $h0,$d1 ++ and $h0#d,%eax ++ shr \$26,$d1 ++ mov %eax,`16*0+12-64`($ctx) ++ ++ mov \$0x3ffffff,%edx ++ and $d1#d,%edx ++ mov %edx,`16*1+12-64`($ctx) ++ lea (%rdx,%rdx,4),%edx # *5 ++ shr \$26,$d1 ++ mov %edx,`16*2+12-64`($ctx) ++ ++ mov $h1,%rax ++ shl \$12,%rax ++ or $d1,%rax ++ and \$0x3ffffff,%eax ++ mov %eax,`16*3+12-64`($ctx) ++ lea (%rax,%rax,4),%eax # *5 ++ mov $h1,$d1 ++ mov %eax,`16*4+12-64`($ctx) ++ ++ mov \$0x3ffffff,%edx ++ shr \$14,$d1 ++ and $d1#d,%edx ++ mov %edx,`16*5+12-64`($ctx) ++ lea (%rdx,%rdx,4),%edx # *5 ++ shr \$26,$d1 ++ mov %edx,`16*6+12-64`($ctx) ++ ++ mov $h2,%rax ++ shl \$24,%rax ++ or %rax,$d1 ++ mov $d1#d,`16*7+12-64`($ctx) ++ lea ($d1,$d1,4),$d1 # *5 ++ mov $d1#d,`16*8+12-64`($ctx) ++ ++ mov $r1,%rax ++ call __poly1305_block # r^4 ++ ++ mov \$0x3ffffff,%eax # save r^4 base 2^26 ++ mov $h0,$d1 ++ and $h0#d,%eax ++ shr \$26,$d1 ++ mov %eax,`16*0+8-64`($ctx) ++ ++ mov \$0x3ffffff,%edx ++ and $d1#d,%edx ++ mov %edx,`16*1+8-64`($ctx) ++ lea (%rdx,%rdx,4),%edx # *5 ++ shr \$26,$d1 ++ mov %edx,`16*2+8-64`($ctx) ++ ++ mov $h1,%rax ++ shl \$12,%rax ++ or $d1,%rax ++ and \$0x3ffffff,%eax ++ mov %eax,`16*3+8-64`($ctx) ++ lea (%rax,%rax,4),%eax # *5 ++ mov $h1,$d1 ++ mov %eax,`16*4+8-64`($ctx) ++ ++ mov \$0x3ffffff,%edx ++ shr \$14,$d1 ++ and $d1#d,%edx ++ mov %edx,`16*5+8-64`($ctx) ++ lea (%rdx,%rdx,4),%edx # *5 ++ shr \$26,$d1 ++ mov %edx,`16*6+8-64`($ctx) ++ ++ mov $h2,%rax ++ shl \$24,%rax ++ or %rax,$d1 ++ mov $d1#d,`16*7+8-64`($ctx) ++ lea ($d1,$d1,4),$d1 # *5 ++ mov $d1#d,`16*8+8-64`($ctx) ++ ++ lea -48-64($ctx),$ctx # size [de-]optimization ++ ret ++.size __poly1305_init_avx,.-__poly1305_init_avx ++ ++.type poly1305_blocks_avx,\@function,4 ++.align 32 ++poly1305_blocks_avx: ++.cfi_startproc ++ mov 20($ctx),%r8d # is_base2_26 ++ cmp \$128,$len ++ jae .Lblocks_avx ++ test %r8d,%r8d ++ jz .Lblocks ++ ++.Lblocks_avx: ++ and \$-16,$len ++ jz .Lno_data_avx ++ ++ vzeroupper ++ ++ test %r8d,%r8d ++ jz .Lbase2_64_avx ++ ++ test \$31,$len ++ jz .Leven_avx ++ ++ push %rbx ++.cfi_push %rbx ++ push %rbp ++.cfi_push %rbp ++ push %r12 ++.cfi_push %r12 ++ push %r13 ++.cfi_push %r13 ++ push %r14 ++.cfi_push %r14 ++ push %r15 ++.cfi_push %r15 ++.Lblocks_avx_body: ++ ++ mov $len,%r15 # reassign $len ++ ++ mov 0($ctx),$d1 # load hash value ++ mov 8($ctx),$d2 ++ mov 16($ctx),$h2#d ++ ++ mov 24($ctx),$r0 # load r ++ mov 32($ctx),$s1 ++ ++ ################################# base 2^26 -> base 2^64 ++ mov $d1#d,$h0#d ++ and \$`-1*(1<<31)`,$d1 ++ mov $d2,$r1 # borrow $r1 ++ mov $d2#d,$h1#d ++ and \$`-1*(1<<31)`,$d2 ++ ++ shr \$6,$d1 ++ shl \$52,$r1 ++ add $d1,$h0 ++ shr \$12,$h1 ++ shr \$18,$d2 ++ add $r1,$h0 ++ adc $d2,$h1 ++ ++ mov $h2,$d1 ++ shl \$40,$d1 ++ shr \$24,$h2 ++ add $d1,$h1 ++ adc \$0,$h2 # can be partially reduced... ++ ++ mov \$-4,$d2 # ... so reduce ++ mov $h2,$d1 ++ and $h2,$d2 ++ shr \$2,$d1 ++ and \$3,$h2 ++ add $d2,$d1 # =*5 ++ add $d1,$h0 ++ adc \$0,$h1 ++ adc \$0,$h2 ++ ++ mov $s1,$r1 ++ mov $s1,%rax ++ shr \$2,$s1 ++ add $r1,$s1 # s1 = r1 + (r1 >> 2) ++ ++ add 0($inp),$h0 # accumulate input ++ adc 8($inp),$h1 ++ lea 16($inp),$inp ++ adc $padbit,$h2 ++ ++ call __poly1305_block ++ ++ test $padbit,$padbit # if $padbit is zero, ++ jz .Lstore_base2_64_avx # store hash in base 2^64 format ++ ++ ################################# base 2^64 -> base 2^26 ++ mov $h0,%rax ++ mov $h0,%rdx ++ shr \$52,$h0 ++ mov $h1,$r0 ++ mov $h1,$r1 ++ shr \$26,%rdx ++ and \$0x3ffffff,%rax # h[0] ++ shl \$12,$r0 ++ and \$0x3ffffff,%rdx # h[1] ++ shr \$14,$h1 ++ or $r0,$h0 ++ shl \$24,$h2 ++ and \$0x3ffffff,$h0 # h[2] ++ shr \$40,$r1 ++ and \$0x3ffffff,$h1 # h[3] ++ or $r1,$h2 # h[4] ++ ++ sub \$16,%r15 ++ jz .Lstore_base2_26_avx ++ ++ vmovd %rax#d,$H0 ++ vmovd %rdx#d,$H1 ++ vmovd $h0#d,$H2 ++ vmovd $h1#d,$H3 ++ vmovd $h2#d,$H4 ++ jmp .Lproceed_avx ++ ++.align 32 ++.Lstore_base2_64_avx: ++ mov $h0,0($ctx) ++ mov $h1,8($ctx) ++ mov $h2,16($ctx) # note that is_base2_26 is zeroed ++ jmp .Ldone_avx ++ ++.align 16 ++.Lstore_base2_26_avx: ++ mov %rax#d,0($ctx) # store hash value base 2^26 ++ mov %rdx#d,4($ctx) ++ mov $h0#d,8($ctx) ++ mov $h1#d,12($ctx) ++ mov $h2#d,16($ctx) ++.align 16 ++.Ldone_avx: ++ mov 0(%rsp),%r15 ++.cfi_restore %r15 ++ mov 8(%rsp),%r14 ++.cfi_restore %r14 ++ mov 16(%rsp),%r13 ++.cfi_restore %r13 ++ mov 24(%rsp),%r12 ++.cfi_restore %r12 ++ mov 32(%rsp),%rbp ++.cfi_restore %rbp ++ mov 40(%rsp),%rbx ++.cfi_restore %rbx ++ lea 48(%rsp),%rsp ++.cfi_adjust_cfa_offset -48 ++.Lno_data_avx: ++.Lblocks_avx_epilogue: ++ ret ++.cfi_endproc ++ ++.align 32 ++.Lbase2_64_avx: ++.cfi_startproc ++ push %rbx ++.cfi_push %rbx ++ push %rbp ++.cfi_push %rbp ++ push %r12 ++.cfi_push %r12 ++ push %r13 ++.cfi_push %r13 ++ push %r14 ++.cfi_push %r14 ++ push %r15 ++.cfi_push %r15 ++.Lbase2_64_avx_body: ++ ++ mov $len,%r15 # reassign $len ++ ++ mov 24($ctx),$r0 # load r ++ mov 32($ctx),$s1 ++ ++ mov 0($ctx),$h0 # load hash value ++ mov 8($ctx),$h1 ++ mov 16($ctx),$h2#d ++ ++ mov $s1,$r1 ++ mov $s1,%rax ++ shr \$2,$s1 ++ add $r1,$s1 # s1 = r1 + (r1 >> 2) ++ ++ test \$31,$len ++ jz .Linit_avx ++ ++ add 0($inp),$h0 # accumulate input ++ adc 8($inp),$h1 ++ lea 16($inp),$inp ++ adc $padbit,$h2 ++ sub \$16,%r15 ++ ++ call __poly1305_block ++ ++.Linit_avx: ++ ################################# base 2^64 -> base 2^26 ++ mov $h0,%rax ++ mov $h0,%rdx ++ shr \$52,$h0 ++ mov $h1,$d1 ++ mov $h1,$d2 ++ shr \$26,%rdx ++ and \$0x3ffffff,%rax # h[0] ++ shl \$12,$d1 ++ and \$0x3ffffff,%rdx # h[1] ++ shr \$14,$h1 ++ or $d1,$h0 ++ shl \$24,$h2 ++ and \$0x3ffffff,$h0 # h[2] ++ shr \$40,$d2 ++ and \$0x3ffffff,$h1 # h[3] ++ or $d2,$h2 # h[4] ++ ++ vmovd %rax#d,$H0 ++ vmovd %rdx#d,$H1 ++ vmovd $h0#d,$H2 ++ vmovd $h1#d,$H3 ++ vmovd $h2#d,$H4 ++ movl \$1,20($ctx) # set is_base2_26 ++ ++ call __poly1305_init_avx ++ ++.Lproceed_avx: ++ mov %r15,$len ++ ++ mov 0(%rsp),%r15 ++.cfi_restore %r15 ++ mov 8(%rsp),%r14 ++.cfi_restore %r14 ++ mov 16(%rsp),%r13 ++.cfi_restore %r13 ++ mov 24(%rsp),%r12 ++.cfi_restore %r12 ++ mov 32(%rsp),%rbp ++.cfi_restore %rbp ++ mov 40(%rsp),%rbx ++.cfi_restore %rbx ++ lea 48(%rsp),%rax ++ lea 48(%rsp),%rsp ++.cfi_adjust_cfa_offset -48 ++.Lbase2_64_avx_epilogue: ++ jmp .Ldo_avx ++.cfi_endproc ++ ++.align 32 ++.Leven_avx: ++.cfi_startproc ++ vmovd 4*0($ctx),$H0 # load hash value ++ vmovd 4*1($ctx),$H1 ++ vmovd 4*2($ctx),$H2 ++ vmovd 4*3($ctx),$H3 ++ vmovd 4*4($ctx),$H4 ++ ++.Ldo_avx: ++___ ++$code.=<<___ if (!$win64); ++ lea -0x58(%rsp),%r11 ++.cfi_def_cfa %r11,0x60 ++ sub \$0x178,%rsp ++___ ++$code.=<<___ if ($win64); ++ lea -0xf8(%rsp),%r11 ++ sub \$0x218,%rsp ++ vmovdqa %xmm6,0x50(%r11) ++ vmovdqa %xmm7,0x60(%r11) ++ vmovdqa %xmm8,0x70(%r11) ++ vmovdqa %xmm9,0x80(%r11) ++ vmovdqa %xmm10,0x90(%r11) ++ vmovdqa %xmm11,0xa0(%r11) ++ vmovdqa %xmm12,0xb0(%r11) ++ vmovdqa %xmm13,0xc0(%r11) ++ vmovdqa %xmm14,0xd0(%r11) ++ vmovdqa %xmm15,0xe0(%r11) ++.Ldo_avx_body: ++___ ++$code.=<<___; ++ sub \$64,$len ++ lea -32($inp),%rax ++ cmovc %rax,$inp ++ ++ vmovdqu `16*3`($ctx),$D4 # preload r0^2 ++ lea `16*3+64`($ctx),$ctx # size optimization ++ lea .Lconst(%rip),%rcx ++ ++ ################################################################ ++ # load input ++ vmovdqu 16*2($inp),$T0 ++ vmovdqu 16*3($inp),$T1 ++ vmovdqa 64(%rcx),$MASK # .Lmask26 ++ ++ vpsrldq \$6,$T0,$T2 # splat input ++ vpsrldq \$6,$T1,$T3 ++ vpunpckhqdq $T1,$T0,$T4 # 4 ++ vpunpcklqdq $T1,$T0,$T0 # 0:1 ++ vpunpcklqdq $T3,$T2,$T3 # 2:3 ++ ++ vpsrlq \$40,$T4,$T4 # 4 ++ vpsrlq \$26,$T0,$T1 ++ vpand $MASK,$T0,$T0 # 0 ++ vpsrlq \$4,$T3,$T2 ++ vpand $MASK,$T1,$T1 # 1 ++ vpsrlq \$30,$T3,$T3 ++ vpand $MASK,$T2,$T2 # 2 ++ vpand $MASK,$T3,$T3 # 3 ++ vpor 32(%rcx),$T4,$T4 # padbit, yes, always ++ ++ jbe .Lskip_loop_avx ++ ++ # expand and copy pre-calculated table to stack ++ vmovdqu `16*1-64`($ctx),$D1 ++ vmovdqu `16*2-64`($ctx),$D2 ++ vpshufd \$0xEE,$D4,$D3 # 34xx -> 3434 ++ vpshufd \$0x44,$D4,$D0 # xx12 -> 1212 ++ vmovdqa $D3,-0x90(%r11) ++ vmovdqa $D0,0x00(%rsp) ++ vpshufd \$0xEE,$D1,$D4 ++ vmovdqu `16*3-64`($ctx),$D0 ++ vpshufd \$0x44,$D1,$D1 ++ vmovdqa $D4,-0x80(%r11) ++ vmovdqa $D1,0x10(%rsp) ++ vpshufd \$0xEE,$D2,$D3 ++ vmovdqu `16*4-64`($ctx),$D1 ++ vpshufd \$0x44,$D2,$D2 ++ vmovdqa $D3,-0x70(%r11) ++ vmovdqa $D2,0x20(%rsp) ++ vpshufd \$0xEE,$D0,$D4 ++ vmovdqu `16*5-64`($ctx),$D2 ++ vpshufd \$0x44,$D0,$D0 ++ vmovdqa $D4,-0x60(%r11) ++ vmovdqa $D0,0x30(%rsp) ++ vpshufd \$0xEE,$D1,$D3 ++ vmovdqu `16*6-64`($ctx),$D0 ++ vpshufd \$0x44,$D1,$D1 ++ vmovdqa $D3,-0x50(%r11) ++ vmovdqa $D1,0x40(%rsp) ++ vpshufd \$0xEE,$D2,$D4 ++ vmovdqu `16*7-64`($ctx),$D1 ++ vpshufd \$0x44,$D2,$D2 ++ vmovdqa $D4,-0x40(%r11) ++ vmovdqa $D2,0x50(%rsp) ++ vpshufd \$0xEE,$D0,$D3 ++ vmovdqu `16*8-64`($ctx),$D2 ++ vpshufd \$0x44,$D0,$D0 ++ vmovdqa $D3,-0x30(%r11) ++ vmovdqa $D0,0x60(%rsp) ++ vpshufd \$0xEE,$D1,$D4 ++ vpshufd \$0x44,$D1,$D1 ++ vmovdqa $D4,-0x20(%r11) ++ vmovdqa $D1,0x70(%rsp) ++ vpshufd \$0xEE,$D2,$D3 ++ vmovdqa 0x00(%rsp),$D4 # preload r0^2 ++ vpshufd \$0x44,$D2,$D2 ++ vmovdqa $D3,-0x10(%r11) ++ vmovdqa $D2,0x80(%rsp) ++ ++ jmp .Loop_avx ++ ++.align 32 ++.Loop_avx: ++ ################################################################ ++ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2 ++ # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r ++ # \___________________/ ++ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2 ++ # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r ++ # \___________________/ \____________________/ ++ # ++ # Note that we start with inp[2:3]*r^2. This is because it ++ # doesn't depend on reduction in previous iteration. ++ ################################################################ ++ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ # ++ # though note that $Tx and $Hx are "reversed" in this section, ++ # and $D4 is preloaded with r0^2... ++ ++ vpmuludq $T0,$D4,$D0 # d0 = h0*r0 ++ vpmuludq $T1,$D4,$D1 # d1 = h1*r0 ++ vmovdqa $H2,0x20(%r11) # offload hash ++ vpmuludq $T2,$D4,$D2 # d3 = h2*r0 ++ vmovdqa 0x10(%rsp),$H2 # r1^2 ++ vpmuludq $T3,$D4,$D3 # d3 = h3*r0 ++ vpmuludq $T4,$D4,$D4 # d4 = h4*r0 ++ ++ vmovdqa $H0,0x00(%r11) # ++ vpmuludq 0x20(%rsp),$T4,$H0 # h4*s1 ++ vmovdqa $H1,0x10(%r11) # ++ vpmuludq $T3,$H2,$H1 # h3*r1 ++ vpaddq $H0,$D0,$D0 # d0 += h4*s1 ++ vpaddq $H1,$D4,$D4 # d4 += h3*r1 ++ vmovdqa $H3,0x30(%r11) # ++ vpmuludq $T2,$H2,$H0 # h2*r1 ++ vpmuludq $T1,$H2,$H1 # h1*r1 ++ vpaddq $H0,$D3,$D3 # d3 += h2*r1 ++ vmovdqa 0x30(%rsp),$H3 # r2^2 ++ vpaddq $H1,$D2,$D2 # d2 += h1*r1 ++ vmovdqa $H4,0x40(%r11) # ++ vpmuludq $T0,$H2,$H2 # h0*r1 ++ vpmuludq $T2,$H3,$H0 # h2*r2 ++ vpaddq $H2,$D1,$D1 # d1 += h0*r1 ++ ++ vmovdqa 0x40(%rsp),$H4 # s2^2 ++ vpaddq $H0,$D4,$D4 # d4 += h2*r2 ++ vpmuludq $T1,$H3,$H1 # h1*r2 ++ vpmuludq $T0,$H3,$H3 # h0*r2 ++ vpaddq $H1,$D3,$D3 # d3 += h1*r2 ++ vmovdqa 0x50(%rsp),$H2 # r3^2 ++ vpaddq $H3,$D2,$D2 # d2 += h0*r2 ++ vpmuludq $T4,$H4,$H0 # h4*s2 ++ vpmuludq $T3,$H4,$H4 # h3*s2 ++ vpaddq $H0,$D1,$D1 # d1 += h4*s2 ++ vmovdqa 0x60(%rsp),$H3 # s3^2 ++ vpaddq $H4,$D0,$D0 # d0 += h3*s2 ++ ++ vmovdqa 0x80(%rsp),$H4 # s4^2 ++ vpmuludq $T1,$H2,$H1 # h1*r3 ++ vpmuludq $T0,$H2,$H2 # h0*r3 ++ vpaddq $H1,$D4,$D4 # d4 += h1*r3 ++ vpaddq $H2,$D3,$D3 # d3 += h0*r3 ++ vpmuludq $T4,$H3,$H0 # h4*s3 ++ vpmuludq $T3,$H3,$H1 # h3*s3 ++ vpaddq $H0,$D2,$D2 # d2 += h4*s3 ++ vmovdqu 16*0($inp),$H0 # load input ++ vpaddq $H1,$D1,$D1 # d1 += h3*s3 ++ vpmuludq $T2,$H3,$H3 # h2*s3 ++ vpmuludq $T2,$H4,$T2 # h2*s4 ++ vpaddq $H3,$D0,$D0 # d0 += h2*s3 ++ ++ vmovdqu 16*1($inp),$H1 # ++ vpaddq $T2,$D1,$D1 # d1 += h2*s4 ++ vpmuludq $T3,$H4,$T3 # h3*s4 ++ vpmuludq $T4,$H4,$T4 # h4*s4 ++ vpsrldq \$6,$H0,$H2 # splat input ++ vpaddq $T3,$D2,$D2 # d2 += h3*s4 ++ vpaddq $T4,$D3,$D3 # d3 += h4*s4 ++ vpsrldq \$6,$H1,$H3 # ++ vpmuludq 0x70(%rsp),$T0,$T4 # h0*r4 ++ vpmuludq $T1,$H4,$T0 # h1*s4 ++ vpunpckhqdq $H1,$H0,$H4 # 4 ++ vpaddq $T4,$D4,$D4 # d4 += h0*r4 ++ vmovdqa -0x90(%r11),$T4 # r0^4 ++ vpaddq $T0,$D0,$D0 # d0 += h1*s4 ++ ++ vpunpcklqdq $H1,$H0,$H0 # 0:1 ++ vpunpcklqdq $H3,$H2,$H3 # 2:3 ++ ++ #vpsrlq \$40,$H4,$H4 # 4 ++ vpsrldq \$`40/8`,$H4,$H4 # 4 ++ vpsrlq \$26,$H0,$H1 ++ vpand $MASK,$H0,$H0 # 0 ++ vpsrlq \$4,$H3,$H2 ++ vpand $MASK,$H1,$H1 # 1 ++ vpand 0(%rcx),$H4,$H4 # .Lmask24 ++ vpsrlq \$30,$H3,$H3 ++ vpand $MASK,$H2,$H2 # 2 ++ vpand $MASK,$H3,$H3 # 3 ++ vpor 32(%rcx),$H4,$H4 # padbit, yes, always ++ ++ vpaddq 0x00(%r11),$H0,$H0 # add hash value ++ vpaddq 0x10(%r11),$H1,$H1 ++ vpaddq 0x20(%r11),$H2,$H2 ++ vpaddq 0x30(%r11),$H3,$H3 ++ vpaddq 0x40(%r11),$H4,$H4 ++ ++ lea 16*2($inp),%rax ++ lea 16*4($inp),$inp ++ sub \$64,$len ++ cmovc %rax,$inp ++ ++ ################################################################ ++ # Now we accumulate (inp[0:1]+hash)*r^4 ++ ################################################################ ++ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ ++ vpmuludq $H0,$T4,$T0 # h0*r0 ++ vpmuludq $H1,$T4,$T1 # h1*r0 ++ vpaddq $T0,$D0,$D0 ++ vpaddq $T1,$D1,$D1 ++ vmovdqa -0x80(%r11),$T2 # r1^4 ++ vpmuludq $H2,$T4,$T0 # h2*r0 ++ vpmuludq $H3,$T4,$T1 # h3*r0 ++ vpaddq $T0,$D2,$D2 ++ vpaddq $T1,$D3,$D3 ++ vpmuludq $H4,$T4,$T4 # h4*r0 ++ vpmuludq -0x70(%r11),$H4,$T0 # h4*s1 ++ vpaddq $T4,$D4,$D4 ++ ++ vpaddq $T0,$D0,$D0 # d0 += h4*s1 ++ vpmuludq $H2,$T2,$T1 # h2*r1 ++ vpmuludq $H3,$T2,$T0 # h3*r1 ++ vpaddq $T1,$D3,$D3 # d3 += h2*r1 ++ vmovdqa -0x60(%r11),$T3 # r2^4 ++ vpaddq $T0,$D4,$D4 # d4 += h3*r1 ++ vpmuludq $H1,$T2,$T1 # h1*r1 ++ vpmuludq $H0,$T2,$T2 # h0*r1 ++ vpaddq $T1,$D2,$D2 # d2 += h1*r1 ++ vpaddq $T2,$D1,$D1 # d1 += h0*r1 ++ ++ vmovdqa -0x50(%r11),$T4 # s2^4 ++ vpmuludq $H2,$T3,$T0 # h2*r2 ++ vpmuludq $H1,$T3,$T1 # h1*r2 ++ vpaddq $T0,$D4,$D4 # d4 += h2*r2 ++ vpaddq $T1,$D3,$D3 # d3 += h1*r2 ++ vmovdqa -0x40(%r11),$T2 # r3^4 ++ vpmuludq $H0,$T3,$T3 # h0*r2 ++ vpmuludq $H4,$T4,$T0 # h4*s2 ++ vpaddq $T3,$D2,$D2 # d2 += h0*r2 ++ vpaddq $T0,$D1,$D1 # d1 += h4*s2 ++ vmovdqa -0x30(%r11),$T3 # s3^4 ++ vpmuludq $H3,$T4,$T4 # h3*s2 ++ vpmuludq $H1,$T2,$T1 # h1*r3 ++ vpaddq $T4,$D0,$D0 # d0 += h3*s2 ++ ++ vmovdqa -0x10(%r11),$T4 # s4^4 ++ vpaddq $T1,$D4,$D4 # d4 += h1*r3 ++ vpmuludq $H0,$T2,$T2 # h0*r3 ++ vpmuludq $H4,$T3,$T0 # h4*s3 ++ vpaddq $T2,$D3,$D3 # d3 += h0*r3 ++ vpaddq $T0,$D2,$D2 # d2 += h4*s3 ++ vmovdqu 16*2($inp),$T0 # load input ++ vpmuludq $H3,$T3,$T2 # h3*s3 ++ vpmuludq $H2,$T3,$T3 # h2*s3 ++ vpaddq $T2,$D1,$D1 # d1 += h3*s3 ++ vmovdqu 16*3($inp),$T1 # ++ vpaddq $T3,$D0,$D0 # d0 += h2*s3 ++ ++ vpmuludq $H2,$T4,$H2 # h2*s4 ++ vpmuludq $H3,$T4,$H3 # h3*s4 ++ vpsrldq \$6,$T0,$T2 # splat input ++ vpaddq $H2,$D1,$D1 # d1 += h2*s4 ++ vpmuludq $H4,$T4,$H4 # h4*s4 ++ vpsrldq \$6,$T1,$T3 # ++ vpaddq $H3,$D2,$H2 # h2 = d2 + h3*s4 ++ vpaddq $H4,$D3,$H3 # h3 = d3 + h4*s4 ++ vpmuludq -0x20(%r11),$H0,$H4 # h0*r4 ++ vpmuludq $H1,$T4,$H0 ++ vpunpckhqdq $T1,$T0,$T4 # 4 ++ vpaddq $H4,$D4,$H4 # h4 = d4 + h0*r4 ++ vpaddq $H0,$D0,$H0 # h0 = d0 + h1*s4 ++ ++ vpunpcklqdq $T1,$T0,$T0 # 0:1 ++ vpunpcklqdq $T3,$T2,$T3 # 2:3 ++ ++ #vpsrlq \$40,$T4,$T4 # 4 ++ vpsrldq \$`40/8`,$T4,$T4 # 4 ++ vpsrlq \$26,$T0,$T1 ++ vmovdqa 0x00(%rsp),$D4 # preload r0^2 ++ vpand $MASK,$T0,$T0 # 0 ++ vpsrlq \$4,$T3,$T2 ++ vpand $MASK,$T1,$T1 # 1 ++ vpand 0(%rcx),$T4,$T4 # .Lmask24 ++ vpsrlq \$30,$T3,$T3 ++ vpand $MASK,$T2,$T2 # 2 ++ vpand $MASK,$T3,$T3 # 3 ++ vpor 32(%rcx),$T4,$T4 # padbit, yes, always ++ ++ ################################################################ ++ # lazy reduction as discussed in "NEON crypto" by D.J. Bernstein ++ # and P. Schwabe ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpaddq $D0,$D1,$H1 # h0 -> h1 ++ ++ vpsrlq \$26,$H4,$D0 ++ vpand $MASK,$H4,$H4 ++ ++ vpsrlq \$26,$H1,$D1 ++ vpand $MASK,$H1,$H1 ++ vpaddq $D1,$H2,$H2 # h1 -> h2 ++ ++ vpaddq $D0,$H0,$H0 ++ vpsllq \$2,$D0,$D0 ++ vpaddq $D0,$H0,$H0 # h4 -> h0 ++ ++ vpsrlq \$26,$H2,$D2 ++ vpand $MASK,$H2,$H2 ++ vpaddq $D2,$H3,$H3 # h2 -> h3 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpaddq $D0,$H1,$H1 # h0 -> h1 ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ ja .Loop_avx ++ ++.Lskip_loop_avx: ++ ################################################################ ++ # multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1 ++ ++ vpshufd \$0x10,$D4,$D4 # r0^n, xx12 -> x1x2 ++ add \$32,$len ++ jnz .Long_tail_avx ++ ++ vpaddq $H2,$T2,$T2 ++ vpaddq $H0,$T0,$T0 ++ vpaddq $H1,$T1,$T1 ++ vpaddq $H3,$T3,$T3 ++ vpaddq $H4,$T4,$T4 ++ ++.Long_tail_avx: ++ vmovdqa $H2,0x20(%r11) ++ vmovdqa $H0,0x00(%r11) ++ vmovdqa $H1,0x10(%r11) ++ vmovdqa $H3,0x30(%r11) ++ vmovdqa $H4,0x40(%r11) ++ ++ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ ++ vpmuludq $T2,$D4,$D2 # d2 = h2*r0 ++ vpmuludq $T0,$D4,$D0 # d0 = h0*r0 ++ vpshufd \$0x10,`16*1-64`($ctx),$H2 # r1^n ++ vpmuludq $T1,$D4,$D1 # d1 = h1*r0 ++ vpmuludq $T3,$D4,$D3 # d3 = h3*r0 ++ vpmuludq $T4,$D4,$D4 # d4 = h4*r0 ++ ++ vpmuludq $T3,$H2,$H0 # h3*r1 ++ vpaddq $H0,$D4,$D4 # d4 += h3*r1 ++ vpshufd \$0x10,`16*2-64`($ctx),$H3 # s1^n ++ vpmuludq $T2,$H2,$H1 # h2*r1 ++ vpaddq $H1,$D3,$D3 # d3 += h2*r1 ++ vpshufd \$0x10,`16*3-64`($ctx),$H4 # r2^n ++ vpmuludq $T1,$H2,$H0 # h1*r1 ++ vpaddq $H0,$D2,$D2 # d2 += h1*r1 ++ vpmuludq $T0,$H2,$H2 # h0*r1 ++ vpaddq $H2,$D1,$D1 # d1 += h0*r1 ++ vpmuludq $T4,$H3,$H3 # h4*s1 ++ vpaddq $H3,$D0,$D0 # d0 += h4*s1 ++ ++ vpshufd \$0x10,`16*4-64`($ctx),$H2 # s2^n ++ vpmuludq $T2,$H4,$H1 # h2*r2 ++ vpaddq $H1,$D4,$D4 # d4 += h2*r2 ++ vpmuludq $T1,$H4,$H0 # h1*r2 ++ vpaddq $H0,$D3,$D3 # d3 += h1*r2 ++ vpshufd \$0x10,`16*5-64`($ctx),$H3 # r3^n ++ vpmuludq $T0,$H4,$H4 # h0*r2 ++ vpaddq $H4,$D2,$D2 # d2 += h0*r2 ++ vpmuludq $T4,$H2,$H1 # h4*s2 ++ vpaddq $H1,$D1,$D1 # d1 += h4*s2 ++ vpshufd \$0x10,`16*6-64`($ctx),$H4 # s3^n ++ vpmuludq $T3,$H2,$H2 # h3*s2 ++ vpaddq $H2,$D0,$D0 # d0 += h3*s2 ++ ++ vpmuludq $T1,$H3,$H0 # h1*r3 ++ vpaddq $H0,$D4,$D4 # d4 += h1*r3 ++ vpmuludq $T0,$H3,$H3 # h0*r3 ++ vpaddq $H3,$D3,$D3 # d3 += h0*r3 ++ vpshufd \$0x10,`16*7-64`($ctx),$H2 # r4^n ++ vpmuludq $T4,$H4,$H1 # h4*s3 ++ vpaddq $H1,$D2,$D2 # d2 += h4*s3 ++ vpshufd \$0x10,`16*8-64`($ctx),$H3 # s4^n ++ vpmuludq $T3,$H4,$H0 # h3*s3 ++ vpaddq $H0,$D1,$D1 # d1 += h3*s3 ++ vpmuludq $T2,$H4,$H4 # h2*s3 ++ vpaddq $H4,$D0,$D0 # d0 += h2*s3 ++ ++ vpmuludq $T0,$H2,$H2 # h0*r4 ++ vpaddq $H2,$D4,$D4 # h4 = d4 + h0*r4 ++ vpmuludq $T4,$H3,$H1 # h4*s4 ++ vpaddq $H1,$D3,$D3 # h3 = d3 + h4*s4 ++ vpmuludq $T3,$H3,$H0 # h3*s4 ++ vpaddq $H0,$D2,$D2 # h2 = d2 + h3*s4 ++ vpmuludq $T2,$H3,$H1 # h2*s4 ++ vpaddq $H1,$D1,$D1 # h1 = d1 + h2*s4 ++ vpmuludq $T1,$H3,$H3 # h1*s4 ++ vpaddq $H3,$D0,$D0 # h0 = d0 + h1*s4 ++ ++ jz .Lshort_tail_avx ++ ++ vmovdqu 16*0($inp),$H0 # load input ++ vmovdqu 16*1($inp),$H1 ++ ++ vpsrldq \$6,$H0,$H2 # splat input ++ vpsrldq \$6,$H1,$H3 ++ vpunpckhqdq $H1,$H0,$H4 # 4 ++ vpunpcklqdq $H1,$H0,$H0 # 0:1 ++ vpunpcklqdq $H3,$H2,$H3 # 2:3 ++ ++ vpsrlq \$40,$H4,$H4 # 4 ++ vpsrlq \$26,$H0,$H1 ++ vpand $MASK,$H0,$H0 # 0 ++ vpsrlq \$4,$H3,$H2 ++ vpand $MASK,$H1,$H1 # 1 ++ vpsrlq \$30,$H3,$H3 ++ vpand $MASK,$H2,$H2 # 2 ++ vpand $MASK,$H3,$H3 # 3 ++ vpor 32(%rcx),$H4,$H4 # padbit, yes, always ++ ++ vpshufd \$0x32,`16*0-64`($ctx),$T4 # r0^n, 34xx -> x3x4 ++ vpaddq 0x00(%r11),$H0,$H0 ++ vpaddq 0x10(%r11),$H1,$H1 ++ vpaddq 0x20(%r11),$H2,$H2 ++ vpaddq 0x30(%r11),$H3,$H3 ++ vpaddq 0x40(%r11),$H4,$H4 ++ ++ ################################################################ ++ # multiply (inp[0:1]+hash) by r^4:r^3 and accumulate ++ ++ vpmuludq $H0,$T4,$T0 # h0*r0 ++ vpaddq $T0,$D0,$D0 # d0 += h0*r0 ++ vpmuludq $H1,$T4,$T1 # h1*r0 ++ vpaddq $T1,$D1,$D1 # d1 += h1*r0 ++ vpmuludq $H2,$T4,$T0 # h2*r0 ++ vpaddq $T0,$D2,$D2 # d2 += h2*r0 ++ vpshufd \$0x32,`16*1-64`($ctx),$T2 # r1^n ++ vpmuludq $H3,$T4,$T1 # h3*r0 ++ vpaddq $T1,$D3,$D3 # d3 += h3*r0 ++ vpmuludq $H4,$T4,$T4 # h4*r0 ++ vpaddq $T4,$D4,$D4 # d4 += h4*r0 ++ ++ vpmuludq $H3,$T2,$T0 # h3*r1 ++ vpaddq $T0,$D4,$D4 # d4 += h3*r1 ++ vpshufd \$0x32,`16*2-64`($ctx),$T3 # s1 ++ vpmuludq $H2,$T2,$T1 # h2*r1 ++ vpaddq $T1,$D3,$D3 # d3 += h2*r1 ++ vpshufd \$0x32,`16*3-64`($ctx),$T4 # r2 ++ vpmuludq $H1,$T2,$T0 # h1*r1 ++ vpaddq $T0,$D2,$D2 # d2 += h1*r1 ++ vpmuludq $H0,$T2,$T2 # h0*r1 ++ vpaddq $T2,$D1,$D1 # d1 += h0*r1 ++ vpmuludq $H4,$T3,$T3 # h4*s1 ++ vpaddq $T3,$D0,$D0 # d0 += h4*s1 ++ ++ vpshufd \$0x32,`16*4-64`($ctx),$T2 # s2 ++ vpmuludq $H2,$T4,$T1 # h2*r2 ++ vpaddq $T1,$D4,$D4 # d4 += h2*r2 ++ vpmuludq $H1,$T4,$T0 # h1*r2 ++ vpaddq $T0,$D3,$D3 # d3 += h1*r2 ++ vpshufd \$0x32,`16*5-64`($ctx),$T3 # r3 ++ vpmuludq $H0,$T4,$T4 # h0*r2 ++ vpaddq $T4,$D2,$D2 # d2 += h0*r2 ++ vpmuludq $H4,$T2,$T1 # h4*s2 ++ vpaddq $T1,$D1,$D1 # d1 += h4*s2 ++ vpshufd \$0x32,`16*6-64`($ctx),$T4 # s3 ++ vpmuludq $H3,$T2,$T2 # h3*s2 ++ vpaddq $T2,$D0,$D0 # d0 += h3*s2 ++ ++ vpmuludq $H1,$T3,$T0 # h1*r3 ++ vpaddq $T0,$D4,$D4 # d4 += h1*r3 ++ vpmuludq $H0,$T3,$T3 # h0*r3 ++ vpaddq $T3,$D3,$D3 # d3 += h0*r3 ++ vpshufd \$0x32,`16*7-64`($ctx),$T2 # r4 ++ vpmuludq $H4,$T4,$T1 # h4*s3 ++ vpaddq $T1,$D2,$D2 # d2 += h4*s3 ++ vpshufd \$0x32,`16*8-64`($ctx),$T3 # s4 ++ vpmuludq $H3,$T4,$T0 # h3*s3 ++ vpaddq $T0,$D1,$D1 # d1 += h3*s3 ++ vpmuludq $H2,$T4,$T4 # h2*s3 ++ vpaddq $T4,$D0,$D0 # d0 += h2*s3 ++ ++ vpmuludq $H0,$T2,$T2 # h0*r4 ++ vpaddq $T2,$D4,$D4 # d4 += h0*r4 ++ vpmuludq $H4,$T3,$T1 # h4*s4 ++ vpaddq $T1,$D3,$D3 # d3 += h4*s4 ++ vpmuludq $H3,$T3,$T0 # h3*s4 ++ vpaddq $T0,$D2,$D2 # d2 += h3*s4 ++ vpmuludq $H2,$T3,$T1 # h2*s4 ++ vpaddq $T1,$D1,$D1 # d1 += h2*s4 ++ vpmuludq $H1,$T3,$T3 # h1*s4 ++ vpaddq $T3,$D0,$D0 # d0 += h1*s4 ++ ++.Lshort_tail_avx: ++ ################################################################ ++ # horizontal addition ++ ++ vpsrldq \$8,$D4,$T4 ++ vpsrldq \$8,$D3,$T3 ++ vpsrldq \$8,$D1,$T1 ++ vpsrldq \$8,$D0,$T0 ++ vpsrldq \$8,$D2,$T2 ++ vpaddq $T3,$D3,$D3 ++ vpaddq $T4,$D4,$D4 ++ vpaddq $T0,$D0,$D0 ++ vpaddq $T1,$D1,$D1 ++ vpaddq $T2,$D2,$D2 ++ ++ ################################################################ ++ # lazy reduction ++ ++ vpsrlq \$26,$D3,$H3 ++ vpand $MASK,$D3,$D3 ++ vpaddq $H3,$D4,$D4 # h3 -> h4 ++ ++ vpsrlq \$26,$D0,$H0 ++ vpand $MASK,$D0,$D0 ++ vpaddq $H0,$D1,$D1 # h0 -> h1 ++ ++ vpsrlq \$26,$D4,$H4 ++ vpand $MASK,$D4,$D4 ++ ++ vpsrlq \$26,$D1,$H1 ++ vpand $MASK,$D1,$D1 ++ vpaddq $H1,$D2,$D2 # h1 -> h2 ++ ++ vpaddq $H4,$D0,$D0 ++ vpsllq \$2,$H4,$H4 ++ vpaddq $H4,$D0,$D0 # h4 -> h0 ++ ++ vpsrlq \$26,$D2,$H2 ++ vpand $MASK,$D2,$D2 ++ vpaddq $H2,$D3,$D3 # h2 -> h3 ++ ++ vpsrlq \$26,$D0,$H0 ++ vpand $MASK,$D0,$D0 ++ vpaddq $H0,$D1,$D1 # h0 -> h1 ++ ++ vpsrlq \$26,$D3,$H3 ++ vpand $MASK,$D3,$D3 ++ vpaddq $H3,$D4,$D4 # h3 -> h4 ++ ++ vmovd $D0,`4*0-48-64`($ctx) # save partially reduced ++ vmovd $D1,`4*1-48-64`($ctx) ++ vmovd $D2,`4*2-48-64`($ctx) ++ vmovd $D3,`4*3-48-64`($ctx) ++ vmovd $D4,`4*4-48-64`($ctx) ++___ ++$code.=<<___ if ($win64); ++ vmovdqa 0x50(%r11),%xmm6 ++ vmovdqa 0x60(%r11),%xmm7 ++ vmovdqa 0x70(%r11),%xmm8 ++ vmovdqa 0x80(%r11),%xmm9 ++ vmovdqa 0x90(%r11),%xmm10 ++ vmovdqa 0xa0(%r11),%xmm11 ++ vmovdqa 0xb0(%r11),%xmm12 ++ vmovdqa 0xc0(%r11),%xmm13 ++ vmovdqa 0xd0(%r11),%xmm14 ++ vmovdqa 0xe0(%r11),%xmm15 ++ lea 0xf8(%r11),%rsp ++.Ldo_avx_epilogue: ++___ ++$code.=<<___ if (!$win64); ++ lea 0x58(%r11),%rsp ++.cfi_def_cfa %rsp,8 ++___ ++$code.=<<___; ++ vzeroupper ++ ret ++.cfi_endproc ++.size poly1305_blocks_avx,.-poly1305_blocks_avx ++ ++.type poly1305_emit_avx,\@function,3 ++.align 32 ++poly1305_emit_avx: ++ cmpl \$0,20($ctx) # is_base2_26? ++ je .Lemit ++ ++ mov 0($ctx),%eax # load hash value base 2^26 ++ mov 4($ctx),%ecx ++ mov 8($ctx),%r8d ++ mov 12($ctx),%r11d ++ mov 16($ctx),%r10d ++ ++ shl \$26,%rcx # base 2^26 -> base 2^64 ++ mov %r8,%r9 ++ shl \$52,%r8 ++ add %rcx,%rax ++ shr \$12,%r9 ++ add %rax,%r8 # h0 ++ adc \$0,%r9 ++ ++ shl \$14,%r11 ++ mov %r10,%rax ++ shr \$24,%r10 ++ add %r11,%r9 ++ shl \$40,%rax ++ add %rax,%r9 # h1 ++ adc \$0,%r10 # h2 ++ ++ mov %r10,%rax # could be partially reduced, so reduce ++ mov %r10,%rcx ++ and \$3,%r10 ++ shr \$2,%rax ++ and \$-4,%rcx ++ add %rcx,%rax ++ add %rax,%r8 ++ adc \$0,%r9 ++ adc \$0,%r10 ++ ++ mov %r8,%rax ++ add \$5,%r8 # compare to modulus ++ mov %r9,%rcx ++ adc \$0,%r9 ++ adc \$0,%r10 ++ shr \$2,%r10 # did 130-bit value overflow? ++ cmovnz %r8,%rax ++ cmovnz %r9,%rcx ++ ++ add 0($nonce),%rax # accumulate nonce ++ adc 8($nonce),%rcx ++ mov %rax,0($mac) # write result ++ mov %rcx,8($mac) ++ ++ ret ++.size poly1305_emit_avx,.-poly1305_emit_avx ++___ ++ ++if ($avx>1) { ++my ($H0,$H1,$H2,$H3,$H4, $MASK, $T4,$T0,$T1,$T2,$T3, $D0,$D1,$D2,$D3,$D4) = ++ map("%ymm$_",(0..15)); ++my $S4=$MASK; ++ ++$code.=<<___; ++.type poly1305_blocks_avx2,\@function,4 ++.align 32 ++poly1305_blocks_avx2: ++.cfi_startproc ++ mov 20($ctx),%r8d # is_base2_26 ++ cmp \$128,$len ++ jae .Lblocks_avx2 ++ test %r8d,%r8d ++ jz .Lblocks ++ ++.Lblocks_avx2: ++ and \$-16,$len ++ jz .Lno_data_avx2 ++ ++ vzeroupper ++ ++ test %r8d,%r8d ++ jz .Lbase2_64_avx2 ++ ++ test \$63,$len ++ jz .Leven_avx2 ++ ++ push %rbx ++.cfi_push %rbx ++ push %rbp ++.cfi_push %rbp ++ push %r12 ++.cfi_push %r12 ++ push %r13 ++.cfi_push %r13 ++ push %r14 ++.cfi_push %r14 ++ push %r15 ++.cfi_push %r15 ++.Lblocks_avx2_body: ++ ++ mov $len,%r15 # reassign $len ++ ++ mov 0($ctx),$d1 # load hash value ++ mov 8($ctx),$d2 ++ mov 16($ctx),$h2#d ++ ++ mov 24($ctx),$r0 # load r ++ mov 32($ctx),$s1 ++ ++ ################################# base 2^26 -> base 2^64 ++ mov $d1#d,$h0#d ++ and \$`-1*(1<<31)`,$d1 ++ mov $d2,$r1 # borrow $r1 ++ mov $d2#d,$h1#d ++ and \$`-1*(1<<31)`,$d2 ++ ++ shr \$6,$d1 ++ shl \$52,$r1 ++ add $d1,$h0 ++ shr \$12,$h1 ++ shr \$18,$d2 ++ add $r1,$h0 ++ adc $d2,$h1 ++ ++ mov $h2,$d1 ++ shl \$40,$d1 ++ shr \$24,$h2 ++ add $d1,$h1 ++ adc \$0,$h2 # can be partially reduced... ++ ++ mov \$-4,$d2 # ... so reduce ++ mov $h2,$d1 ++ and $h2,$d2 ++ shr \$2,$d1 ++ and \$3,$h2 ++ add $d2,$d1 # =*5 ++ add $d1,$h0 ++ adc \$0,$h1 ++ adc \$0,$h2 ++ ++ mov $s1,$r1 ++ mov $s1,%rax ++ shr \$2,$s1 ++ add $r1,$s1 # s1 = r1 + (r1 >> 2) ++ ++.Lbase2_26_pre_avx2: ++ add 0($inp),$h0 # accumulate input ++ adc 8($inp),$h1 ++ lea 16($inp),$inp ++ adc $padbit,$h2 ++ sub \$16,%r15 ++ ++ call __poly1305_block ++ mov $r1,%rax ++ ++ test \$63,%r15 ++ jnz .Lbase2_26_pre_avx2 ++ ++ test $padbit,$padbit # if $padbit is zero, ++ jz .Lstore_base2_64_avx2 # store hash in base 2^64 format ++ ++ ################################# base 2^64 -> base 2^26 ++ mov $h0,%rax ++ mov $h0,%rdx ++ shr \$52,$h0 ++ mov $h1,$r0 ++ mov $h1,$r1 ++ shr \$26,%rdx ++ and \$0x3ffffff,%rax # h[0] ++ shl \$12,$r0 ++ and \$0x3ffffff,%rdx # h[1] ++ shr \$14,$h1 ++ or $r0,$h0 ++ shl \$24,$h2 ++ and \$0x3ffffff,$h0 # h[2] ++ shr \$40,$r1 ++ and \$0x3ffffff,$h1 # h[3] ++ or $r1,$h2 # h[4] ++ ++ test %r15,%r15 ++ jz .Lstore_base2_26_avx2 ++ ++ vmovd %rax#d,%x#$H0 ++ vmovd %rdx#d,%x#$H1 ++ vmovd $h0#d,%x#$H2 ++ vmovd $h1#d,%x#$H3 ++ vmovd $h2#d,%x#$H4 ++ jmp .Lproceed_avx2 ++ ++.align 32 ++.Lstore_base2_64_avx2: ++ mov $h0,0($ctx) ++ mov $h1,8($ctx) ++ mov $h2,16($ctx) # note that is_base2_26 is zeroed ++ jmp .Ldone_avx2 ++ ++.align 16 ++.Lstore_base2_26_avx2: ++ mov %rax#d,0($ctx) # store hash value base 2^26 ++ mov %rdx#d,4($ctx) ++ mov $h0#d,8($ctx) ++ mov $h1#d,12($ctx) ++ mov $h2#d,16($ctx) ++.align 16 ++.Ldone_avx2: ++ mov 0(%rsp),%r15 ++.cfi_restore %r15 ++ mov 8(%rsp),%r14 ++.cfi_restore %r14 ++ mov 16(%rsp),%r13 ++.cfi_restore %r13 ++ mov 24(%rsp),%r12 ++.cfi_restore %r12 ++ mov 32(%rsp),%rbp ++.cfi_restore %rbp ++ mov 40(%rsp),%rbx ++.cfi_restore %rbx ++ lea 48(%rsp),%rsp ++.cfi_adjust_cfa_offset -48 ++.Lno_data_avx2: ++.Lblocks_avx2_epilogue: ++ ret ++.cfi_endproc ++ ++.align 32 ++.Lbase2_64_avx2: ++.cfi_startproc ++ push %rbx ++.cfi_push %rbx ++ push %rbp ++.cfi_push %rbp ++ push %r12 ++.cfi_push %r12 ++ push %r13 ++.cfi_push %r13 ++ push %r14 ++.cfi_push %r14 ++ push %r15 ++.cfi_push %r15 ++.Lbase2_64_avx2_body: ++ ++ mov $len,%r15 # reassign $len ++ ++ mov 24($ctx),$r0 # load r ++ mov 32($ctx),$s1 ++ ++ mov 0($ctx),$h0 # load hash value ++ mov 8($ctx),$h1 ++ mov 16($ctx),$h2#d ++ ++ mov $s1,$r1 ++ mov $s1,%rax ++ shr \$2,$s1 ++ add $r1,$s1 # s1 = r1 + (r1 >> 2) ++ ++ test \$63,$len ++ jz .Linit_avx2 ++ ++.Lbase2_64_pre_avx2: ++ add 0($inp),$h0 # accumulate input ++ adc 8($inp),$h1 ++ lea 16($inp),$inp ++ adc $padbit,$h2 ++ sub \$16,%r15 ++ ++ call __poly1305_block ++ mov $r1,%rax ++ ++ test \$63,%r15 ++ jnz .Lbase2_64_pre_avx2 ++ ++.Linit_avx2: ++ ################################# base 2^64 -> base 2^26 ++ mov $h0,%rax ++ mov $h0,%rdx ++ shr \$52,$h0 ++ mov $h1,$d1 ++ mov $h1,$d2 ++ shr \$26,%rdx ++ and \$0x3ffffff,%rax # h[0] ++ shl \$12,$d1 ++ and \$0x3ffffff,%rdx # h[1] ++ shr \$14,$h1 ++ or $d1,$h0 ++ shl \$24,$h2 ++ and \$0x3ffffff,$h0 # h[2] ++ shr \$40,$d2 ++ and \$0x3ffffff,$h1 # h[3] ++ or $d2,$h2 # h[4] ++ ++ vmovd %rax#d,%x#$H0 ++ vmovd %rdx#d,%x#$H1 ++ vmovd $h0#d,%x#$H2 ++ vmovd $h1#d,%x#$H3 ++ vmovd $h2#d,%x#$H4 ++ movl \$1,20($ctx) # set is_base2_26 ++ ++ call __poly1305_init_avx ++ ++.Lproceed_avx2: ++ mov %r15,$len # restore $len ++ mov OPENSSL_ia32cap_P+8(%rip),%r10d ++ mov \$`(1<<31|1<<30|1<<16)`,%r11d ++ ++ mov 0(%rsp),%r15 ++.cfi_restore %r15 ++ mov 8(%rsp),%r14 ++.cfi_restore %r14 ++ mov 16(%rsp),%r13 ++.cfi_restore %r13 ++ mov 24(%rsp),%r12 ++.cfi_restore %r12 ++ mov 32(%rsp),%rbp ++.cfi_restore %rbp ++ mov 40(%rsp),%rbx ++.cfi_restore %rbx ++ lea 48(%rsp),%rax ++ lea 48(%rsp),%rsp ++.cfi_adjust_cfa_offset -48 ++.Lbase2_64_avx2_epilogue: ++ jmp .Ldo_avx2 ++.cfi_endproc ++ ++.align 32 ++.Leven_avx2: ++.cfi_startproc ++ mov OPENSSL_ia32cap_P+8(%rip),%r10d ++ vmovd 4*0($ctx),%x#$H0 # load hash value base 2^26 ++ vmovd 4*1($ctx),%x#$H1 ++ vmovd 4*2($ctx),%x#$H2 ++ vmovd 4*3($ctx),%x#$H3 ++ vmovd 4*4($ctx),%x#$H4 ++ ++.Ldo_avx2: ++___ ++$code.=<<___ if ($avx>2); ++ cmp \$512,$len ++ jb .Lskip_avx512 ++ and %r11d,%r10d ++ test \$`1<<16`,%r10d # check for AVX512F ++ jnz .Lblocks_avx512 ++.Lskip_avx512: ++___ ++$code.=<<___ if (!$win64); ++ lea -8(%rsp),%r11 ++.cfi_def_cfa %r11,16 ++ sub \$0x128,%rsp ++___ ++$code.=<<___ if ($win64); ++ lea -0xf8(%rsp),%r11 ++ sub \$0x1c8,%rsp ++ vmovdqa %xmm6,0x50(%r11) ++ vmovdqa %xmm7,0x60(%r11) ++ vmovdqa %xmm8,0x70(%r11) ++ vmovdqa %xmm9,0x80(%r11) ++ vmovdqa %xmm10,0x90(%r11) ++ vmovdqa %xmm11,0xa0(%r11) ++ vmovdqa %xmm12,0xb0(%r11) ++ vmovdqa %xmm13,0xc0(%r11) ++ vmovdqa %xmm14,0xd0(%r11) ++ vmovdqa %xmm15,0xe0(%r11) ++.Ldo_avx2_body: ++___ ++$code.=<<___; ++ lea .Lconst(%rip),%rcx ++ lea 48+64($ctx),$ctx # size optimization ++ vmovdqa 96(%rcx),$T0 # .Lpermd_avx2 ++ ++ # expand and copy pre-calculated table to stack ++ vmovdqu `16*0-64`($ctx),%x#$T2 ++ and \$-512,%rsp ++ vmovdqu `16*1-64`($ctx),%x#$T3 ++ vmovdqu `16*2-64`($ctx),%x#$T4 ++ vmovdqu `16*3-64`($ctx),%x#$D0 ++ vmovdqu `16*4-64`($ctx),%x#$D1 ++ vmovdqu `16*5-64`($ctx),%x#$D2 ++ lea 0x90(%rsp),%rax # size optimization ++ vmovdqu `16*6-64`($ctx),%x#$D3 ++ vpermd $T2,$T0,$T2 # 00003412 -> 14243444 ++ vmovdqu `16*7-64`($ctx),%x#$D4 ++ vpermd $T3,$T0,$T3 ++ vmovdqu `16*8-64`($ctx),%x#$MASK ++ vpermd $T4,$T0,$T4 ++ vmovdqa $T2,0x00(%rsp) ++ vpermd $D0,$T0,$D0 ++ vmovdqa $T3,0x20-0x90(%rax) ++ vpermd $D1,$T0,$D1 ++ vmovdqa $T4,0x40-0x90(%rax) ++ vpermd $D2,$T0,$D2 ++ vmovdqa $D0,0x60-0x90(%rax) ++ vpermd $D3,$T0,$D3 ++ vmovdqa $D1,0x80-0x90(%rax) ++ vpermd $D4,$T0,$D4 ++ vmovdqa $D2,0xa0-0x90(%rax) ++ vpermd $MASK,$T0,$MASK ++ vmovdqa $D3,0xc0-0x90(%rax) ++ vmovdqa $D4,0xe0-0x90(%rax) ++ vmovdqa $MASK,0x100-0x90(%rax) ++ vmovdqa 64(%rcx),$MASK # .Lmask26 ++ ++ ################################################################ ++ # load input ++ vmovdqu 16*0($inp),%x#$T0 ++ vmovdqu 16*1($inp),%x#$T1 ++ vinserti128 \$1,16*2($inp),$T0,$T0 ++ vinserti128 \$1,16*3($inp),$T1,$T1 ++ lea 16*4($inp),$inp ++ ++ vpsrldq \$6,$T0,$T2 # splat input ++ vpsrldq \$6,$T1,$T3 ++ vpunpckhqdq $T1,$T0,$T4 # 4 ++ vpunpcklqdq $T3,$T2,$T2 # 2:3 ++ vpunpcklqdq $T1,$T0,$T0 # 0:1 ++ ++ vpsrlq \$30,$T2,$T3 ++ vpsrlq \$4,$T2,$T2 ++ vpsrlq \$26,$T0,$T1 ++ vpsrlq \$40,$T4,$T4 # 4 ++ vpand $MASK,$T2,$T2 # 2 ++ vpand $MASK,$T0,$T0 # 0 ++ vpand $MASK,$T1,$T1 # 1 ++ vpand $MASK,$T3,$T3 # 3 ++ vpor 32(%rcx),$T4,$T4 # padbit, yes, always ++ ++ vpaddq $H2,$T2,$H2 # accumulate input ++ sub \$64,$len ++ jz .Ltail_avx2 ++ jmp .Loop_avx2 ++ ++.align 32 ++.Loop_avx2: ++ ################################################################ ++ # ((inp[0]*r^4+inp[4])*r^4+inp[ 8])*r^4 ++ # ((inp[1]*r^4+inp[5])*r^4+inp[ 9])*r^3 ++ # ((inp[2]*r^4+inp[6])*r^4+inp[10])*r^2 ++ # ((inp[3]*r^4+inp[7])*r^4+inp[11])*r^1 ++ # \________/\__________/ ++ ################################################################ ++ #vpaddq $H2,$T2,$H2 # accumulate input ++ vpaddq $H0,$T0,$H0 ++ vmovdqa `32*0`(%rsp),$T0 # r0^4 ++ vpaddq $H1,$T1,$H1 ++ vmovdqa `32*1`(%rsp),$T1 # r1^4 ++ vpaddq $H3,$T3,$H3 ++ vmovdqa `32*3`(%rsp),$T2 # r2^4 ++ vpaddq $H4,$T4,$H4 ++ vmovdqa `32*6-0x90`(%rax),$T3 # s3^4 ++ vmovdqa `32*8-0x90`(%rax),$S4 # s4^4 ++ ++ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ # ++ # however, as h2 is "chronologically" first one available pull ++ # corresponding operations up, so it's ++ # ++ # d4 = h2*r2 + h4*r0 + h3*r1 + h1*r3 + h0*r4 ++ # d3 = h2*r1 + h3*r0 + h1*r2 + h0*r3 + h4*5*r4 ++ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ # d1 = h2*5*r4 + h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 ++ # d0 = h2*5*r3 + h0*r0 + h4*5*r1 + h3*5*r2 + h1*5*r4 ++ ++ vpmuludq $H2,$T0,$D2 # d2 = h2*r0 ++ vpmuludq $H2,$T1,$D3 # d3 = h2*r1 ++ vpmuludq $H2,$T2,$D4 # d4 = h2*r2 ++ vpmuludq $H2,$T3,$D0 # d0 = h2*s3 ++ vpmuludq $H2,$S4,$D1 # d1 = h2*s4 ++ ++ vpmuludq $H0,$T1,$T4 # h0*r1 ++ vpmuludq $H1,$T1,$H2 # h1*r1, borrow $H2 as temp ++ vpaddq $T4,$D1,$D1 # d1 += h0*r1 ++ vpaddq $H2,$D2,$D2 # d2 += h1*r1 ++ vpmuludq $H3,$T1,$T4 # h3*r1 ++ vpmuludq `32*2`(%rsp),$H4,$H2 # h4*s1 ++ vpaddq $T4,$D4,$D4 # d4 += h3*r1 ++ vpaddq $H2,$D0,$D0 # d0 += h4*s1 ++ vmovdqa `32*4-0x90`(%rax),$T1 # s2 ++ ++ vpmuludq $H0,$T0,$T4 # h0*r0 ++ vpmuludq $H1,$T0,$H2 # h1*r0 ++ vpaddq $T4,$D0,$D0 # d0 += h0*r0 ++ vpaddq $H2,$D1,$D1 # d1 += h1*r0 ++ vpmuludq $H3,$T0,$T4 # h3*r0 ++ vpmuludq $H4,$T0,$H2 # h4*r0 ++ vmovdqu 16*0($inp),%x#$T0 # load input ++ vpaddq $T4,$D3,$D3 # d3 += h3*r0 ++ vpaddq $H2,$D4,$D4 # d4 += h4*r0 ++ vinserti128 \$1,16*2($inp),$T0,$T0 ++ ++ vpmuludq $H3,$T1,$T4 # h3*s2 ++ vpmuludq $H4,$T1,$H2 # h4*s2 ++ vmovdqu 16*1($inp),%x#$T1 ++ vpaddq $T4,$D0,$D0 # d0 += h3*s2 ++ vpaddq $H2,$D1,$D1 # d1 += h4*s2 ++ vmovdqa `32*5-0x90`(%rax),$H2 # r3 ++ vpmuludq $H1,$T2,$T4 # h1*r2 ++ vpmuludq $H0,$T2,$T2 # h0*r2 ++ vpaddq $T4,$D3,$D3 # d3 += h1*r2 ++ vpaddq $T2,$D2,$D2 # d2 += h0*r2 ++ vinserti128 \$1,16*3($inp),$T1,$T1 ++ lea 16*4($inp),$inp ++ ++ vpmuludq $H1,$H2,$T4 # h1*r3 ++ vpmuludq $H0,$H2,$H2 # h0*r3 ++ vpsrldq \$6,$T0,$T2 # splat input ++ vpaddq $T4,$D4,$D4 # d4 += h1*r3 ++ vpaddq $H2,$D3,$D3 # d3 += h0*r3 ++ vpmuludq $H3,$T3,$T4 # h3*s3 ++ vpmuludq $H4,$T3,$H2 # h4*s3 ++ vpsrldq \$6,$T1,$T3 ++ vpaddq $T4,$D1,$D1 # d1 += h3*s3 ++ vpaddq $H2,$D2,$D2 # d2 += h4*s3 ++ vpunpckhqdq $T1,$T0,$T4 # 4 ++ ++ vpmuludq $H3,$S4,$H3 # h3*s4 ++ vpmuludq $H4,$S4,$H4 # h4*s4 ++ vpunpcklqdq $T1,$T0,$T0 # 0:1 ++ vpaddq $H3,$D2,$H2 # h2 = d2 + h3*r4 ++ vpaddq $H4,$D3,$H3 # h3 = d3 + h4*r4 ++ vpunpcklqdq $T3,$T2,$T3 # 2:3 ++ vpmuludq `32*7-0x90`(%rax),$H0,$H4 # h0*r4 ++ vpmuludq $H1,$S4,$H0 # h1*s4 ++ vmovdqa 64(%rcx),$MASK # .Lmask26 ++ vpaddq $H4,$D4,$H4 # h4 = d4 + h0*r4 ++ vpaddq $H0,$D0,$H0 # h0 = d0 + h1*s4 ++ ++ ################################################################ ++ # lazy reduction (interleaved with tail of input splat) ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpaddq $D0,$D1,$H1 # h0 -> h1 ++ ++ vpsrlq \$26,$H4,$D4 ++ vpand $MASK,$H4,$H4 ++ ++ vpsrlq \$4,$T3,$T2 ++ ++ vpsrlq \$26,$H1,$D1 ++ vpand $MASK,$H1,$H1 ++ vpaddq $D1,$H2,$H2 # h1 -> h2 ++ ++ vpaddq $D4,$H0,$H0 ++ vpsllq \$2,$D4,$D4 ++ vpaddq $D4,$H0,$H0 # h4 -> h0 ++ ++ vpand $MASK,$T2,$T2 # 2 ++ vpsrlq \$26,$T0,$T1 ++ ++ vpsrlq \$26,$H2,$D2 ++ vpand $MASK,$H2,$H2 ++ vpaddq $D2,$H3,$H3 # h2 -> h3 ++ ++ vpaddq $T2,$H2,$H2 # modulo-scheduled ++ vpsrlq \$30,$T3,$T3 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpaddq $D0,$H1,$H1 # h0 -> h1 ++ ++ vpsrlq \$40,$T4,$T4 # 4 ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ vpand $MASK,$T0,$T0 # 0 ++ vpand $MASK,$T1,$T1 # 1 ++ vpand $MASK,$T3,$T3 # 3 ++ vpor 32(%rcx),$T4,$T4 # padbit, yes, always ++ ++ sub \$64,$len ++ jnz .Loop_avx2 ++ ++ .byte 0x66,0x90 ++.Ltail_avx2: ++ ################################################################ ++ # while above multiplications were by r^4 in all lanes, in last ++ # iteration we multiply least significant lane by r^4 and most ++ # significant one by r, so copy of above except that references ++ # to the precomputed table are displaced by 4... ++ ++ #vpaddq $H2,$T2,$H2 # accumulate input ++ vpaddq $H0,$T0,$H0 ++ vmovdqu `32*0+4`(%rsp),$T0 # r0^4 ++ vpaddq $H1,$T1,$H1 ++ vmovdqu `32*1+4`(%rsp),$T1 # r1^4 ++ vpaddq $H3,$T3,$H3 ++ vmovdqu `32*3+4`(%rsp),$T2 # r2^4 ++ vpaddq $H4,$T4,$H4 ++ vmovdqu `32*6+4-0x90`(%rax),$T3 # s3^4 ++ vmovdqu `32*8+4-0x90`(%rax),$S4 # s4^4 ++ ++ vpmuludq $H2,$T0,$D2 # d2 = h2*r0 ++ vpmuludq $H2,$T1,$D3 # d3 = h2*r1 ++ vpmuludq $H2,$T2,$D4 # d4 = h2*r2 ++ vpmuludq $H2,$T3,$D0 # d0 = h2*s3 ++ vpmuludq $H2,$S4,$D1 # d1 = h2*s4 ++ ++ vpmuludq $H0,$T1,$T4 # h0*r1 ++ vpmuludq $H1,$T1,$H2 # h1*r1 ++ vpaddq $T4,$D1,$D1 # d1 += h0*r1 ++ vpaddq $H2,$D2,$D2 # d2 += h1*r1 ++ vpmuludq $H3,$T1,$T4 # h3*r1 ++ vpmuludq `32*2+4`(%rsp),$H4,$H2 # h4*s1 ++ vpaddq $T4,$D4,$D4 # d4 += h3*r1 ++ vpaddq $H2,$D0,$D0 # d0 += h4*s1 ++ ++ vpmuludq $H0,$T0,$T4 # h0*r0 ++ vpmuludq $H1,$T0,$H2 # h1*r0 ++ vpaddq $T4,$D0,$D0 # d0 += h0*r0 ++ vmovdqu `32*4+4-0x90`(%rax),$T1 # s2 ++ vpaddq $H2,$D1,$D1 # d1 += h1*r0 ++ vpmuludq $H3,$T0,$T4 # h3*r0 ++ vpmuludq $H4,$T0,$H2 # h4*r0 ++ vpaddq $T4,$D3,$D3 # d3 += h3*r0 ++ vpaddq $H2,$D4,$D4 # d4 += h4*r0 ++ ++ vpmuludq $H3,$T1,$T4 # h3*s2 ++ vpmuludq $H4,$T1,$H2 # h4*s2 ++ vpaddq $T4,$D0,$D0 # d0 += h3*s2 ++ vpaddq $H2,$D1,$D1 # d1 += h4*s2 ++ vmovdqu `32*5+4-0x90`(%rax),$H2 # r3 ++ vpmuludq $H1,$T2,$T4 # h1*r2 ++ vpmuludq $H0,$T2,$T2 # h0*r2 ++ vpaddq $T4,$D3,$D3 # d3 += h1*r2 ++ vpaddq $T2,$D2,$D2 # d2 += h0*r2 ++ ++ vpmuludq $H1,$H2,$T4 # h1*r3 ++ vpmuludq $H0,$H2,$H2 # h0*r3 ++ vpaddq $T4,$D4,$D4 # d4 += h1*r3 ++ vpaddq $H2,$D3,$D3 # d3 += h0*r3 ++ vpmuludq $H3,$T3,$T4 # h3*s3 ++ vpmuludq $H4,$T3,$H2 # h4*s3 ++ vpaddq $T4,$D1,$D1 # d1 += h3*s3 ++ vpaddq $H2,$D2,$D2 # d2 += h4*s3 ++ ++ vpmuludq $H3,$S4,$H3 # h3*s4 ++ vpmuludq $H4,$S4,$H4 # h4*s4 ++ vpaddq $H3,$D2,$H2 # h2 = d2 + h3*r4 ++ vpaddq $H4,$D3,$H3 # h3 = d3 + h4*r4 ++ vpmuludq `32*7+4-0x90`(%rax),$H0,$H4 # h0*r4 ++ vpmuludq $H1,$S4,$H0 # h1*s4 ++ vmovdqa 64(%rcx),$MASK # .Lmask26 ++ vpaddq $H4,$D4,$H4 # h4 = d4 + h0*r4 ++ vpaddq $H0,$D0,$H0 # h0 = d0 + h1*s4 ++ ++ ################################################################ ++ # horizontal addition ++ ++ vpsrldq \$8,$D1,$T1 ++ vpsrldq \$8,$H2,$T2 ++ vpsrldq \$8,$H3,$T3 ++ vpsrldq \$8,$H4,$T4 ++ vpsrldq \$8,$H0,$T0 ++ vpaddq $T1,$D1,$D1 ++ vpaddq $T2,$H2,$H2 ++ vpaddq $T3,$H3,$H3 ++ vpaddq $T4,$H4,$H4 ++ vpaddq $T0,$H0,$H0 ++ ++ vpermq \$0x2,$H3,$T3 ++ vpermq \$0x2,$H4,$T4 ++ vpermq \$0x2,$H0,$T0 ++ vpermq \$0x2,$D1,$T1 ++ vpermq \$0x2,$H2,$T2 ++ vpaddq $T3,$H3,$H3 ++ vpaddq $T4,$H4,$H4 ++ vpaddq $T0,$H0,$H0 ++ vpaddq $T1,$D1,$D1 ++ vpaddq $T2,$H2,$H2 ++ ++ ################################################################ ++ # lazy reduction ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpaddq $D0,$D1,$H1 # h0 -> h1 ++ ++ vpsrlq \$26,$H4,$D4 ++ vpand $MASK,$H4,$H4 ++ ++ vpsrlq \$26,$H1,$D1 ++ vpand $MASK,$H1,$H1 ++ vpaddq $D1,$H2,$H2 # h1 -> h2 ++ ++ vpaddq $D4,$H0,$H0 ++ vpsllq \$2,$D4,$D4 ++ vpaddq $D4,$H0,$H0 # h4 -> h0 ++ ++ vpsrlq \$26,$H2,$D2 ++ vpand $MASK,$H2,$H2 ++ vpaddq $D2,$H3,$H3 # h2 -> h3 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpaddq $D0,$H1,$H1 # h0 -> h1 ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ vmovd %x#$H0,`4*0-48-64`($ctx)# save partially reduced ++ vmovd %x#$H1,`4*1-48-64`($ctx) ++ vmovd %x#$H2,`4*2-48-64`($ctx) ++ vmovd %x#$H3,`4*3-48-64`($ctx) ++ vmovd %x#$H4,`4*4-48-64`($ctx) ++___ ++$code.=<<___ if ($win64); ++ vmovdqa 0x50(%r11),%xmm6 ++ vmovdqa 0x60(%r11),%xmm7 ++ vmovdqa 0x70(%r11),%xmm8 ++ vmovdqa 0x80(%r11),%xmm9 ++ vmovdqa 0x90(%r11),%xmm10 ++ vmovdqa 0xa0(%r11),%xmm11 ++ vmovdqa 0xb0(%r11),%xmm12 ++ vmovdqa 0xc0(%r11),%xmm13 ++ vmovdqa 0xd0(%r11),%xmm14 ++ vmovdqa 0xe0(%r11),%xmm15 ++ lea 0xf8(%r11),%rsp ++.Ldo_avx2_epilogue: ++___ ++$code.=<<___ if (!$win64); ++ lea 8(%r11),%rsp ++.cfi_def_cfa %rsp,8 ++___ ++$code.=<<___; ++ vzeroupper ++ ret ++.cfi_endproc ++.size poly1305_blocks_avx2,.-poly1305_blocks_avx2 ++___ ++####################################################################### ++if ($avx>2) { ++# On entry we have input length divisible by 64. But since inner loop ++# processes 128 bytes per iteration, cases when length is not divisible ++# by 128 are handled by passing tail 64 bytes to .Ltail_avx2. For this ++# reason stack layout is kept identical to poly1305_blocks_avx2. If not ++# for this tail, we wouldn't have to even allocate stack frame... ++ ++my ($R0,$R1,$R2,$R3,$R4, $S1,$S2,$S3,$S4) = map("%zmm$_",(16..24)); ++my ($M0,$M1,$M2,$M3,$M4) = map("%zmm$_",(25..29)); ++my $PADBIT="%zmm30"; ++ ++map(s/%y/%z/,($T4,$T0,$T1,$T2,$T3)); # switch to %zmm domain ++map(s/%y/%z/,($D0,$D1,$D2,$D3,$D4)); ++map(s/%y/%z/,($H0,$H1,$H2,$H3,$H4)); ++map(s/%y/%z/,($MASK)); ++ ++$code.=<<___; ++.type poly1305_blocks_avx512,\@function,4 ++.align 32 ++poly1305_blocks_avx512: ++.cfi_startproc ++.Lblocks_avx512: ++ mov \$15,%eax ++ kmovw %eax,%k2 ++___ ++$code.=<<___ if (!$win64); ++ lea -8(%rsp),%r11 ++.cfi_def_cfa %r11,16 ++ sub \$0x128,%rsp ++___ ++$code.=<<___ if ($win64); ++ lea -0xf8(%rsp),%r11 ++ sub \$0x1c8,%rsp ++ vmovdqa %xmm6,0x50(%r11) ++ vmovdqa %xmm7,0x60(%r11) ++ vmovdqa %xmm8,0x70(%r11) ++ vmovdqa %xmm9,0x80(%r11) ++ vmovdqa %xmm10,0x90(%r11) ++ vmovdqa %xmm11,0xa0(%r11) ++ vmovdqa %xmm12,0xb0(%r11) ++ vmovdqa %xmm13,0xc0(%r11) ++ vmovdqa %xmm14,0xd0(%r11) ++ vmovdqa %xmm15,0xe0(%r11) ++.Ldo_avx512_body: ++___ ++$code.=<<___; ++ lea .Lconst(%rip),%rcx ++ lea 48+64($ctx),$ctx # size optimization ++ vmovdqa 96(%rcx),%y#$T2 # .Lpermd_avx2 ++ ++ # expand pre-calculated table ++ vmovdqu `16*0-64`($ctx),%x#$D0 # will become expanded ${R0} ++ and \$-512,%rsp ++ vmovdqu `16*1-64`($ctx),%x#$D1 # will become ... ${R1} ++ mov \$0x20,%rax ++ vmovdqu `16*2-64`($ctx),%x#$T0 # ... ${S1} ++ vmovdqu `16*3-64`($ctx),%x#$D2 # ... ${R2} ++ vmovdqu `16*4-64`($ctx),%x#$T1 # ... ${S2} ++ vmovdqu `16*5-64`($ctx),%x#$D3 # ... ${R3} ++ vmovdqu `16*6-64`($ctx),%x#$T3 # ... ${S3} ++ vmovdqu `16*7-64`($ctx),%x#$D4 # ... ${R4} ++ vmovdqu `16*8-64`($ctx),%x#$T4 # ... ${S4} ++ vpermd $D0,$T2,$R0 # 00003412 -> 14243444 ++ vpbroadcastq 64(%rcx),$MASK # .Lmask26 ++ vpermd $D1,$T2,$R1 ++ vpermd $T0,$T2,$S1 ++ vpermd $D2,$T2,$R2 ++ vmovdqa64 $R0,0x00(%rsp){%k2} # save in case $len%128 != 0 ++ vpsrlq \$32,$R0,$T0 # 14243444 -> 01020304 ++ vpermd $T1,$T2,$S2 ++ vmovdqu64 $R1,0x00(%rsp,%rax){%k2} ++ vpsrlq \$32,$R1,$T1 ++ vpermd $D3,$T2,$R3 ++ vmovdqa64 $S1,0x40(%rsp){%k2} ++ vpermd $T3,$T2,$S3 ++ vpermd $D4,$T2,$R4 ++ vmovdqu64 $R2,0x40(%rsp,%rax){%k2} ++ vpermd $T4,$T2,$S4 ++ vmovdqa64 $S2,0x80(%rsp){%k2} ++ vmovdqu64 $R3,0x80(%rsp,%rax){%k2} ++ vmovdqa64 $S3,0xc0(%rsp){%k2} ++ vmovdqu64 $R4,0xc0(%rsp,%rax){%k2} ++ vmovdqa64 $S4,0x100(%rsp){%k2} ++ ++ ################################################################ ++ # calculate 5th through 8th powers of the key ++ # ++ # d0 = r0'*r0 + r1'*5*r4 + r2'*5*r3 + r3'*5*r2 + r4'*5*r1 ++ # d1 = r0'*r1 + r1'*r0 + r2'*5*r4 + r3'*5*r3 + r4'*5*r2 ++ # d2 = r0'*r2 + r1'*r1 + r2'*r0 + r3'*5*r4 + r4'*5*r3 ++ # d3 = r0'*r3 + r1'*r2 + r2'*r1 + r3'*r0 + r4'*5*r4 ++ # d4 = r0'*r4 + r1'*r3 + r2'*r2 + r3'*r1 + r4'*r0 ++ ++ vpmuludq $T0,$R0,$D0 # d0 = r0'*r0 ++ vpmuludq $T0,$R1,$D1 # d1 = r0'*r1 ++ vpmuludq $T0,$R2,$D2 # d2 = r0'*r2 ++ vpmuludq $T0,$R3,$D3 # d3 = r0'*r3 ++ vpmuludq $T0,$R4,$D4 # d4 = r0'*r4 ++ vpsrlq \$32,$R2,$T2 ++ ++ vpmuludq $T1,$S4,$M0 ++ vpmuludq $T1,$R0,$M1 ++ vpmuludq $T1,$R1,$M2 ++ vpmuludq $T1,$R2,$M3 ++ vpmuludq $T1,$R3,$M4 ++ vpsrlq \$32,$R3,$T3 ++ vpaddq $M0,$D0,$D0 # d0 += r1'*5*r4 ++ vpaddq $M1,$D1,$D1 # d1 += r1'*r0 ++ vpaddq $M2,$D2,$D2 # d2 += r1'*r1 ++ vpaddq $M3,$D3,$D3 # d3 += r1'*r2 ++ vpaddq $M4,$D4,$D4 # d4 += r1'*r3 ++ ++ vpmuludq $T2,$S3,$M0 ++ vpmuludq $T2,$S4,$M1 ++ vpmuludq $T2,$R1,$M3 ++ vpmuludq $T2,$R2,$M4 ++ vpmuludq $T2,$R0,$M2 ++ vpsrlq \$32,$R4,$T4 ++ vpaddq $M0,$D0,$D0 # d0 += r2'*5*r3 ++ vpaddq $M1,$D1,$D1 # d1 += r2'*5*r4 ++ vpaddq $M3,$D3,$D3 # d3 += r2'*r1 ++ vpaddq $M4,$D4,$D4 # d4 += r2'*r2 ++ vpaddq $M2,$D2,$D2 # d2 += r2'*r0 ++ ++ vpmuludq $T3,$S2,$M0 ++ vpmuludq $T3,$R0,$M3 ++ vpmuludq $T3,$R1,$M4 ++ vpmuludq $T3,$S3,$M1 ++ vpmuludq $T3,$S4,$M2 ++ vpaddq $M0,$D0,$D0 # d0 += r3'*5*r2 ++ vpaddq $M3,$D3,$D3 # d3 += r3'*r0 ++ vpaddq $M4,$D4,$D4 # d4 += r3'*r1 ++ vpaddq $M1,$D1,$D1 # d1 += r3'*5*r3 ++ vpaddq $M2,$D2,$D2 # d2 += r3'*5*r4 ++ ++ vpmuludq $T4,$S4,$M3 ++ vpmuludq $T4,$R0,$M4 ++ vpmuludq $T4,$S1,$M0 ++ vpmuludq $T4,$S2,$M1 ++ vpmuludq $T4,$S3,$M2 ++ vpaddq $M3,$D3,$D3 # d3 += r2'*5*r4 ++ vpaddq $M4,$D4,$D4 # d4 += r2'*r0 ++ vpaddq $M0,$D0,$D0 # d0 += r2'*5*r1 ++ vpaddq $M1,$D1,$D1 # d1 += r2'*5*r2 ++ vpaddq $M2,$D2,$D2 # d2 += r2'*5*r3 ++ ++ ################################################################ ++ # load input ++ vmovdqu64 16*0($inp),%z#$T3 ++ vmovdqu64 16*4($inp),%z#$T4 ++ lea 16*8($inp),$inp ++ ++ ################################################################ ++ # lazy reduction ++ ++ vpsrlq \$26,$D3,$M3 ++ vpandq $MASK,$D3,$D3 ++ vpaddq $M3,$D4,$D4 # d3 -> d4 ++ ++ vpsrlq \$26,$D0,$M0 ++ vpandq $MASK,$D0,$D0 ++ vpaddq $M0,$D1,$D1 # d0 -> d1 ++ ++ vpsrlq \$26,$D4,$M4 ++ vpandq $MASK,$D4,$D4 ++ ++ vpsrlq \$26,$D1,$M1 ++ vpandq $MASK,$D1,$D1 ++ vpaddq $M1,$D2,$D2 # d1 -> d2 ++ ++ vpaddq $M4,$D0,$D0 ++ vpsllq \$2,$M4,$M4 ++ vpaddq $M4,$D0,$D0 # d4 -> d0 ++ ++ vpsrlq \$26,$D2,$M2 ++ vpandq $MASK,$D2,$D2 ++ vpaddq $M2,$D3,$D3 # d2 -> d3 ++ ++ vpsrlq \$26,$D0,$M0 ++ vpandq $MASK,$D0,$D0 ++ vpaddq $M0,$D1,$D1 # d0 -> d1 ++ ++ vpsrlq \$26,$D3,$M3 ++ vpandq $MASK,$D3,$D3 ++ vpaddq $M3,$D4,$D4 # d3 -> d4 ++ ++ ################################################################ ++ # at this point we have 14243444 in $R0-$S4 and 05060708 in ++ # $D0-$D4, ... ++ ++ vpunpcklqdq $T4,$T3,$T0 # transpose input ++ vpunpckhqdq $T4,$T3,$T4 ++ ++ # ... since input 64-bit lanes are ordered as 73625140, we could ++ # "vperm" it to 76543210 (here and in each loop iteration), *or* ++ # we could just flow along, hence the goal for $R0-$S4 is ++ # 1858286838784888 ... ++ ++ vmovdqa32 128(%rcx),$M0 # .Lpermd_avx512: ++ mov \$0x7777,%eax ++ kmovw %eax,%k1 ++ ++ vpermd $R0,$M0,$R0 # 14243444 -> 1---2---3---4--- ++ vpermd $R1,$M0,$R1 ++ vpermd $R2,$M0,$R2 ++ vpermd $R3,$M0,$R3 ++ vpermd $R4,$M0,$R4 ++ ++ vpermd $D0,$M0,${R0}{%k1} # 05060708 -> 1858286838784888 ++ vpermd $D1,$M0,${R1}{%k1} ++ vpermd $D2,$M0,${R2}{%k1} ++ vpermd $D3,$M0,${R3}{%k1} ++ vpermd $D4,$M0,${R4}{%k1} ++ ++ vpslld \$2,$R1,$S1 # *5 ++ vpslld \$2,$R2,$S2 ++ vpslld \$2,$R3,$S3 ++ vpslld \$2,$R4,$S4 ++ vpaddd $R1,$S1,$S1 ++ vpaddd $R2,$S2,$S2 ++ vpaddd $R3,$S3,$S3 ++ vpaddd $R4,$S4,$S4 ++ ++ vpbroadcastq 32(%rcx),$PADBIT # .L129 ++ ++ vpsrlq \$52,$T0,$T2 # splat input ++ vpsllq \$12,$T4,$T3 ++ vporq $T3,$T2,$T2 ++ vpsrlq \$26,$T0,$T1 ++ vpsrlq \$14,$T4,$T3 ++ vpsrlq \$40,$T4,$T4 # 4 ++ vpandq $MASK,$T2,$T2 # 2 ++ vpandq $MASK,$T0,$T0 # 0 ++ #vpandq $MASK,$T1,$T1 # 1 ++ #vpandq $MASK,$T3,$T3 # 3 ++ #vporq $PADBIT,$T4,$T4 # padbit, yes, always ++ ++ vpaddq $H2,$T2,$H2 # accumulate input ++ sub \$192,$len ++ jbe .Ltail_avx512 ++ jmp .Loop_avx512 ++ ++.align 32 ++.Loop_avx512: ++ ################################################################ ++ # ((inp[0]*r^8+inp[ 8])*r^8+inp[16])*r^8 ++ # ((inp[1]*r^8+inp[ 9])*r^8+inp[17])*r^7 ++ # ((inp[2]*r^8+inp[10])*r^8+inp[18])*r^6 ++ # ((inp[3]*r^8+inp[11])*r^8+inp[19])*r^5 ++ # ((inp[4]*r^8+inp[12])*r^8+inp[20])*r^4 ++ # ((inp[5]*r^8+inp[13])*r^8+inp[21])*r^3 ++ # ((inp[6]*r^8+inp[14])*r^8+inp[22])*r^2 ++ # ((inp[7]*r^8+inp[15])*r^8+inp[23])*r^1 ++ # \________/\___________/ ++ ################################################################ ++ #vpaddq $H2,$T2,$H2 # accumulate input ++ ++ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4 ++ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4 ++ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4 ++ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4 ++ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4 ++ # ++ # however, as h2 is "chronologically" first one available pull ++ # corresponding operations up, so it's ++ # ++ # d3 = h2*r1 + h0*r3 + h1*r2 + h3*r0 + h4*5*r4 ++ # d4 = h2*r2 + h0*r4 + h1*r3 + h3*r1 + h4*r0 ++ # d0 = h2*5*r3 + h0*r0 + h1*5*r4 + h3*5*r2 + h4*5*r1 ++ # d1 = h2*5*r4 + h0*r1 + h1*r0 + h3*5*r3 + h4*5*r2 ++ # d2 = h2*r0 + h0*r2 + h1*r1 + h3*5*r4 + h4*5*r3 ++ ++ vpmuludq $H2,$R1,$D3 # d3 = h2*r1 ++ vpaddq $H0,$T0,$H0 ++ vpmuludq $H2,$R2,$D4 # d4 = h2*r2 ++ vpandq $MASK,$T1,$T1 # 1 ++ vpmuludq $H2,$S3,$D0 # d0 = h2*s3 ++ vpandq $MASK,$T3,$T3 # 3 ++ vpmuludq $H2,$S4,$D1 # d1 = h2*s4 ++ vporq $PADBIT,$T4,$T4 # padbit, yes, always ++ vpmuludq $H2,$R0,$D2 # d2 = h2*r0 ++ vpaddq $H1,$T1,$H1 # accumulate input ++ vpaddq $H3,$T3,$H3 ++ vpaddq $H4,$T4,$H4 ++ ++ vmovdqu64 16*0($inp),$T3 # load input ++ vmovdqu64 16*4($inp),$T4 ++ lea 16*8($inp),$inp ++ vpmuludq $H0,$R3,$M3 ++ vpmuludq $H0,$R4,$M4 ++ vpmuludq $H0,$R0,$M0 ++ vpmuludq $H0,$R1,$M1 ++ vpaddq $M3,$D3,$D3 # d3 += h0*r3 ++ vpaddq $M4,$D4,$D4 # d4 += h0*r4 ++ vpaddq $M0,$D0,$D0 # d0 += h0*r0 ++ vpaddq $M1,$D1,$D1 # d1 += h0*r1 ++ ++ vpmuludq $H1,$R2,$M3 ++ vpmuludq $H1,$R3,$M4 ++ vpmuludq $H1,$S4,$M0 ++ vpmuludq $H0,$R2,$M2 ++ vpaddq $M3,$D3,$D3 # d3 += h1*r2 ++ vpaddq $M4,$D4,$D4 # d4 += h1*r3 ++ vpaddq $M0,$D0,$D0 # d0 += h1*s4 ++ vpaddq $M2,$D2,$D2 # d2 += h0*r2 ++ ++ vpunpcklqdq $T4,$T3,$T0 # transpose input ++ vpunpckhqdq $T4,$T3,$T4 ++ ++ vpmuludq $H3,$R0,$M3 ++ vpmuludq $H3,$R1,$M4 ++ vpmuludq $H1,$R0,$M1 ++ vpmuludq $H1,$R1,$M2 ++ vpaddq $M3,$D3,$D3 # d3 += h3*r0 ++ vpaddq $M4,$D4,$D4 # d4 += h3*r1 ++ vpaddq $M1,$D1,$D1 # d1 += h1*r0 ++ vpaddq $M2,$D2,$D2 # d2 += h1*r1 ++ ++ vpmuludq $H4,$S4,$M3 ++ vpmuludq $H4,$R0,$M4 ++ vpmuludq $H3,$S2,$M0 ++ vpmuludq $H3,$S3,$M1 ++ vpaddq $M3,$D3,$D3 # d3 += h4*s4 ++ vpmuludq $H3,$S4,$M2 ++ vpaddq $M4,$D4,$D4 # d4 += h4*r0 ++ vpaddq $M0,$D0,$D0 # d0 += h3*s2 ++ vpaddq $M1,$D1,$D1 # d1 += h3*s3 ++ vpaddq $M2,$D2,$D2 # d2 += h3*s4 ++ ++ vpmuludq $H4,$S1,$M0 ++ vpmuludq $H4,$S2,$M1 ++ vpmuludq $H4,$S3,$M2 ++ vpaddq $M0,$D0,$H0 # h0 = d0 + h4*s1 ++ vpaddq $M1,$D1,$H1 # h1 = d2 + h4*s2 ++ vpaddq $M2,$D2,$H2 # h2 = d3 + h4*s3 ++ ++ ################################################################ ++ # lazy reduction (interleaved with input splat) ++ ++ vpsrlq \$52,$T0,$T2 # splat input ++ vpsllq \$12,$T4,$T3 ++ ++ vpsrlq \$26,$D3,$H3 ++ vpandq $MASK,$D3,$D3 ++ vpaddq $H3,$D4,$H4 # h3 -> h4 ++ ++ vporq $T3,$T2,$T2 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpandq $MASK,$H0,$H0 ++ vpaddq $D0,$H1,$H1 # h0 -> h1 ++ ++ vpandq $MASK,$T2,$T2 # 2 ++ ++ vpsrlq \$26,$H4,$D4 ++ vpandq $MASK,$H4,$H4 ++ ++ vpsrlq \$26,$H1,$D1 ++ vpandq $MASK,$H1,$H1 ++ vpaddq $D1,$H2,$H2 # h1 -> h2 ++ ++ vpaddq $D4,$H0,$H0 ++ vpsllq \$2,$D4,$D4 ++ vpaddq $D4,$H0,$H0 # h4 -> h0 ++ ++ vpaddq $T2,$H2,$H2 # modulo-scheduled ++ vpsrlq \$26,$T0,$T1 ++ ++ vpsrlq \$26,$H2,$D2 ++ vpandq $MASK,$H2,$H2 ++ vpaddq $D2,$D3,$H3 # h2 -> h3 ++ ++ vpsrlq \$14,$T4,$T3 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpandq $MASK,$H0,$H0 ++ vpaddq $D0,$H1,$H1 # h0 -> h1 ++ ++ vpsrlq \$40,$T4,$T4 # 4 ++ ++ vpsrlq \$26,$H3,$D3 ++ vpandq $MASK,$H3,$H3 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ vpandq $MASK,$T0,$T0 # 0 ++ #vpandq $MASK,$T1,$T1 # 1 ++ #vpandq $MASK,$T3,$T3 # 3 ++ #vporq $PADBIT,$T4,$T4 # padbit, yes, always ++ ++ sub \$128,$len ++ ja .Loop_avx512 ++ ++.Ltail_avx512: ++ ################################################################ ++ # while above multiplications were by r^8 in all lanes, in last ++ # iteration we multiply least significant lane by r^8 and most ++ # significant one by r, that's why table gets shifted... ++ ++ vpsrlq \$32,$R0,$R0 # 0105020603070408 ++ vpsrlq \$32,$R1,$R1 ++ vpsrlq \$32,$R2,$R2 ++ vpsrlq \$32,$S3,$S3 ++ vpsrlq \$32,$S4,$S4 ++ vpsrlq \$32,$R3,$R3 ++ vpsrlq \$32,$R4,$R4 ++ vpsrlq \$32,$S1,$S1 ++ vpsrlq \$32,$S2,$S2 ++ ++ ################################################################ ++ # load either next or last 64 byte of input ++ lea ($inp,$len),$inp ++ ++ #vpaddq $H2,$T2,$H2 # accumulate input ++ vpaddq $H0,$T0,$H0 ++ ++ vpmuludq $H2,$R1,$D3 # d3 = h2*r1 ++ vpmuludq $H2,$R2,$D4 # d4 = h2*r2 ++ vpmuludq $H2,$S3,$D0 # d0 = h2*s3 ++ vpandq $MASK,$T1,$T1 # 1 ++ vpmuludq $H2,$S4,$D1 # d1 = h2*s4 ++ vpandq $MASK,$T3,$T3 # 3 ++ vpmuludq $H2,$R0,$D2 # d2 = h2*r0 ++ vporq $PADBIT,$T4,$T4 # padbit, yes, always ++ vpaddq $H1,$T1,$H1 # accumulate input ++ vpaddq $H3,$T3,$H3 ++ vpaddq $H4,$T4,$H4 ++ ++ vmovdqu 16*0($inp),%x#$T0 ++ vpmuludq $H0,$R3,$M3 ++ vpmuludq $H0,$R4,$M4 ++ vpmuludq $H0,$R0,$M0 ++ vpmuludq $H0,$R1,$M1 ++ vpaddq $M3,$D3,$D3 # d3 += h0*r3 ++ vpaddq $M4,$D4,$D4 # d4 += h0*r4 ++ vpaddq $M0,$D0,$D0 # d0 += h0*r0 ++ vpaddq $M1,$D1,$D1 # d1 += h0*r1 ++ ++ vmovdqu 16*1($inp),%x#$T1 ++ vpmuludq $H1,$R2,$M3 ++ vpmuludq $H1,$R3,$M4 ++ vpmuludq $H1,$S4,$M0 ++ vpmuludq $H0,$R2,$M2 ++ vpaddq $M3,$D3,$D3 # d3 += h1*r2 ++ vpaddq $M4,$D4,$D4 # d4 += h1*r3 ++ vpaddq $M0,$D0,$D0 # d0 += h1*s4 ++ vpaddq $M2,$D2,$D2 # d2 += h0*r2 ++ ++ vinserti128 \$1,16*2($inp),%y#$T0,%y#$T0 ++ vpmuludq $H3,$R0,$M3 ++ vpmuludq $H3,$R1,$M4 ++ vpmuludq $H1,$R0,$M1 ++ vpmuludq $H1,$R1,$M2 ++ vpaddq $M3,$D3,$D3 # d3 += h3*r0 ++ vpaddq $M4,$D4,$D4 # d4 += h3*r1 ++ vpaddq $M1,$D1,$D1 # d1 += h1*r0 ++ vpaddq $M2,$D2,$D2 # d2 += h1*r1 ++ ++ vinserti128 \$1,16*3($inp),%y#$T1,%y#$T1 ++ vpmuludq $H4,$S4,$M3 ++ vpmuludq $H4,$R0,$M4 ++ vpmuludq $H3,$S2,$M0 ++ vpmuludq $H3,$S3,$M1 ++ vpmuludq $H3,$S4,$M2 ++ vpaddq $M3,$D3,$H3 # h3 = d3 + h4*s4 ++ vpaddq $M4,$D4,$D4 # d4 += h4*r0 ++ vpaddq $M0,$D0,$D0 # d0 += h3*s2 ++ vpaddq $M1,$D1,$D1 # d1 += h3*s3 ++ vpaddq $M2,$D2,$D2 # d2 += h3*s4 ++ ++ vpmuludq $H4,$S1,$M0 ++ vpmuludq $H4,$S2,$M1 ++ vpmuludq $H4,$S3,$M2 ++ vpaddq $M0,$D0,$H0 # h0 = d0 + h4*s1 ++ vpaddq $M1,$D1,$H1 # h1 = d2 + h4*s2 ++ vpaddq $M2,$D2,$H2 # h2 = d3 + h4*s3 ++ ++ ################################################################ ++ # horizontal addition ++ ++ mov \$1,%eax ++ vpermq \$0xb1,$H3,$D3 ++ vpermq \$0xb1,$D4,$H4 ++ vpermq \$0xb1,$H0,$D0 ++ vpermq \$0xb1,$H1,$D1 ++ vpermq \$0xb1,$H2,$D2 ++ vpaddq $D3,$H3,$H3 ++ vpaddq $D4,$H4,$H4 ++ vpaddq $D0,$H0,$H0 ++ vpaddq $D1,$H1,$H1 ++ vpaddq $D2,$H2,$H2 ++ ++ kmovw %eax,%k3 ++ vpermq \$0x2,$H3,$D3 ++ vpermq \$0x2,$H4,$D4 ++ vpermq \$0x2,$H0,$D0 ++ vpermq \$0x2,$H1,$D1 ++ vpermq \$0x2,$H2,$D2 ++ vpaddq $D3,$H3,$H3 ++ vpaddq $D4,$H4,$H4 ++ vpaddq $D0,$H0,$H0 ++ vpaddq $D1,$H1,$H1 ++ vpaddq $D2,$H2,$H2 ++ ++ vextracti64x4 \$0x1,$H3,%y#$D3 ++ vextracti64x4 \$0x1,$H4,%y#$D4 ++ vextracti64x4 \$0x1,$H0,%y#$D0 ++ vextracti64x4 \$0x1,$H1,%y#$D1 ++ vextracti64x4 \$0x1,$H2,%y#$D2 ++ vpaddq $D3,$H3,${H3}{%k3}{z} # keep single qword in case ++ vpaddq $D4,$H4,${H4}{%k3}{z} # it's passed to .Ltail_avx2 ++ vpaddq $D0,$H0,${H0}{%k3}{z} ++ vpaddq $D1,$H1,${H1}{%k3}{z} ++ vpaddq $D2,$H2,${H2}{%k3}{z} ++___ ++map(s/%z/%y/,($T0,$T1,$T2,$T3,$T4, $PADBIT)); ++map(s/%z/%y/,($H0,$H1,$H2,$H3,$H4, $D0,$D1,$D2,$D3,$D4, $MASK)); ++$code.=<<___; ++ ################################################################ ++ # lazy reduction (interleaved with input splat) ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpsrldq \$6,$T0,$T2 # splat input ++ vpsrldq \$6,$T1,$T3 ++ vpunpckhqdq $T1,$T0,$T4 # 4 ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpunpcklqdq $T3,$T2,$T2 # 2:3 ++ vpunpcklqdq $T1,$T0,$T0 # 0:1 ++ vpaddq $D0,$H1,$H1 # h0 -> h1 ++ ++ vpsrlq \$26,$H4,$D4 ++ vpand $MASK,$H4,$H4 ++ ++ vpsrlq \$26,$H1,$D1 ++ vpand $MASK,$H1,$H1 ++ vpsrlq \$30,$T2,$T3 ++ vpsrlq \$4,$T2,$T2 ++ vpaddq $D1,$H2,$H2 # h1 -> h2 ++ ++ vpaddq $D4,$H0,$H0 ++ vpsllq \$2,$D4,$D4 ++ vpsrlq \$26,$T0,$T1 ++ vpsrlq \$40,$T4,$T4 # 4 ++ vpaddq $D4,$H0,$H0 # h4 -> h0 ++ ++ vpsrlq \$26,$H2,$D2 ++ vpand $MASK,$H2,$H2 ++ vpand $MASK,$T2,$T2 # 2 ++ vpand $MASK,$T0,$T0 # 0 ++ vpaddq $D2,$H3,$H3 # h2 -> h3 ++ ++ vpsrlq \$26,$H0,$D0 ++ vpand $MASK,$H0,$H0 ++ vpaddq $H2,$T2,$H2 # accumulate input for .Ltail_avx2 ++ vpand $MASK,$T1,$T1 # 1 ++ vpaddq $D0,$H1,$H1 # h0 -> h1 ++ ++ vpsrlq \$26,$H3,$D3 ++ vpand $MASK,$H3,$H3 ++ vpand $MASK,$T3,$T3 # 3 ++ vpor 32(%rcx),$T4,$T4 # padbit, yes, always ++ vpaddq $D3,$H4,$H4 # h3 -> h4 ++ ++ lea 0x90(%rsp),%rax # size optimization for .Ltail_avx2 ++ add \$64,$len ++ jnz .Ltail_avx2 ++ ++ vpsubq $T2,$H2,$H2 # undo input accumulation ++ vmovd %x#$H0,`4*0-48-64`($ctx)# save partially reduced ++ vmovd %x#$H1,`4*1-48-64`($ctx) ++ vmovd %x#$H2,`4*2-48-64`($ctx) ++ vmovd %x#$H3,`4*3-48-64`($ctx) ++ vmovd %x#$H4,`4*4-48-64`($ctx) ++ vzeroall ++___ ++$code.=<<___ if ($win64); ++ movdqa 0x50(%r11),%xmm6 ++ movdqa 0x60(%r11),%xmm7 ++ movdqa 0x70(%r11),%xmm8 ++ movdqa 0x80(%r11),%xmm9 ++ movdqa 0x90(%r11),%xmm10 ++ movdqa 0xa0(%r11),%xmm11 ++ movdqa 0xb0(%r11),%xmm12 ++ movdqa 0xc0(%r11),%xmm13 ++ movdqa 0xd0(%r11),%xmm14 ++ movdqa 0xe0(%r11),%xmm15 ++ lea 0xf8(%r11),%rsp ++.Ldo_avx512_epilogue: ++___ ++$code.=<<___ if (!$win64); ++ lea 8(%r11),%rsp ++.cfi_def_cfa %rsp,8 ++___ ++$code.=<<___; ++ ret ++.cfi_endproc ++.size poly1305_blocks_avx512,.-poly1305_blocks_avx512 ++___ ++if ($avx>3) { ++######################################################################## ++# VPMADD52 version using 2^44 radix. ++# ++# One can argue that base 2^52 would be more natural. Well, even though ++# some operations would be more natural, one has to recognize couple of ++# things. Base 2^52 doesn't provide advantage over base 2^44 if you look ++# at amount of multiply-n-accumulate operations. Secondly, it makes it ++# impossible to pre-compute multiples of 5 [referred to as s[]/sN in ++# reference implementations], which means that more such operations ++# would have to be performed in inner loop, which in turn makes critical ++# path longer. In other words, even though base 2^44 reduction might ++# look less elegant, overall critical path is actually shorter... ++ ++######################################################################## ++# Layout of opaque area is following. ++# ++# unsigned __int64 h[3]; # current hash value base 2^44 ++# unsigned __int64 s[2]; # key value*20 base 2^44 ++# unsigned __int64 r[3]; # key value base 2^44 ++# struct { unsigned __int64 r^1, r^3, r^2, r^4; } R[4]; ++# # r^n positions reflect ++# # placement in register, not ++# # memory, R[3] is R[1]*20 ++ ++$code.=<<___; ++.type poly1305_init_base2_44,\@function,3 ++.align 32 ++poly1305_init_base2_44: ++ xor %rax,%rax ++ mov %rax,0($ctx) # initialize hash value ++ mov %rax,8($ctx) ++ mov %rax,16($ctx) ++ ++.Linit_base2_44: ++ lea poly1305_blocks_vpmadd52(%rip),%r10 ++ lea poly1305_emit_base2_44(%rip),%r11 ++ ++ mov \$0x0ffffffc0fffffff,%rax ++ mov \$0x0ffffffc0ffffffc,%rcx ++ and 0($inp),%rax ++ mov \$0x00000fffffffffff,%r8 ++ and 8($inp),%rcx ++ mov \$0x00000fffffffffff,%r9 ++ and %rax,%r8 ++ shrd \$44,%rcx,%rax ++ mov %r8,40($ctx) # r0 ++ and %r9,%rax ++ shr \$24,%rcx ++ mov %rax,48($ctx) # r1 ++ lea (%rax,%rax,4),%rax # *5 ++ mov %rcx,56($ctx) # r2 ++ shl \$2,%rax # magic <<2 ++ lea (%rcx,%rcx,4),%rcx # *5 ++ shl \$2,%rcx # magic <<2 ++ mov %rax,24($ctx) # s1 ++ mov %rcx,32($ctx) # s2 ++ movq \$-1,64($ctx) # write impossible value ++___ ++$code.=<<___ if ($flavour !~ /elf32/); ++ mov %r10,0(%rdx) ++ mov %r11,8(%rdx) ++___ ++$code.=<<___ if ($flavour =~ /elf32/); ++ mov %r10d,0(%rdx) ++ mov %r11d,4(%rdx) ++___ ++$code.=<<___; ++ mov \$1,%eax ++ ret ++.size poly1305_init_base2_44,.-poly1305_init_base2_44 ++___ ++{ ++my ($H0,$H1,$H2,$r2r1r0,$r1r0s2,$r0s2s1,$Dlo,$Dhi) = map("%ymm$_",(0..5,16,17)); ++my ($T0,$inp_permd,$inp_shift,$PAD) = map("%ymm$_",(18..21)); ++my ($reduc_mask,$reduc_rght,$reduc_left) = map("%ymm$_",(22..25)); ++ ++$code.=<<___; ++.type poly1305_blocks_vpmadd52,\@function,4 ++.align 32 ++poly1305_blocks_vpmadd52: ++ shr \$4,$len ++ jz .Lno_data_vpmadd52 # too short ++ ++ shl \$40,$padbit ++ mov 64($ctx),%r8 # peek on power of the key ++ ++ # if powers of the key are not calculated yet, process up to 3 ++ # blocks with this single-block subroutine, otherwise ensure that ++ # length is divisible by 2 blocks and pass the rest down to next ++ # subroutine... ++ ++ mov \$3,%rax ++ mov \$1,%r10 ++ cmp \$4,$len # is input long ++ cmovae %r10,%rax ++ test %r8,%r8 # is power value impossible? ++ cmovns %r10,%rax ++ ++ and $len,%rax # is input of favourable length? ++ jz .Lblocks_vpmadd52_4x ++ ++ sub %rax,$len ++ mov \$7,%r10d ++ mov \$1,%r11d ++ kmovw %r10d,%k7 ++ lea .L2_44_inp_permd(%rip),%r10 ++ kmovw %r11d,%k1 ++ ++ vmovq $padbit,%x#$PAD ++ vmovdqa64 0(%r10),$inp_permd # .L2_44_inp_permd ++ vmovdqa64 32(%r10),$inp_shift # .L2_44_inp_shift ++ vpermq \$0xcf,$PAD,$PAD ++ vmovdqa64 64(%r10),$reduc_mask # .L2_44_mask ++ ++ vmovdqu64 0($ctx),${Dlo}{%k7}{z} # load hash value ++ vmovdqu64 40($ctx),${r2r1r0}{%k7}{z} # load keys ++ vmovdqu64 32($ctx),${r1r0s2}{%k7}{z} ++ vmovdqu64 24($ctx),${r0s2s1}{%k7}{z} ++ ++ vmovdqa64 96(%r10),$reduc_rght # .L2_44_shift_rgt ++ vmovdqa64 128(%r10),$reduc_left # .L2_44_shift_lft ++ ++ jmp .Loop_vpmadd52 ++ ++.align 32 ++.Loop_vpmadd52: ++ vmovdqu32 0($inp),%x#$T0 # load input as ----3210 ++ lea 16($inp),$inp ++ ++ vpermd $T0,$inp_permd,$T0 # ----3210 -> --322110 ++ vpsrlvq $inp_shift,$T0,$T0 ++ vpandq $reduc_mask,$T0,$T0 ++ vporq $PAD,$T0,$T0 ++ ++ vpaddq $T0,$Dlo,$Dlo # accumulate input ++ ++ vpermq \$0,$Dlo,${H0}{%k7}{z} # smash hash value ++ vpermq \$0b01010101,$Dlo,${H1}{%k7}{z} ++ vpermq \$0b10101010,$Dlo,${H2}{%k7}{z} ++ ++ vpxord $Dlo,$Dlo,$Dlo ++ vpxord $Dhi,$Dhi,$Dhi ++ ++ vpmadd52luq $r2r1r0,$H0,$Dlo ++ vpmadd52huq $r2r1r0,$H0,$Dhi ++ ++ vpmadd52luq $r1r0s2,$H1,$Dlo ++ vpmadd52huq $r1r0s2,$H1,$Dhi ++ ++ vpmadd52luq $r0s2s1,$H2,$Dlo ++ vpmadd52huq $r0s2s1,$H2,$Dhi ++ ++ vpsrlvq $reduc_rght,$Dlo,$T0 # 0 in topmost qword ++ vpsllvq $reduc_left,$Dhi,$Dhi # 0 in topmost qword ++ vpandq $reduc_mask,$Dlo,$Dlo ++ ++ vpaddq $T0,$Dhi,$Dhi ++ ++ vpermq \$0b10010011,$Dhi,$Dhi # 0 in lowest qword ++ ++ vpaddq $Dhi,$Dlo,$Dlo # note topmost qword :-) ++ ++ vpsrlvq $reduc_rght,$Dlo,$T0 # 0 in topmost word ++ vpandq $reduc_mask,$Dlo,$Dlo ++ ++ vpermq \$0b10010011,$T0,$T0 ++ ++ vpaddq $T0,$Dlo,$Dlo ++ ++ vpermq \$0b10010011,$Dlo,${T0}{%k1}{z} ++ ++ vpaddq $T0,$Dlo,$Dlo ++ vpsllq \$2,$T0,$T0 ++ ++ vpaddq $T0,$Dlo,$Dlo ++ ++ dec %rax # len-=16 ++ jnz .Loop_vpmadd52 ++ ++ vmovdqu64 $Dlo,0($ctx){%k7} # store hash value ++ ++ test $len,$len ++ jnz .Lblocks_vpmadd52_4x ++ ++.Lno_data_vpmadd52: ++ ret ++.size poly1305_blocks_vpmadd52,.-poly1305_blocks_vpmadd52 ++___ ++} ++{ ++######################################################################## ++# As implied by its name 4x subroutine processes 4 blocks in parallel ++# (but handles even 4*n+2 blocks lengths). It takes up to 4th key power ++# and is handled in 256-bit %ymm registers. ++ ++my ($H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2) = map("%ymm$_",(0..5,16,17)); ++my ($D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi) = map("%ymm$_",(18..23)); ++my ($T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD) = map("%ymm$_",(24..31)); ++ ++$code.=<<___; ++.type poly1305_blocks_vpmadd52_4x,\@function,4 ++.align 32 ++poly1305_blocks_vpmadd52_4x: ++ shr \$4,$len ++ jz .Lno_data_vpmadd52_4x # too short ++ ++ shl \$40,$padbit ++ mov 64($ctx),%r8 # peek on power of the key ++ ++.Lblocks_vpmadd52_4x: ++ vpbroadcastq $padbit,$PAD ++ ++ vmovdqa64 .Lx_mask44(%rip),$mask44 ++ mov \$5,%eax ++ vmovdqa64 .Lx_mask42(%rip),$mask42 ++ kmovw %eax,%k1 # used in 2x path ++ ++ test %r8,%r8 # is power value impossible? ++ js .Linit_vpmadd52 # if it is, then init R[4] ++ ++ vmovq 0($ctx),%x#$H0 # load current hash value ++ vmovq 8($ctx),%x#$H1 ++ vmovq 16($ctx),%x#$H2 ++ ++ test \$3,$len # is length 4*n+2? ++ jnz .Lblocks_vpmadd52_2x_do ++ ++.Lblocks_vpmadd52_4x_do: ++ vpbroadcastq 64($ctx),$R0 # load 4th power of the key ++ vpbroadcastq 96($ctx),$R1 ++ vpbroadcastq 128($ctx),$R2 ++ vpbroadcastq 160($ctx),$S1 ++ ++.Lblocks_vpmadd52_4x_key_loaded: ++ vpsllq \$2,$R2,$S2 # S2 = R2*5*4 ++ vpaddq $R2,$S2,$S2 ++ vpsllq \$2,$S2,$S2 ++ ++ test \$7,$len # is len 8*n? ++ jz .Lblocks_vpmadd52_8x ++ ++ vmovdqu64 16*0($inp),$T2 # load data ++ vmovdqu64 16*2($inp),$T3 ++ lea 16*4($inp),$inp ++ ++ vpunpcklqdq $T3,$T2,$T1 # transpose data ++ vpunpckhqdq $T3,$T2,$T3 ++ ++ # at this point 64-bit lanes are ordered as 3-1-2-0 ++ ++ vpsrlq \$24,$T3,$T2 # splat the data ++ vporq $PAD,$T2,$T2 ++ vpaddq $T2,$H2,$H2 # accumulate input ++ vpandq $mask44,$T1,$T0 ++ vpsrlq \$44,$T1,$T1 ++ vpsllq \$20,$T3,$T3 ++ vporq $T3,$T1,$T1 ++ vpandq $mask44,$T1,$T1 ++ ++ sub \$4,$len ++ jz .Ltail_vpmadd52_4x ++ jmp .Loop_vpmadd52_4x ++ ud2 ++ ++.align 32 ++.Linit_vpmadd52: ++ vmovq 24($ctx),%x#$S1 # load key ++ vmovq 56($ctx),%x#$H2 ++ vmovq 32($ctx),%x#$S2 ++ vmovq 40($ctx),%x#$R0 ++ vmovq 48($ctx),%x#$R1 ++ ++ vmovdqa $R0,$H0 ++ vmovdqa $R1,$H1 ++ vmovdqa $H2,$R2 ++ ++ mov \$2,%eax ++ ++.Lmul_init_vpmadd52: ++ vpxorq $D0lo,$D0lo,$D0lo ++ vpmadd52luq $H2,$S1,$D0lo ++ vpxorq $D0hi,$D0hi,$D0hi ++ vpmadd52huq $H2,$S1,$D0hi ++ vpxorq $D1lo,$D1lo,$D1lo ++ vpmadd52luq $H2,$S2,$D1lo ++ vpxorq $D1hi,$D1hi,$D1hi ++ vpmadd52huq $H2,$S2,$D1hi ++ vpxorq $D2lo,$D2lo,$D2lo ++ vpmadd52luq $H2,$R0,$D2lo ++ vpxorq $D2hi,$D2hi,$D2hi ++ vpmadd52huq $H2,$R0,$D2hi ++ ++ vpmadd52luq $H0,$R0,$D0lo ++ vpmadd52huq $H0,$R0,$D0hi ++ vpmadd52luq $H0,$R1,$D1lo ++ vpmadd52huq $H0,$R1,$D1hi ++ vpmadd52luq $H0,$R2,$D2lo ++ vpmadd52huq $H0,$R2,$D2hi ++ ++ vpmadd52luq $H1,$S2,$D0lo ++ vpmadd52huq $H1,$S2,$D0hi ++ vpmadd52luq $H1,$R0,$D1lo ++ vpmadd52huq $H1,$R0,$D1hi ++ vpmadd52luq $H1,$R1,$D2lo ++ vpmadd52huq $H1,$R1,$D2hi ++ ++ ################################################################ ++ # partial reduction ++ vpsrlq \$44,$D0lo,$tmp ++ vpsllq \$8,$D0hi,$D0hi ++ vpandq $mask44,$D0lo,$H0 ++ vpaddq $tmp,$D0hi,$D0hi ++ ++ vpaddq $D0hi,$D1lo,$D1lo ++ ++ vpsrlq \$44,$D1lo,$tmp ++ vpsllq \$8,$D1hi,$D1hi ++ vpandq $mask44,$D1lo,$H1 ++ vpaddq $tmp,$D1hi,$D1hi ++ ++ vpaddq $D1hi,$D2lo,$D2lo ++ ++ vpsrlq \$42,$D2lo,$tmp ++ vpsllq \$10,$D2hi,$D2hi ++ vpandq $mask42,$D2lo,$H2 ++ vpaddq $tmp,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ vpsllq \$2,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ ++ vpsrlq \$44,$H0,$tmp # additional step ++ vpandq $mask44,$H0,$H0 ++ ++ vpaddq $tmp,$H1,$H1 ++ ++ dec %eax ++ jz .Ldone_init_vpmadd52 ++ ++ vpunpcklqdq $R1,$H1,$R1 # 1,2 ++ vpbroadcastq %x#$H1,%x#$H1 # 2,2 ++ vpunpcklqdq $R2,$H2,$R2 ++ vpbroadcastq %x#$H2,%x#$H2 ++ vpunpcklqdq $R0,$H0,$R0 ++ vpbroadcastq %x#$H0,%x#$H0 ++ ++ vpsllq \$2,$R1,$S1 # S1 = R1*5*4 ++ vpsllq \$2,$R2,$S2 # S2 = R2*5*4 ++ vpaddq $R1,$S1,$S1 ++ vpaddq $R2,$S2,$S2 ++ vpsllq \$2,$S1,$S1 ++ vpsllq \$2,$S2,$S2 ++ ++ jmp .Lmul_init_vpmadd52 ++ ud2 ++ ++.align 32 ++.Ldone_init_vpmadd52: ++ vinserti128 \$1,%x#$R1,$H1,$R1 # 1,2,3,4 ++ vinserti128 \$1,%x#$R2,$H2,$R2 ++ vinserti128 \$1,%x#$R0,$H0,$R0 ++ ++ vpermq \$0b11011000,$R1,$R1 # 1,3,2,4 ++ vpermq \$0b11011000,$R2,$R2 ++ vpermq \$0b11011000,$R0,$R0 ++ ++ vpsllq \$2,$R1,$S1 # S1 = R1*5*4 ++ vpaddq $R1,$S1,$S1 ++ vpsllq \$2,$S1,$S1 ++ ++ vmovq 0($ctx),%x#$H0 # load current hash value ++ vmovq 8($ctx),%x#$H1 ++ vmovq 16($ctx),%x#$H2 ++ ++ test \$3,$len # is length 4*n+2? ++ jnz .Ldone_init_vpmadd52_2x ++ ++ vmovdqu64 $R0,64($ctx) # save key powers ++ vpbroadcastq %x#$R0,$R0 # broadcast 4th power ++ vmovdqu64 $R1,96($ctx) ++ vpbroadcastq %x#$R1,$R1 ++ vmovdqu64 $R2,128($ctx) ++ vpbroadcastq %x#$R2,$R2 ++ vmovdqu64 $S1,160($ctx) ++ vpbroadcastq %x#$S1,$S1 ++ ++ jmp .Lblocks_vpmadd52_4x_key_loaded ++ ud2 ++ ++.align 32 ++.Ldone_init_vpmadd52_2x: ++ vmovdqu64 $R0,64($ctx) # save key powers ++ vpsrldq \$8,$R0,$R0 # 0-1-0-2 ++ vmovdqu64 $R1,96($ctx) ++ vpsrldq \$8,$R1,$R1 ++ vmovdqu64 $R2,128($ctx) ++ vpsrldq \$8,$R2,$R2 ++ vmovdqu64 $S1,160($ctx) ++ vpsrldq \$8,$S1,$S1 ++ jmp .Lblocks_vpmadd52_2x_key_loaded ++ ud2 ++ ++.align 32 ++.Lblocks_vpmadd52_2x_do: ++ vmovdqu64 128+8($ctx),${R2}{%k1}{z}# load 2nd and 1st key powers ++ vmovdqu64 160+8($ctx),${S1}{%k1}{z} ++ vmovdqu64 64+8($ctx),${R0}{%k1}{z} ++ vmovdqu64 96+8($ctx),${R1}{%k1}{z} ++ ++.Lblocks_vpmadd52_2x_key_loaded: ++ vmovdqu64 16*0($inp),$T2 # load data ++ vpxorq $T3,$T3,$T3 ++ lea 16*2($inp),$inp ++ ++ vpunpcklqdq $T3,$T2,$T1 # transpose data ++ vpunpckhqdq $T3,$T2,$T3 ++ ++ # at this point 64-bit lanes are ordered as x-1-x-0 ++ ++ vpsrlq \$24,$T3,$T2 # splat the data ++ vporq $PAD,$T2,$T2 ++ vpaddq $T2,$H2,$H2 # accumulate input ++ vpandq $mask44,$T1,$T0 ++ vpsrlq \$44,$T1,$T1 ++ vpsllq \$20,$T3,$T3 ++ vporq $T3,$T1,$T1 ++ vpandq $mask44,$T1,$T1 ++ ++ jmp .Ltail_vpmadd52_2x ++ ud2 ++ ++.align 32 ++.Loop_vpmadd52_4x: ++ #vpaddq $T2,$H2,$H2 # accumulate input ++ vpaddq $T0,$H0,$H0 ++ vpaddq $T1,$H1,$H1 ++ ++ vpxorq $D0lo,$D0lo,$D0lo ++ vpmadd52luq $H2,$S1,$D0lo ++ vpxorq $D0hi,$D0hi,$D0hi ++ vpmadd52huq $H2,$S1,$D0hi ++ vpxorq $D1lo,$D1lo,$D1lo ++ vpmadd52luq $H2,$S2,$D1lo ++ vpxorq $D1hi,$D1hi,$D1hi ++ vpmadd52huq $H2,$S2,$D1hi ++ vpxorq $D2lo,$D2lo,$D2lo ++ vpmadd52luq $H2,$R0,$D2lo ++ vpxorq $D2hi,$D2hi,$D2hi ++ vpmadd52huq $H2,$R0,$D2hi ++ ++ vmovdqu64 16*0($inp),$T2 # load data ++ vmovdqu64 16*2($inp),$T3 ++ lea 16*4($inp),$inp ++ vpmadd52luq $H0,$R0,$D0lo ++ vpmadd52huq $H0,$R0,$D0hi ++ vpmadd52luq $H0,$R1,$D1lo ++ vpmadd52huq $H0,$R1,$D1hi ++ vpmadd52luq $H0,$R2,$D2lo ++ vpmadd52huq $H0,$R2,$D2hi ++ ++ vpunpcklqdq $T3,$T2,$T1 # transpose data ++ vpunpckhqdq $T3,$T2,$T3 ++ vpmadd52luq $H1,$S2,$D0lo ++ vpmadd52huq $H1,$S2,$D0hi ++ vpmadd52luq $H1,$R0,$D1lo ++ vpmadd52huq $H1,$R0,$D1hi ++ vpmadd52luq $H1,$R1,$D2lo ++ vpmadd52huq $H1,$R1,$D2hi ++ ++ ################################################################ ++ # partial reduction (interleaved with data splat) ++ vpsrlq \$44,$D0lo,$tmp ++ vpsllq \$8,$D0hi,$D0hi ++ vpandq $mask44,$D0lo,$H0 ++ vpaddq $tmp,$D0hi,$D0hi ++ ++ vpsrlq \$24,$T3,$T2 ++ vporq $PAD,$T2,$T2 ++ vpaddq $D0hi,$D1lo,$D1lo ++ ++ vpsrlq \$44,$D1lo,$tmp ++ vpsllq \$8,$D1hi,$D1hi ++ vpandq $mask44,$D1lo,$H1 ++ vpaddq $tmp,$D1hi,$D1hi ++ ++ vpandq $mask44,$T1,$T0 ++ vpsrlq \$44,$T1,$T1 ++ vpsllq \$20,$T3,$T3 ++ vpaddq $D1hi,$D2lo,$D2lo ++ ++ vpsrlq \$42,$D2lo,$tmp ++ vpsllq \$10,$D2hi,$D2hi ++ vpandq $mask42,$D2lo,$H2 ++ vpaddq $tmp,$D2hi,$D2hi ++ ++ vpaddq $T2,$H2,$H2 # accumulate input ++ vpaddq $D2hi,$H0,$H0 ++ vpsllq \$2,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ vporq $T3,$T1,$T1 ++ vpandq $mask44,$T1,$T1 ++ ++ vpsrlq \$44,$H0,$tmp # additional step ++ vpandq $mask44,$H0,$H0 ++ ++ vpaddq $tmp,$H1,$H1 ++ ++ sub \$4,$len # len-=64 ++ jnz .Loop_vpmadd52_4x ++ ++.Ltail_vpmadd52_4x: ++ vmovdqu64 128($ctx),$R2 # load all key powers ++ vmovdqu64 160($ctx),$S1 ++ vmovdqu64 64($ctx),$R0 ++ vmovdqu64 96($ctx),$R1 ++ ++.Ltail_vpmadd52_2x: ++ vpsllq \$2,$R2,$S2 # S2 = R2*5*4 ++ vpaddq $R2,$S2,$S2 ++ vpsllq \$2,$S2,$S2 ++ ++ #vpaddq $T2,$H2,$H2 # accumulate input ++ vpaddq $T0,$H0,$H0 ++ vpaddq $T1,$H1,$H1 ++ ++ vpxorq $D0lo,$D0lo,$D0lo ++ vpmadd52luq $H2,$S1,$D0lo ++ vpxorq $D0hi,$D0hi,$D0hi ++ vpmadd52huq $H2,$S1,$D0hi ++ vpxorq $D1lo,$D1lo,$D1lo ++ vpmadd52luq $H2,$S2,$D1lo ++ vpxorq $D1hi,$D1hi,$D1hi ++ vpmadd52huq $H2,$S2,$D1hi ++ vpxorq $D2lo,$D2lo,$D2lo ++ vpmadd52luq $H2,$R0,$D2lo ++ vpxorq $D2hi,$D2hi,$D2hi ++ vpmadd52huq $H2,$R0,$D2hi ++ ++ vpmadd52luq $H0,$R0,$D0lo ++ vpmadd52huq $H0,$R0,$D0hi ++ vpmadd52luq $H0,$R1,$D1lo ++ vpmadd52huq $H0,$R1,$D1hi ++ vpmadd52luq $H0,$R2,$D2lo ++ vpmadd52huq $H0,$R2,$D2hi ++ ++ vpmadd52luq $H1,$S2,$D0lo ++ vpmadd52huq $H1,$S2,$D0hi ++ vpmadd52luq $H1,$R0,$D1lo ++ vpmadd52huq $H1,$R0,$D1hi ++ vpmadd52luq $H1,$R1,$D2lo ++ vpmadd52huq $H1,$R1,$D2hi ++ ++ ################################################################ ++ # horizontal addition ++ ++ mov \$1,%eax ++ kmovw %eax,%k1 ++ vpsrldq \$8,$D0lo,$T0 ++ vpsrldq \$8,$D0hi,$H0 ++ vpsrldq \$8,$D1lo,$T1 ++ vpsrldq \$8,$D1hi,$H1 ++ vpaddq $T0,$D0lo,$D0lo ++ vpaddq $H0,$D0hi,$D0hi ++ vpsrldq \$8,$D2lo,$T2 ++ vpsrldq \$8,$D2hi,$H2 ++ vpaddq $T1,$D1lo,$D1lo ++ vpaddq $H1,$D1hi,$D1hi ++ vpermq \$0x2,$D0lo,$T0 ++ vpermq \$0x2,$D0hi,$H0 ++ vpaddq $T2,$D2lo,$D2lo ++ vpaddq $H2,$D2hi,$D2hi ++ ++ vpermq \$0x2,$D1lo,$T1 ++ vpermq \$0x2,$D1hi,$H1 ++ vpaddq $T0,$D0lo,${D0lo}{%k1}{z} ++ vpaddq $H0,$D0hi,${D0hi}{%k1}{z} ++ vpermq \$0x2,$D2lo,$T2 ++ vpermq \$0x2,$D2hi,$H2 ++ vpaddq $T1,$D1lo,${D1lo}{%k1}{z} ++ vpaddq $H1,$D1hi,${D1hi}{%k1}{z} ++ vpaddq $T2,$D2lo,${D2lo}{%k1}{z} ++ vpaddq $H2,$D2hi,${D2hi}{%k1}{z} ++ ++ ################################################################ ++ # partial reduction ++ vpsrlq \$44,$D0lo,$tmp ++ vpsllq \$8,$D0hi,$D0hi ++ vpandq $mask44,$D0lo,$H0 ++ vpaddq $tmp,$D0hi,$D0hi ++ ++ vpaddq $D0hi,$D1lo,$D1lo ++ ++ vpsrlq \$44,$D1lo,$tmp ++ vpsllq \$8,$D1hi,$D1hi ++ vpandq $mask44,$D1lo,$H1 ++ vpaddq $tmp,$D1hi,$D1hi ++ ++ vpaddq $D1hi,$D2lo,$D2lo ++ ++ vpsrlq \$42,$D2lo,$tmp ++ vpsllq \$10,$D2hi,$D2hi ++ vpandq $mask42,$D2lo,$H2 ++ vpaddq $tmp,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ vpsllq \$2,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ ++ vpsrlq \$44,$H0,$tmp # additional step ++ vpandq $mask44,$H0,$H0 ++ ++ vpaddq $tmp,$H1,$H1 ++ # at this point $len is ++ # either 4*n+2 or 0... ++ sub \$2,$len # len-=32 ++ ja .Lblocks_vpmadd52_4x_do ++ ++ vmovq %x#$H0,0($ctx) ++ vmovq %x#$H1,8($ctx) ++ vmovq %x#$H2,16($ctx) ++ vzeroall ++ ++.Lno_data_vpmadd52_4x: ++ ret ++.size poly1305_blocks_vpmadd52_4x,.-poly1305_blocks_vpmadd52_4x ++___ ++} ++{ ++######################################################################## ++# As implied by its name 8x subroutine processes 8 blocks in parallel... ++# This is intermediate version, as it's used only in cases when input ++# length is either 8*n, 8*n+1 or 8*n+2... ++ ++my ($H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2) = map("%ymm$_",(0..5,16,17)); ++my ($D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi) = map("%ymm$_",(18..23)); ++my ($T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD) = map("%ymm$_",(24..31)); ++my ($RR0,$RR1,$RR2,$SS1,$SS2) = map("%ymm$_",(6..10)); ++ ++$code.=<<___; ++.type poly1305_blocks_vpmadd52_8x,\@function,4 ++.align 32 ++poly1305_blocks_vpmadd52_8x: ++ shr \$4,$len ++ jz .Lno_data_vpmadd52_8x # too short ++ ++ shl \$40,$padbit ++ mov 64($ctx),%r8 # peek on power of the key ++ ++ vmovdqa64 .Lx_mask44(%rip),$mask44 ++ vmovdqa64 .Lx_mask42(%rip),$mask42 ++ ++ test %r8,%r8 # is power value impossible? ++ js .Linit_vpmadd52 # if it is, then init R[4] ++ ++ vmovq 0($ctx),%x#$H0 # load current hash value ++ vmovq 8($ctx),%x#$H1 ++ vmovq 16($ctx),%x#$H2 ++ ++.Lblocks_vpmadd52_8x: ++ ################################################################ ++ # fist we calculate more key powers ++ ++ vmovdqu64 128($ctx),$R2 # load 1-3-2-4 powers ++ vmovdqu64 160($ctx),$S1 ++ vmovdqu64 64($ctx),$R0 ++ vmovdqu64 96($ctx),$R1 ++ ++ vpsllq \$2,$R2,$S2 # S2 = R2*5*4 ++ vpaddq $R2,$S2,$S2 ++ vpsllq \$2,$S2,$S2 ++ ++ vpbroadcastq %x#$R2,$RR2 # broadcast 4th power ++ vpbroadcastq %x#$R0,$RR0 ++ vpbroadcastq %x#$R1,$RR1 ++ ++ vpxorq $D0lo,$D0lo,$D0lo ++ vpmadd52luq $RR2,$S1,$D0lo ++ vpxorq $D0hi,$D0hi,$D0hi ++ vpmadd52huq $RR2,$S1,$D0hi ++ vpxorq $D1lo,$D1lo,$D1lo ++ vpmadd52luq $RR2,$S2,$D1lo ++ vpxorq $D1hi,$D1hi,$D1hi ++ vpmadd52huq $RR2,$S2,$D1hi ++ vpxorq $D2lo,$D2lo,$D2lo ++ vpmadd52luq $RR2,$R0,$D2lo ++ vpxorq $D2hi,$D2hi,$D2hi ++ vpmadd52huq $RR2,$R0,$D2hi ++ ++ vpmadd52luq $RR0,$R0,$D0lo ++ vpmadd52huq $RR0,$R0,$D0hi ++ vpmadd52luq $RR0,$R1,$D1lo ++ vpmadd52huq $RR0,$R1,$D1hi ++ vpmadd52luq $RR0,$R2,$D2lo ++ vpmadd52huq $RR0,$R2,$D2hi ++ ++ vpmadd52luq $RR1,$S2,$D0lo ++ vpmadd52huq $RR1,$S2,$D0hi ++ vpmadd52luq $RR1,$R0,$D1lo ++ vpmadd52huq $RR1,$R0,$D1hi ++ vpmadd52luq $RR1,$R1,$D2lo ++ vpmadd52huq $RR1,$R1,$D2hi ++ ++ ################################################################ ++ # partial reduction ++ vpsrlq \$44,$D0lo,$tmp ++ vpsllq \$8,$D0hi,$D0hi ++ vpandq $mask44,$D0lo,$RR0 ++ vpaddq $tmp,$D0hi,$D0hi ++ ++ vpaddq $D0hi,$D1lo,$D1lo ++ ++ vpsrlq \$44,$D1lo,$tmp ++ vpsllq \$8,$D1hi,$D1hi ++ vpandq $mask44,$D1lo,$RR1 ++ vpaddq $tmp,$D1hi,$D1hi ++ ++ vpaddq $D1hi,$D2lo,$D2lo ++ ++ vpsrlq \$42,$D2lo,$tmp ++ vpsllq \$10,$D2hi,$D2hi ++ vpandq $mask42,$D2lo,$RR2 ++ vpaddq $tmp,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$RR0,$RR0 ++ vpsllq \$2,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$RR0,$RR0 ++ ++ vpsrlq \$44,$RR0,$tmp # additional step ++ vpandq $mask44,$RR0,$RR0 ++ ++ vpaddq $tmp,$RR1,$RR1 ++ ++ ################################################################ ++ # At this point Rx holds 1324 powers, RRx - 5768, and the goal ++ # is 15263748, which reflects how data is loaded... ++ ++ vpunpcklqdq $R2,$RR2,$T2 # 3748 ++ vpunpckhqdq $R2,$RR2,$R2 # 1526 ++ vpunpcklqdq $R0,$RR0,$T0 ++ vpunpckhqdq $R0,$RR0,$R0 ++ vpunpcklqdq $R1,$RR1,$T1 ++ vpunpckhqdq $R1,$RR1,$R1 ++___ ++######## switch to %zmm ++map(s/%y/%z/, $H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2); ++map(s/%y/%z/, $D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi); ++map(s/%y/%z/, $T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD); ++map(s/%y/%z/, $RR0,$RR1,$RR2,$SS1,$SS2); ++ ++$code.=<<___; ++ vshufi64x2 \$0x44,$R2,$T2,$RR2 # 15263748 ++ vshufi64x2 \$0x44,$R0,$T0,$RR0 ++ vshufi64x2 \$0x44,$R1,$T1,$RR1 ++ ++ vmovdqu64 16*0($inp),$T2 # load data ++ vmovdqu64 16*4($inp),$T3 ++ lea 16*8($inp),$inp ++ ++ vpsllq \$2,$RR2,$SS2 # S2 = R2*5*4 ++ vpsllq \$2,$RR1,$SS1 # S1 = R1*5*4 ++ vpaddq $RR2,$SS2,$SS2 ++ vpaddq $RR1,$SS1,$SS1 ++ vpsllq \$2,$SS2,$SS2 ++ vpsllq \$2,$SS1,$SS1 ++ ++ vpbroadcastq $padbit,$PAD ++ vpbroadcastq %x#$mask44,$mask44 ++ vpbroadcastq %x#$mask42,$mask42 ++ ++ vpbroadcastq %x#$SS1,$S1 # broadcast 8th power ++ vpbroadcastq %x#$SS2,$S2 ++ vpbroadcastq %x#$RR0,$R0 ++ vpbroadcastq %x#$RR1,$R1 ++ vpbroadcastq %x#$RR2,$R2 ++ ++ vpunpcklqdq $T3,$T2,$T1 # transpose data ++ vpunpckhqdq $T3,$T2,$T3 ++ ++ # at this point 64-bit lanes are ordered as 73625140 ++ ++ vpsrlq \$24,$T3,$T2 # splat the data ++ vporq $PAD,$T2,$T2 ++ vpaddq $T2,$H2,$H2 # accumulate input ++ vpandq $mask44,$T1,$T0 ++ vpsrlq \$44,$T1,$T1 ++ vpsllq \$20,$T3,$T3 ++ vporq $T3,$T1,$T1 ++ vpandq $mask44,$T1,$T1 ++ ++ sub \$8,$len ++ jz .Ltail_vpmadd52_8x ++ jmp .Loop_vpmadd52_8x ++ ++.align 32 ++.Loop_vpmadd52_8x: ++ #vpaddq $T2,$H2,$H2 # accumulate input ++ vpaddq $T0,$H0,$H0 ++ vpaddq $T1,$H1,$H1 ++ ++ vpxorq $D0lo,$D0lo,$D0lo ++ vpmadd52luq $H2,$S1,$D0lo ++ vpxorq $D0hi,$D0hi,$D0hi ++ vpmadd52huq $H2,$S1,$D0hi ++ vpxorq $D1lo,$D1lo,$D1lo ++ vpmadd52luq $H2,$S2,$D1lo ++ vpxorq $D1hi,$D1hi,$D1hi ++ vpmadd52huq $H2,$S2,$D1hi ++ vpxorq $D2lo,$D2lo,$D2lo ++ vpmadd52luq $H2,$R0,$D2lo ++ vpxorq $D2hi,$D2hi,$D2hi ++ vpmadd52huq $H2,$R0,$D2hi ++ ++ vmovdqu64 16*0($inp),$T2 # load data ++ vmovdqu64 16*4($inp),$T3 ++ lea 16*8($inp),$inp ++ vpmadd52luq $H0,$R0,$D0lo ++ vpmadd52huq $H0,$R0,$D0hi ++ vpmadd52luq $H0,$R1,$D1lo ++ vpmadd52huq $H0,$R1,$D1hi ++ vpmadd52luq $H0,$R2,$D2lo ++ vpmadd52huq $H0,$R2,$D2hi ++ ++ vpunpcklqdq $T3,$T2,$T1 # transpose data ++ vpunpckhqdq $T3,$T2,$T3 ++ vpmadd52luq $H1,$S2,$D0lo ++ vpmadd52huq $H1,$S2,$D0hi ++ vpmadd52luq $H1,$R0,$D1lo ++ vpmadd52huq $H1,$R0,$D1hi ++ vpmadd52luq $H1,$R1,$D2lo ++ vpmadd52huq $H1,$R1,$D2hi ++ ++ ################################################################ ++ # partial reduction (interleaved with data splat) ++ vpsrlq \$44,$D0lo,$tmp ++ vpsllq \$8,$D0hi,$D0hi ++ vpandq $mask44,$D0lo,$H0 ++ vpaddq $tmp,$D0hi,$D0hi ++ ++ vpsrlq \$24,$T3,$T2 ++ vporq $PAD,$T2,$T2 ++ vpaddq $D0hi,$D1lo,$D1lo ++ ++ vpsrlq \$44,$D1lo,$tmp ++ vpsllq \$8,$D1hi,$D1hi ++ vpandq $mask44,$D1lo,$H1 ++ vpaddq $tmp,$D1hi,$D1hi ++ ++ vpandq $mask44,$T1,$T0 ++ vpsrlq \$44,$T1,$T1 ++ vpsllq \$20,$T3,$T3 ++ vpaddq $D1hi,$D2lo,$D2lo ++ ++ vpsrlq \$42,$D2lo,$tmp ++ vpsllq \$10,$D2hi,$D2hi ++ vpandq $mask42,$D2lo,$H2 ++ vpaddq $tmp,$D2hi,$D2hi ++ ++ vpaddq $T2,$H2,$H2 # accumulate input ++ vpaddq $D2hi,$H0,$H0 ++ vpsllq \$2,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ vporq $T3,$T1,$T1 ++ vpandq $mask44,$T1,$T1 ++ ++ vpsrlq \$44,$H0,$tmp # additional step ++ vpandq $mask44,$H0,$H0 ++ ++ vpaddq $tmp,$H1,$H1 ++ ++ sub \$8,$len # len-=128 ++ jnz .Loop_vpmadd52_8x ++ ++.Ltail_vpmadd52_8x: ++ #vpaddq $T2,$H2,$H2 # accumulate input ++ vpaddq $T0,$H0,$H0 ++ vpaddq $T1,$H1,$H1 ++ ++ vpxorq $D0lo,$D0lo,$D0lo ++ vpmadd52luq $H2,$SS1,$D0lo ++ vpxorq $D0hi,$D0hi,$D0hi ++ vpmadd52huq $H2,$SS1,$D0hi ++ vpxorq $D1lo,$D1lo,$D1lo ++ vpmadd52luq $H2,$SS2,$D1lo ++ vpxorq $D1hi,$D1hi,$D1hi ++ vpmadd52huq $H2,$SS2,$D1hi ++ vpxorq $D2lo,$D2lo,$D2lo ++ vpmadd52luq $H2,$RR0,$D2lo ++ vpxorq $D2hi,$D2hi,$D2hi ++ vpmadd52huq $H2,$RR0,$D2hi ++ ++ vpmadd52luq $H0,$RR0,$D0lo ++ vpmadd52huq $H0,$RR0,$D0hi ++ vpmadd52luq $H0,$RR1,$D1lo ++ vpmadd52huq $H0,$RR1,$D1hi ++ vpmadd52luq $H0,$RR2,$D2lo ++ vpmadd52huq $H0,$RR2,$D2hi ++ ++ vpmadd52luq $H1,$SS2,$D0lo ++ vpmadd52huq $H1,$SS2,$D0hi ++ vpmadd52luq $H1,$RR0,$D1lo ++ vpmadd52huq $H1,$RR0,$D1hi ++ vpmadd52luq $H1,$RR1,$D2lo ++ vpmadd52huq $H1,$RR1,$D2hi ++ ++ ################################################################ ++ # horizontal addition ++ ++ mov \$1,%eax ++ kmovw %eax,%k1 ++ vpsrldq \$8,$D0lo,$T0 ++ vpsrldq \$8,$D0hi,$H0 ++ vpsrldq \$8,$D1lo,$T1 ++ vpsrldq \$8,$D1hi,$H1 ++ vpaddq $T0,$D0lo,$D0lo ++ vpaddq $H0,$D0hi,$D0hi ++ vpsrldq \$8,$D2lo,$T2 ++ vpsrldq \$8,$D2hi,$H2 ++ vpaddq $T1,$D1lo,$D1lo ++ vpaddq $H1,$D1hi,$D1hi ++ vpermq \$0x2,$D0lo,$T0 ++ vpermq \$0x2,$D0hi,$H0 ++ vpaddq $T2,$D2lo,$D2lo ++ vpaddq $H2,$D2hi,$D2hi ++ ++ vpermq \$0x2,$D1lo,$T1 ++ vpermq \$0x2,$D1hi,$H1 ++ vpaddq $T0,$D0lo,$D0lo ++ vpaddq $H0,$D0hi,$D0hi ++ vpermq \$0x2,$D2lo,$T2 ++ vpermq \$0x2,$D2hi,$H2 ++ vpaddq $T1,$D1lo,$D1lo ++ vpaddq $H1,$D1hi,$D1hi ++ vextracti64x4 \$1,$D0lo,%y#$T0 ++ vextracti64x4 \$1,$D0hi,%y#$H0 ++ vpaddq $T2,$D2lo,$D2lo ++ vpaddq $H2,$D2hi,$D2hi ++ ++ vextracti64x4 \$1,$D1lo,%y#$T1 ++ vextracti64x4 \$1,$D1hi,%y#$H1 ++ vextracti64x4 \$1,$D2lo,%y#$T2 ++ vextracti64x4 \$1,$D2hi,%y#$H2 ++___ ++######## switch back to %ymm ++map(s/%z/%y/, $H0,$H1,$H2,$R0,$R1,$R2,$S1,$S2); ++map(s/%z/%y/, $D0lo,$D0hi,$D1lo,$D1hi,$D2lo,$D2hi); ++map(s/%z/%y/, $T0,$T1,$T2,$T3,$mask44,$mask42,$tmp,$PAD); ++ ++$code.=<<___; ++ vpaddq $T0,$D0lo,${D0lo}{%k1}{z} ++ vpaddq $H0,$D0hi,${D0hi}{%k1}{z} ++ vpaddq $T1,$D1lo,${D1lo}{%k1}{z} ++ vpaddq $H1,$D1hi,${D1hi}{%k1}{z} ++ vpaddq $T2,$D2lo,${D2lo}{%k1}{z} ++ vpaddq $H2,$D2hi,${D2hi}{%k1}{z} ++ ++ ################################################################ ++ # partial reduction ++ vpsrlq \$44,$D0lo,$tmp ++ vpsllq \$8,$D0hi,$D0hi ++ vpandq $mask44,$D0lo,$H0 ++ vpaddq $tmp,$D0hi,$D0hi ++ ++ vpaddq $D0hi,$D1lo,$D1lo ++ ++ vpsrlq \$44,$D1lo,$tmp ++ vpsllq \$8,$D1hi,$D1hi ++ vpandq $mask44,$D1lo,$H1 ++ vpaddq $tmp,$D1hi,$D1hi ++ ++ vpaddq $D1hi,$D2lo,$D2lo ++ ++ vpsrlq \$42,$D2lo,$tmp ++ vpsllq \$10,$D2hi,$D2hi ++ vpandq $mask42,$D2lo,$H2 ++ vpaddq $tmp,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ vpsllq \$2,$D2hi,$D2hi ++ ++ vpaddq $D2hi,$H0,$H0 ++ ++ vpsrlq \$44,$H0,$tmp # additional step ++ vpandq $mask44,$H0,$H0 ++ ++ vpaddq $tmp,$H1,$H1 ++ ++ ################################################################ ++ ++ vmovq %x#$H0,0($ctx) ++ vmovq %x#$H1,8($ctx) ++ vmovq %x#$H2,16($ctx) ++ vzeroall ++ ++.Lno_data_vpmadd52_8x: ++ ret ++.size poly1305_blocks_vpmadd52_8x,.-poly1305_blocks_vpmadd52_8x ++___ ++} ++$code.=<<___; ++.type poly1305_emit_base2_44,\@function,3 ++.align 32 ++poly1305_emit_base2_44: ++ mov 0($ctx),%r8 # load hash value ++ mov 8($ctx),%r9 ++ mov 16($ctx),%r10 ++ ++ mov %r9,%rax ++ shr \$20,%r9 ++ shl \$44,%rax ++ mov %r10,%rcx ++ shr \$40,%r10 ++ shl \$24,%rcx ++ ++ add %rax,%r8 ++ adc %rcx,%r9 ++ adc \$0,%r10 ++ ++ mov %r8,%rax ++ add \$5,%r8 # compare to modulus ++ mov %r9,%rcx ++ adc \$0,%r9 ++ adc \$0,%r10 ++ shr \$2,%r10 # did 130-bit value overflow? ++ cmovnz %r8,%rax ++ cmovnz %r9,%rcx ++ ++ add 0($nonce),%rax # accumulate nonce ++ adc 8($nonce),%rcx ++ mov %rax,0($mac) # write result ++ mov %rcx,8($mac) ++ ++ ret ++.size poly1305_emit_base2_44,.-poly1305_emit_base2_44 ++___ ++} } } ++$code.=<<___; ++.align 64 ++.Lconst: ++.Lmask24: ++.long 0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0 ++.L129: ++.long `1<<24`,0,`1<<24`,0,`1<<24`,0,`1<<24`,0 ++.Lmask26: ++.long 0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0 ++.Lpermd_avx2: ++.long 2,2,2,3,2,0,2,1 ++.Lpermd_avx512: ++.long 0,0,0,1, 0,2,0,3, 0,4,0,5, 0,6,0,7 ++ ++.L2_44_inp_permd: ++.long 0,1,1,2,2,3,7,7 ++.L2_44_inp_shift: ++.quad 0,12,24,64 ++.L2_44_mask: ++.quad 0xfffffffffff,0xfffffffffff,0x3ffffffffff,0xffffffffffffffff ++.L2_44_shift_rgt: ++.quad 44,44,42,64 ++.L2_44_shift_lft: ++.quad 8,8,10,64 ++ ++.align 64 ++.Lx_mask44: ++.quad 0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff ++.quad 0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff ++.Lx_mask42: ++.quad 0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff ++.quad 0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff ++___ ++} ++$code.=<<___; ++.asciz "Poly1305 for x86_64, CRYPTOGAMS by " ++.align 16 ++___ ++ ++{ # chacha20-poly1305 helpers ++my ($out,$inp,$otp,$len)=$win64 ? ("%rcx","%rdx","%r8", "%r9") : # Win64 order ++ ("%rdi","%rsi","%rdx","%rcx"); # Unix order ++$code.=<<___; ++.globl xor128_encrypt_n_pad ++.type xor128_encrypt_n_pad,\@abi-omnipotent ++.align 16 ++xor128_encrypt_n_pad: ++ sub $otp,$inp ++ sub $otp,$out ++ mov $len,%r10 # put len aside ++ shr \$4,$len # len / 16 ++ jz .Ltail_enc ++ nop ++.Loop_enc_xmm: ++ movdqu ($inp,$otp),%xmm0 ++ pxor ($otp),%xmm0 ++ movdqu %xmm0,($out,$otp) ++ movdqa %xmm0,($otp) ++ lea 16($otp),$otp ++ dec $len ++ jnz .Loop_enc_xmm ++ ++ and \$15,%r10 # len % 16 ++ jz .Ldone_enc ++ ++.Ltail_enc: ++ mov \$16,$len ++ sub %r10,$len ++ xor %eax,%eax ++.Loop_enc_byte: ++ mov ($inp,$otp),%al ++ xor ($otp),%al ++ mov %al,($out,$otp) ++ mov %al,($otp) ++ lea 1($otp),$otp ++ dec %r10 ++ jnz .Loop_enc_byte ++ ++ xor %eax,%eax ++.Loop_enc_pad: ++ mov %al,($otp) ++ lea 1($otp),$otp ++ dec $len ++ jnz .Loop_enc_pad ++ ++.Ldone_enc: ++ mov $otp,%rax ++ ret ++.size xor128_encrypt_n_pad,.-xor128_encrypt_n_pad ++ ++.globl xor128_decrypt_n_pad ++.type xor128_decrypt_n_pad,\@abi-omnipotent ++.align 16 ++xor128_decrypt_n_pad: ++ sub $otp,$inp ++ sub $otp,$out ++ mov $len,%r10 # put len aside ++ shr \$4,$len # len / 16 ++ jz .Ltail_dec ++ nop ++.Loop_dec_xmm: ++ movdqu ($inp,$otp),%xmm0 ++ movdqa ($otp),%xmm1 ++ pxor %xmm0,%xmm1 ++ movdqu %xmm1,($out,$otp) ++ movdqa %xmm0,($otp) ++ lea 16($otp),$otp ++ dec $len ++ jnz .Loop_dec_xmm ++ ++ pxor %xmm1,%xmm1 ++ and \$15,%r10 # len % 16 ++ jz .Ldone_dec ++ ++.Ltail_dec: ++ mov \$16,$len ++ sub %r10,$len ++ xor %eax,%eax ++ xor %r11,%r11 ++.Loop_dec_byte: ++ mov ($inp,$otp),%r11b ++ mov ($otp),%al ++ xor %r11b,%al ++ mov %al,($out,$otp) ++ mov %r11b,($otp) ++ lea 1($otp),$otp ++ dec %r10 ++ jnz .Loop_dec_byte ++ ++ xor %eax,%eax ++.Loop_dec_pad: ++ mov %al,($otp) ++ lea 1($otp),$otp ++ dec $len ++ jnz .Loop_dec_pad ++ ++.Ldone_dec: ++ mov $otp,%rax ++ ret ++.size xor128_decrypt_n_pad,.-xor128_decrypt_n_pad ++___ ++} ++ ++# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, ++# CONTEXT *context,DISPATCHER_CONTEXT *disp) ++if ($win64) { ++$rec="%rcx"; ++$frame="%rdx"; ++$context="%r8"; ++$disp="%r9"; ++ ++$code.=<<___; ++.extern __imp_RtlVirtualUnwind ++.type se_handler,\@abi-omnipotent ++.align 16 ++se_handler: ++ push %rsi ++ push %rdi ++ push %rbx ++ push %rbp ++ push %r12 ++ push %r13 ++ push %r14 ++ push %r15 ++ pushfq ++ sub \$64,%rsp ++ ++ mov 120($context),%rax # pull context->Rax ++ mov 248($context),%rbx # pull context->Rip ++ ++ mov 8($disp),%rsi # disp->ImageBase ++ mov 56($disp),%r11 # disp->HandlerData ++ ++ mov 0(%r11),%r10d # HandlerData[0] ++ lea (%rsi,%r10),%r10 # prologue label ++ cmp %r10,%rbx # context->Rip<.Lprologue ++ jb .Lcommon_seh_tail ++ ++ mov 152($context),%rax # pull context->Rsp ++ ++ mov 4(%r11),%r10d # HandlerData[1] ++ lea (%rsi,%r10),%r10 # epilogue label ++ cmp %r10,%rbx # context->Rip>=.Lepilogue ++ jae .Lcommon_seh_tail ++ ++ lea 48(%rax),%rax ++ ++ mov -8(%rax),%rbx ++ mov -16(%rax),%rbp ++ mov -24(%rax),%r12 ++ mov -32(%rax),%r13 ++ mov -40(%rax),%r14 ++ mov -48(%rax),%r15 ++ mov %rbx,144($context) # restore context->Rbx ++ mov %rbp,160($context) # restore context->Rbp ++ mov %r12,216($context) # restore context->R12 ++ mov %r13,224($context) # restore context->R13 ++ mov %r14,232($context) # restore context->R14 ++ mov %r15,240($context) # restore context->R14 ++ ++ jmp .Lcommon_seh_tail ++.size se_handler,.-se_handler ++ ++.type avx_handler,\@abi-omnipotent ++.align 16 ++avx_handler: ++ push %rsi ++ push %rdi ++ push %rbx ++ push %rbp ++ push %r12 ++ push %r13 ++ push %r14 ++ push %r15 ++ pushfq ++ sub \$64,%rsp ++ ++ mov 120($context),%rax # pull context->Rax ++ mov 248($context),%rbx # pull context->Rip ++ ++ mov 8($disp),%rsi # disp->ImageBase ++ mov 56($disp),%r11 # disp->HandlerData ++ ++ mov 0(%r11),%r10d # HandlerData[0] ++ lea (%rsi,%r10),%r10 # prologue label ++ cmp %r10,%rbx # context->RipRsp ++ ++ mov 4(%r11),%r10d # HandlerData[1] ++ lea (%rsi,%r10),%r10 # epilogue label ++ cmp %r10,%rbx # context->Rip>=epilogue label ++ jae .Lcommon_seh_tail ++ ++ mov 208($context),%rax # pull context->R11 ++ ++ lea 0x50(%rax),%rsi ++ lea 0xf8(%rax),%rax ++ lea 512($context),%rdi # &context.Xmm6 ++ mov \$20,%ecx ++ .long 0xa548f3fc # cld; rep movsq ++ ++.Lcommon_seh_tail: ++ mov 8(%rax),%rdi ++ mov 16(%rax),%rsi ++ mov %rax,152($context) # restore context->Rsp ++ mov %rsi,168($context) # restore context->Rsi ++ mov %rdi,176($context) # restore context->Rdi ++ ++ mov 40($disp),%rdi # disp->ContextRecord ++ mov $context,%rsi # context ++ mov \$154,%ecx # sizeof(CONTEXT) ++ .long 0xa548f3fc # cld; rep movsq ++ ++ mov $disp,%rsi ++ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER ++ mov 8(%rsi),%rdx # arg2, disp->ImageBase ++ mov 0(%rsi),%r8 # arg3, disp->ControlPc ++ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry ++ mov 40(%rsi),%r10 # disp->ContextRecord ++ lea 56(%rsi),%r11 # &disp->HandlerData ++ lea 24(%rsi),%r12 # &disp->EstablisherFrame ++ mov %r10,32(%rsp) # arg5 ++ mov %r11,40(%rsp) # arg6 ++ mov %r12,48(%rsp) # arg7 ++ mov %rcx,56(%rsp) # arg8, (NULL) ++ call *__imp_RtlVirtualUnwind(%rip) ++ ++ mov \$1,%eax # ExceptionContinueSearch ++ add \$64,%rsp ++ popfq ++ pop %r15 ++ pop %r14 ++ pop %r13 ++ pop %r12 ++ pop %rbp ++ pop %rbx ++ pop %rdi ++ pop %rsi ++ ret ++.size avx_handler,.-avx_handler ++ ++.section .pdata ++.align 4 ++ .rva .LSEH_begin_poly1305_init ++ .rva .LSEH_end_poly1305_init ++ .rva .LSEH_info_poly1305_init ++ ++ .rva .LSEH_begin_poly1305_blocks ++ .rva .LSEH_end_poly1305_blocks ++ .rva .LSEH_info_poly1305_blocks ++ ++ .rva .LSEH_begin_poly1305_emit ++ .rva .LSEH_end_poly1305_emit ++ .rva .LSEH_info_poly1305_emit ++___ ++$code.=<<___ if ($avx); ++ .rva .LSEH_begin_poly1305_blocks_avx ++ .rva .Lbase2_64_avx ++ .rva .LSEH_info_poly1305_blocks_avx_1 ++ ++ .rva .Lbase2_64_avx ++ .rva .Leven_avx ++ .rva .LSEH_info_poly1305_blocks_avx_2 ++ ++ .rva .Leven_avx ++ .rva .LSEH_end_poly1305_blocks_avx ++ .rva .LSEH_info_poly1305_blocks_avx_3 ++ ++ .rva .LSEH_begin_poly1305_emit_avx ++ .rva .LSEH_end_poly1305_emit_avx ++ .rva .LSEH_info_poly1305_emit_avx ++___ ++$code.=<<___ if ($avx>1); ++ .rva .LSEH_begin_poly1305_blocks_avx2 ++ .rva .Lbase2_64_avx2 ++ .rva .LSEH_info_poly1305_blocks_avx2_1 ++ ++ .rva .Lbase2_64_avx2 ++ .rva .Leven_avx2 ++ .rva .LSEH_info_poly1305_blocks_avx2_2 ++ ++ .rva .Leven_avx2 ++ .rva .LSEH_end_poly1305_blocks_avx2 ++ .rva .LSEH_info_poly1305_blocks_avx2_3 ++___ ++$code.=<<___ if ($avx>2); ++ .rva .LSEH_begin_poly1305_blocks_avx512 ++ .rva .LSEH_end_poly1305_blocks_avx512 ++ .rva .LSEH_info_poly1305_blocks_avx512 ++___ ++$code.=<<___; ++.section .xdata ++.align 8 ++.LSEH_info_poly1305_init: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .LSEH_begin_poly1305_init,.LSEH_begin_poly1305_init ++ ++.LSEH_info_poly1305_blocks: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .Lblocks_body,.Lblocks_epilogue ++ ++.LSEH_info_poly1305_emit: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .LSEH_begin_poly1305_emit,.LSEH_begin_poly1305_emit ++___ ++$code.=<<___ if ($avx); ++.LSEH_info_poly1305_blocks_avx_1: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .Lblocks_avx_body,.Lblocks_avx_epilogue # HandlerData[] ++ ++.LSEH_info_poly1305_blocks_avx_2: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .Lbase2_64_avx_body,.Lbase2_64_avx_epilogue # HandlerData[] ++ ++.LSEH_info_poly1305_blocks_avx_3: ++ .byte 9,0,0,0 ++ .rva avx_handler ++ .rva .Ldo_avx_body,.Ldo_avx_epilogue # HandlerData[] ++ ++.LSEH_info_poly1305_emit_avx: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .LSEH_begin_poly1305_emit_avx,.LSEH_begin_poly1305_emit_avx ++___ ++$code.=<<___ if ($avx>1); ++.LSEH_info_poly1305_blocks_avx2_1: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .Lblocks_avx2_body,.Lblocks_avx2_epilogue # HandlerData[] ++ ++.LSEH_info_poly1305_blocks_avx2_2: ++ .byte 9,0,0,0 ++ .rva se_handler ++ .rva .Lbase2_64_avx2_body,.Lbase2_64_avx2_epilogue # HandlerData[] ++ ++.LSEH_info_poly1305_blocks_avx2_3: ++ .byte 9,0,0,0 ++ .rva avx_handler ++ .rva .Ldo_avx2_body,.Ldo_avx2_epilogue # HandlerData[] ++___ ++$code.=<<___ if ($avx>2); ++.LSEH_info_poly1305_blocks_avx512: ++ .byte 9,0,0,0 ++ .rva avx_handler ++ .rva .Ldo_avx512_body,.Ldo_avx512_epilogue # HandlerData[] ++___ ++} ++ ++foreach (split('\n',$code)) { ++ s/\`([^\`]*)\`/eval($1)/ge; ++ s/%r([a-z]+)#d/%e$1/g; ++ s/%r([0-9]+)#d/%r$1d/g; ++ s/%x#%[yz]/%x/g or s/%y#%z/%y/g or s/%z#%[yz]/%z/g; ++ ++ print $_,"\n"; ++} ++close STDOUT; diff --git a/ipq806x/backport-5.4/080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch b/ipq806x/backport-5.4/080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch new file mode 100644 index 0000000..0fc8348 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0043-crypto-x86-poly1305-wire-up-faster-implementations-f.patch @@ -0,0 +1,2927 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 5 Jan 2020 22:40:48 -0500 +Subject: [PATCH] crypto: x86/poly1305 - wire up faster implementations for + kernel + +commit d7d7b853566254648df59f7ea27ea05952a6cfa8 upstream. + +These x86_64 vectorized implementations support AVX, AVX-2, and AVX512F. +The AVX-512F implementation is disabled on Skylake, due to throttling, +but it is quite fast on >= Cannonlake. + +On the left is cycle counts on a Core i7 6700HQ using the AVX-2 +codepath, comparing this implementation ("new") to the implementation in +the current crypto api ("old"). On the right are benchmarks on a Xeon +Gold 5120 using the AVX-512 codepath. The new implementation is faster +on all benchmarks. + + AVX-2 AVX-512 + --------- ----------- + + size old new size old new + ---- ---- ---- ---- ---- ---- + 0 70 68 0 74 70 + 16 92 90 16 96 92 + 32 134 104 32 136 106 + 48 172 120 48 184 124 + 64 218 136 64 218 138 + 80 254 158 80 260 160 + 96 298 174 96 300 176 + 112 342 192 112 342 194 + 128 388 212 128 384 212 + 144 428 228 144 420 226 + 160 466 246 160 464 248 + 176 510 264 176 504 264 + 192 550 282 192 544 282 + 208 594 302 208 582 300 + 224 628 316 224 624 318 + 240 676 334 240 662 338 + 256 716 354 256 708 358 + 272 764 374 272 748 372 + 288 802 352 288 788 358 + 304 420 366 304 422 370 + 320 428 360 320 432 364 + 336 484 378 336 486 380 + 352 426 384 352 434 390 + 368 478 400 368 480 408 + 384 488 394 384 490 398 + 400 542 408 400 542 412 + 416 486 416 416 492 426 + 432 534 430 432 538 436 + 448 544 422 448 546 432 + 464 600 438 464 600 448 + 480 540 448 480 548 456 + 496 594 464 496 594 476 + 512 602 456 512 606 470 + 528 656 476 528 656 480 + 544 600 480 544 606 498 + 560 650 494 560 652 512 + 576 664 490 576 662 508 + 592 714 508 592 716 522 + 608 656 514 608 664 538 + 624 708 532 624 710 552 + 640 716 524 640 720 516 + 656 770 536 656 772 526 + 672 716 548 672 722 544 + 688 770 562 688 768 556 + 704 774 552 704 778 556 + 720 826 568 720 832 568 + 736 768 574 736 780 584 + 752 822 592 752 826 600 + 768 830 584 768 836 560 + 784 884 602 784 888 572 + 800 828 610 800 838 588 + 816 884 628 816 884 604 + 832 888 618 832 894 598 + 848 942 632 848 946 612 + 864 884 644 864 896 628 + 880 936 660 880 942 644 + 896 948 652 896 952 608 + 912 1000 664 912 1004 616 + 928 942 676 928 954 634 + 944 994 690 944 1000 646 + 960 1002 680 960 1008 646 + 976 1054 694 976 1062 658 + 992 1002 706 992 1012 674 + 1008 1052 720 1008 1058 690 + +This commit wires in the prior implementation from Andy, and makes the +following changes to be suitable for kernel land. + + - Some cosmetic and structural changes, like renaming labels to + .Lname, constants, and other Linux conventions, as well as making + the code easy for us to maintain moving forward. + + - CPU feature checking is done in C by the glue code. + + - We avoid jumping into the middle of functions, to appease objtool, + and instead parameterize shared code. + + - We maintain frame pointers so that stack traces make sense. + + - We remove the dependency on the perl xlate code, which transforms + the output into things that assemblers we don't care about use. + +Importantly, none of our changes affect the arithmetic or core code, but +just involve the differing environment of kernel space. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Samuel Neves +Co-developed-by: Samuel Neves +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/.gitignore | 1 + + arch/x86/crypto/Makefile | 11 +- + arch/x86/crypto/poly1305-avx2-x86_64.S | 390 ---------- + arch/x86/crypto/poly1305-sse2-x86_64.S | 590 --------------- + arch/x86/crypto/poly1305-x86_64-cryptogams.pl | 682 ++++++++++-------- + arch/x86/crypto/poly1305_glue.c | 473 +++++------- + lib/crypto/Kconfig | 2 +- + 7 files changed, 572 insertions(+), 1577 deletions(-) + create mode 100644 arch/x86/crypto/.gitignore + delete mode 100644 arch/x86/crypto/poly1305-avx2-x86_64.S + delete mode 100644 arch/x86/crypto/poly1305-sse2-x86_64.S + +--- /dev/null ++++ b/arch/x86/crypto/.gitignore +@@ -0,0 +1 @@ ++poly1305-x86_64.S +--- a/arch/x86/crypto/Makefile ++++ b/arch/x86/crypto/Makefile +@@ -73,6 +73,10 @@ aegis128-aesni-y := aegis128-aesni-asm.o + + nhpoly1305-sse2-y := nh-sse2-x86_64.o nhpoly1305-sse2-glue.o + blake2s-x86_64-y := blake2s-core.o blake2s-glue.o ++poly1305-x86_64-y := poly1305-x86_64-cryptogams.o poly1305_glue.o ++ifneq ($(CONFIG_CRYPTO_POLY1305_X86_64),) ++targets += poly1305-x86_64-cryptogams.S ++endif + + ifeq ($(avx_supported),yes) + camellia-aesni-avx-x86_64-y := camellia-aesni-avx-asm_64.o \ +@@ -101,10 +105,8 @@ aesni-intel-y := aesni-intel_asm.o aesni + aesni-intel-$(CONFIG_64BIT) += aesni-intel_avx-x86_64.o aes_ctrby8_avx-x86_64.o + ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o + sha1-ssse3-y := sha1_ssse3_asm.o sha1_ssse3_glue.o +-poly1305-x86_64-y := poly1305-sse2-x86_64.o poly1305_glue.o + ifeq ($(avx2_supported),yes) + sha1-ssse3-y += sha1_avx2_x86_64_asm.o +-poly1305-x86_64-y += poly1305-avx2-x86_64.o + endif + ifeq ($(sha1_ni_supported),yes) + sha1-ssse3-y += sha1_ni_asm.o +@@ -118,3 +120,8 @@ sha256-ssse3-y += sha256_ni_asm.o + endif + sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o + crct10dif-pclmul-y := crct10dif-pcl-asm_64.o crct10dif-pclmul_glue.o ++ ++quiet_cmd_perlasm = PERLASM $@ ++ cmd_perlasm = $(PERL) $< > $@ ++$(obj)/%.S: $(src)/%.pl FORCE ++ $(call if_changed,perlasm) +--- a/arch/x86/crypto/poly1305-avx2-x86_64.S ++++ /dev/null +@@ -1,390 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Poly1305 authenticator algorithm, RFC7539, x64 AVX2 functions +- * +- * Copyright (C) 2015 Martin Willi +- */ +- +-#include +- +-.section .rodata.cst32.ANMASK, "aM", @progbits, 32 +-.align 32 +-ANMASK: .octa 0x0000000003ffffff0000000003ffffff +- .octa 0x0000000003ffffff0000000003ffffff +- +-.section .rodata.cst32.ORMASK, "aM", @progbits, 32 +-.align 32 +-ORMASK: .octa 0x00000000010000000000000001000000 +- .octa 0x00000000010000000000000001000000 +- +-.text +- +-#define h0 0x00(%rdi) +-#define h1 0x04(%rdi) +-#define h2 0x08(%rdi) +-#define h3 0x0c(%rdi) +-#define h4 0x10(%rdi) +-#define r0 0x00(%rdx) +-#define r1 0x04(%rdx) +-#define r2 0x08(%rdx) +-#define r3 0x0c(%rdx) +-#define r4 0x10(%rdx) +-#define u0 0x00(%r8) +-#define u1 0x04(%r8) +-#define u2 0x08(%r8) +-#define u3 0x0c(%r8) +-#define u4 0x10(%r8) +-#define w0 0x18(%r8) +-#define w1 0x1c(%r8) +-#define w2 0x20(%r8) +-#define w3 0x24(%r8) +-#define w4 0x28(%r8) +-#define y0 0x30(%r8) +-#define y1 0x34(%r8) +-#define y2 0x38(%r8) +-#define y3 0x3c(%r8) +-#define y4 0x40(%r8) +-#define m %rsi +-#define hc0 %ymm0 +-#define hc1 %ymm1 +-#define hc2 %ymm2 +-#define hc3 %ymm3 +-#define hc4 %ymm4 +-#define hc0x %xmm0 +-#define hc1x %xmm1 +-#define hc2x %xmm2 +-#define hc3x %xmm3 +-#define hc4x %xmm4 +-#define t1 %ymm5 +-#define t2 %ymm6 +-#define t1x %xmm5 +-#define t2x %xmm6 +-#define ruwy0 %ymm7 +-#define ruwy1 %ymm8 +-#define ruwy2 %ymm9 +-#define ruwy3 %ymm10 +-#define ruwy4 %ymm11 +-#define ruwy0x %xmm7 +-#define ruwy1x %xmm8 +-#define ruwy2x %xmm9 +-#define ruwy3x %xmm10 +-#define ruwy4x %xmm11 +-#define svxz1 %ymm12 +-#define svxz2 %ymm13 +-#define svxz3 %ymm14 +-#define svxz4 %ymm15 +-#define d0 %r9 +-#define d1 %r10 +-#define d2 %r11 +-#define d3 %r12 +-#define d4 %r13 +- +-ENTRY(poly1305_4block_avx2) +- # %rdi: Accumulator h[5] +- # %rsi: 64 byte input block m +- # %rdx: Poly1305 key r[5] +- # %rcx: Quadblock count +- # %r8: Poly1305 derived key r^2 u[5], r^3 w[5], r^4 y[5], +- +- # This four-block variant uses loop unrolled block processing. It +- # requires 4 Poly1305 keys: r, r^2, r^3 and r^4: +- # h = (h + m) * r => h = (h + m1) * r^4 + m2 * r^3 + m3 * r^2 + m4 * r +- +- vzeroupper +- push %rbx +- push %r12 +- push %r13 +- +- # combine r0,u0,w0,y0 +- vmovd y0,ruwy0x +- vmovd w0,t1x +- vpunpcklqdq t1,ruwy0,ruwy0 +- vmovd u0,t1x +- vmovd r0,t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,ruwy0,ruwy0 +- +- # combine r1,u1,w1,y1 and s1=r1*5,v1=u1*5,x1=w1*5,z1=y1*5 +- vmovd y1,ruwy1x +- vmovd w1,t1x +- vpunpcklqdq t1,ruwy1,ruwy1 +- vmovd u1,t1x +- vmovd r1,t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,ruwy1,ruwy1 +- vpslld $2,ruwy1,svxz1 +- vpaddd ruwy1,svxz1,svxz1 +- +- # combine r2,u2,w2,y2 and s2=r2*5,v2=u2*5,x2=w2*5,z2=y2*5 +- vmovd y2,ruwy2x +- vmovd w2,t1x +- vpunpcklqdq t1,ruwy2,ruwy2 +- vmovd u2,t1x +- vmovd r2,t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,ruwy2,ruwy2 +- vpslld $2,ruwy2,svxz2 +- vpaddd ruwy2,svxz2,svxz2 +- +- # combine r3,u3,w3,y3 and s3=r3*5,v3=u3*5,x3=w3*5,z3=y3*5 +- vmovd y3,ruwy3x +- vmovd w3,t1x +- vpunpcklqdq t1,ruwy3,ruwy3 +- vmovd u3,t1x +- vmovd r3,t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,ruwy3,ruwy3 +- vpslld $2,ruwy3,svxz3 +- vpaddd ruwy3,svxz3,svxz3 +- +- # combine r4,u4,w4,y4 and s4=r4*5,v4=u4*5,x4=w4*5,z4=y4*5 +- vmovd y4,ruwy4x +- vmovd w4,t1x +- vpunpcklqdq t1,ruwy4,ruwy4 +- vmovd u4,t1x +- vmovd r4,t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,ruwy4,ruwy4 +- vpslld $2,ruwy4,svxz4 +- vpaddd ruwy4,svxz4,svxz4 +- +-.Ldoblock4: +- # hc0 = [m[48-51] & 0x3ffffff, m[32-35] & 0x3ffffff, +- # m[16-19] & 0x3ffffff, m[ 0- 3] & 0x3ffffff + h0] +- vmovd 0x00(m),hc0x +- vmovd 0x10(m),t1x +- vpunpcklqdq t1,hc0,hc0 +- vmovd 0x20(m),t1x +- vmovd 0x30(m),t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,hc0,hc0 +- vpand ANMASK(%rip),hc0,hc0 +- vmovd h0,t1x +- vpaddd t1,hc0,hc0 +- # hc1 = [(m[51-54] >> 2) & 0x3ffffff, (m[35-38] >> 2) & 0x3ffffff, +- # (m[19-22] >> 2) & 0x3ffffff, (m[ 3- 6] >> 2) & 0x3ffffff + h1] +- vmovd 0x03(m),hc1x +- vmovd 0x13(m),t1x +- vpunpcklqdq t1,hc1,hc1 +- vmovd 0x23(m),t1x +- vmovd 0x33(m),t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,hc1,hc1 +- vpsrld $2,hc1,hc1 +- vpand ANMASK(%rip),hc1,hc1 +- vmovd h1,t1x +- vpaddd t1,hc1,hc1 +- # hc2 = [(m[54-57] >> 4) & 0x3ffffff, (m[38-41] >> 4) & 0x3ffffff, +- # (m[22-25] >> 4) & 0x3ffffff, (m[ 6- 9] >> 4) & 0x3ffffff + h2] +- vmovd 0x06(m),hc2x +- vmovd 0x16(m),t1x +- vpunpcklqdq t1,hc2,hc2 +- vmovd 0x26(m),t1x +- vmovd 0x36(m),t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,hc2,hc2 +- vpsrld $4,hc2,hc2 +- vpand ANMASK(%rip),hc2,hc2 +- vmovd h2,t1x +- vpaddd t1,hc2,hc2 +- # hc3 = [(m[57-60] >> 6) & 0x3ffffff, (m[41-44] >> 6) & 0x3ffffff, +- # (m[25-28] >> 6) & 0x3ffffff, (m[ 9-12] >> 6) & 0x3ffffff + h3] +- vmovd 0x09(m),hc3x +- vmovd 0x19(m),t1x +- vpunpcklqdq t1,hc3,hc3 +- vmovd 0x29(m),t1x +- vmovd 0x39(m),t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,hc3,hc3 +- vpsrld $6,hc3,hc3 +- vpand ANMASK(%rip),hc3,hc3 +- vmovd h3,t1x +- vpaddd t1,hc3,hc3 +- # hc4 = [(m[60-63] >> 8) | (1<<24), (m[44-47] >> 8) | (1<<24), +- # (m[28-31] >> 8) | (1<<24), (m[12-15] >> 8) | (1<<24) + h4] +- vmovd 0x0c(m),hc4x +- vmovd 0x1c(m),t1x +- vpunpcklqdq t1,hc4,hc4 +- vmovd 0x2c(m),t1x +- vmovd 0x3c(m),t2x +- vpunpcklqdq t2,t1,t1 +- vperm2i128 $0x20,t1,hc4,hc4 +- vpsrld $8,hc4,hc4 +- vpor ORMASK(%rip),hc4,hc4 +- vmovd h4,t1x +- vpaddd t1,hc4,hc4 +- +- # t1 = [ hc0[3] * r0, hc0[2] * u0, hc0[1] * w0, hc0[0] * y0 ] +- vpmuludq hc0,ruwy0,t1 +- # t1 += [ hc1[3] * s4, hc1[2] * v4, hc1[1] * x4, hc1[0] * z4 ] +- vpmuludq hc1,svxz4,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc2[3] * s3, hc2[2] * v3, hc2[1] * x3, hc2[0] * z3 ] +- vpmuludq hc2,svxz3,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc3[3] * s2, hc3[2] * v2, hc3[1] * x2, hc3[0] * z2 ] +- vpmuludq hc3,svxz2,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc4[3] * s1, hc4[2] * v1, hc4[1] * x1, hc4[0] * z1 ] +- vpmuludq hc4,svxz1,t2 +- vpaddq t2,t1,t1 +- # d0 = t1[0] + t1[1] + t[2] + t[3] +- vpermq $0xee,t1,t2 +- vpaddq t2,t1,t1 +- vpsrldq $8,t1,t2 +- vpaddq t2,t1,t1 +- vmovq t1x,d0 +- +- # t1 = [ hc0[3] * r1, hc0[2] * u1,hc0[1] * w1, hc0[0] * y1 ] +- vpmuludq hc0,ruwy1,t1 +- # t1 += [ hc1[3] * r0, hc1[2] * u0, hc1[1] * w0, hc1[0] * y0 ] +- vpmuludq hc1,ruwy0,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc2[3] * s4, hc2[2] * v4, hc2[1] * x4, hc2[0] * z4 ] +- vpmuludq hc2,svxz4,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc3[3] * s3, hc3[2] * v3, hc3[1] * x3, hc3[0] * z3 ] +- vpmuludq hc3,svxz3,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc4[3] * s2, hc4[2] * v2, hc4[1] * x2, hc4[0] * z2 ] +- vpmuludq hc4,svxz2,t2 +- vpaddq t2,t1,t1 +- # d1 = t1[0] + t1[1] + t1[3] + t1[4] +- vpermq $0xee,t1,t2 +- vpaddq t2,t1,t1 +- vpsrldq $8,t1,t2 +- vpaddq t2,t1,t1 +- vmovq t1x,d1 +- +- # t1 = [ hc0[3] * r2, hc0[2] * u2, hc0[1] * w2, hc0[0] * y2 ] +- vpmuludq hc0,ruwy2,t1 +- # t1 += [ hc1[3] * r1, hc1[2] * u1, hc1[1] * w1, hc1[0] * y1 ] +- vpmuludq hc1,ruwy1,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc2[3] * r0, hc2[2] * u0, hc2[1] * w0, hc2[0] * y0 ] +- vpmuludq hc2,ruwy0,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc3[3] * s4, hc3[2] * v4, hc3[1] * x4, hc3[0] * z4 ] +- vpmuludq hc3,svxz4,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc4[3] * s3, hc4[2] * v3, hc4[1] * x3, hc4[0] * z3 ] +- vpmuludq hc4,svxz3,t2 +- vpaddq t2,t1,t1 +- # d2 = t1[0] + t1[1] + t1[2] + t1[3] +- vpermq $0xee,t1,t2 +- vpaddq t2,t1,t1 +- vpsrldq $8,t1,t2 +- vpaddq t2,t1,t1 +- vmovq t1x,d2 +- +- # t1 = [ hc0[3] * r3, hc0[2] * u3, hc0[1] * w3, hc0[0] * y3 ] +- vpmuludq hc0,ruwy3,t1 +- # t1 += [ hc1[3] * r2, hc1[2] * u2, hc1[1] * w2, hc1[0] * y2 ] +- vpmuludq hc1,ruwy2,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc2[3] * r1, hc2[2] * u1, hc2[1] * w1, hc2[0] * y1 ] +- vpmuludq hc2,ruwy1,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc3[3] * r0, hc3[2] * u0, hc3[1] * w0, hc3[0] * y0 ] +- vpmuludq hc3,ruwy0,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc4[3] * s4, hc4[2] * v4, hc4[1] * x4, hc4[0] * z4 ] +- vpmuludq hc4,svxz4,t2 +- vpaddq t2,t1,t1 +- # d3 = t1[0] + t1[1] + t1[2] + t1[3] +- vpermq $0xee,t1,t2 +- vpaddq t2,t1,t1 +- vpsrldq $8,t1,t2 +- vpaddq t2,t1,t1 +- vmovq t1x,d3 +- +- # t1 = [ hc0[3] * r4, hc0[2] * u4, hc0[1] * w4, hc0[0] * y4 ] +- vpmuludq hc0,ruwy4,t1 +- # t1 += [ hc1[3] * r3, hc1[2] * u3, hc1[1] * w3, hc1[0] * y3 ] +- vpmuludq hc1,ruwy3,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc2[3] * r2, hc2[2] * u2, hc2[1] * w2, hc2[0] * y2 ] +- vpmuludq hc2,ruwy2,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc3[3] * r1, hc3[2] * u1, hc3[1] * w1, hc3[0] * y1 ] +- vpmuludq hc3,ruwy1,t2 +- vpaddq t2,t1,t1 +- # t1 += [ hc4[3] * r0, hc4[2] * u0, hc4[1] * w0, hc4[0] * y0 ] +- vpmuludq hc4,ruwy0,t2 +- vpaddq t2,t1,t1 +- # d4 = t1[0] + t1[1] + t1[2] + t1[3] +- vpermq $0xee,t1,t2 +- vpaddq t2,t1,t1 +- vpsrldq $8,t1,t2 +- vpaddq t2,t1,t1 +- vmovq t1x,d4 +- +- # Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 -> +- # h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small +- # amount. Careful: we must not assume the carry bits 'd0 >> 26', +- # 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit +- # integers. It's true in a single-block implementation, but not here. +- +- # d1 += d0 >> 26 +- mov d0,%rax +- shr $26,%rax +- add %rax,d1 +- # h0 = d0 & 0x3ffffff +- mov d0,%rbx +- and $0x3ffffff,%ebx +- +- # d2 += d1 >> 26 +- mov d1,%rax +- shr $26,%rax +- add %rax,d2 +- # h1 = d1 & 0x3ffffff +- mov d1,%rax +- and $0x3ffffff,%eax +- mov %eax,h1 +- +- # d3 += d2 >> 26 +- mov d2,%rax +- shr $26,%rax +- add %rax,d3 +- # h2 = d2 & 0x3ffffff +- mov d2,%rax +- and $0x3ffffff,%eax +- mov %eax,h2 +- +- # d4 += d3 >> 26 +- mov d3,%rax +- shr $26,%rax +- add %rax,d4 +- # h3 = d3 & 0x3ffffff +- mov d3,%rax +- and $0x3ffffff,%eax +- mov %eax,h3 +- +- # h0 += (d4 >> 26) * 5 +- mov d4,%rax +- shr $26,%rax +- lea (%rax,%rax,4),%rax +- add %rax,%rbx +- # h4 = d4 & 0x3ffffff +- mov d4,%rax +- and $0x3ffffff,%eax +- mov %eax,h4 +- +- # h1 += h0 >> 26 +- mov %rbx,%rax +- shr $26,%rax +- add %eax,h1 +- # h0 = h0 & 0x3ffffff +- andl $0x3ffffff,%ebx +- mov %ebx,h0 +- +- add $0x40,m +- dec %rcx +- jnz .Ldoblock4 +- +- vzeroupper +- pop %r13 +- pop %r12 +- pop %rbx +- ret +-ENDPROC(poly1305_4block_avx2) +--- a/arch/x86/crypto/poly1305-sse2-x86_64.S ++++ /dev/null +@@ -1,590 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-or-later */ +-/* +- * Poly1305 authenticator algorithm, RFC7539, x64 SSE2 functions +- * +- * Copyright (C) 2015 Martin Willi +- */ +- +-#include +- +-.section .rodata.cst16.ANMASK, "aM", @progbits, 16 +-.align 16 +-ANMASK: .octa 0x0000000003ffffff0000000003ffffff +- +-.section .rodata.cst16.ORMASK, "aM", @progbits, 16 +-.align 16 +-ORMASK: .octa 0x00000000010000000000000001000000 +- +-.text +- +-#define h0 0x00(%rdi) +-#define h1 0x04(%rdi) +-#define h2 0x08(%rdi) +-#define h3 0x0c(%rdi) +-#define h4 0x10(%rdi) +-#define r0 0x00(%rdx) +-#define r1 0x04(%rdx) +-#define r2 0x08(%rdx) +-#define r3 0x0c(%rdx) +-#define r4 0x10(%rdx) +-#define s1 0x00(%rsp) +-#define s2 0x04(%rsp) +-#define s3 0x08(%rsp) +-#define s4 0x0c(%rsp) +-#define m %rsi +-#define h01 %xmm0 +-#define h23 %xmm1 +-#define h44 %xmm2 +-#define t1 %xmm3 +-#define t2 %xmm4 +-#define t3 %xmm5 +-#define t4 %xmm6 +-#define mask %xmm7 +-#define d0 %r8 +-#define d1 %r9 +-#define d2 %r10 +-#define d3 %r11 +-#define d4 %r12 +- +-ENTRY(poly1305_block_sse2) +- # %rdi: Accumulator h[5] +- # %rsi: 16 byte input block m +- # %rdx: Poly1305 key r[5] +- # %rcx: Block count +- +- # This single block variant tries to improve performance by doing two +- # multiplications in parallel using SSE instructions. There is quite +- # some quardword packing involved, hence the speedup is marginal. +- +- push %rbx +- push %r12 +- sub $0x10,%rsp +- +- # s1..s4 = r1..r4 * 5 +- mov r1,%eax +- lea (%eax,%eax,4),%eax +- mov %eax,s1 +- mov r2,%eax +- lea (%eax,%eax,4),%eax +- mov %eax,s2 +- mov r3,%eax +- lea (%eax,%eax,4),%eax +- mov %eax,s3 +- mov r4,%eax +- lea (%eax,%eax,4),%eax +- mov %eax,s4 +- +- movdqa ANMASK(%rip),mask +- +-.Ldoblock: +- # h01 = [0, h1, 0, h0] +- # h23 = [0, h3, 0, h2] +- # h44 = [0, h4, 0, h4] +- movd h0,h01 +- movd h1,t1 +- movd h2,h23 +- movd h3,t2 +- movd h4,h44 +- punpcklqdq t1,h01 +- punpcklqdq t2,h23 +- punpcklqdq h44,h44 +- +- # h01 += [ (m[3-6] >> 2) & 0x3ffffff, m[0-3] & 0x3ffffff ] +- movd 0x00(m),t1 +- movd 0x03(m),t2 +- psrld $2,t2 +- punpcklqdq t2,t1 +- pand mask,t1 +- paddd t1,h01 +- # h23 += [ (m[9-12] >> 6) & 0x3ffffff, (m[6-9] >> 4) & 0x3ffffff ] +- movd 0x06(m),t1 +- movd 0x09(m),t2 +- psrld $4,t1 +- psrld $6,t2 +- punpcklqdq t2,t1 +- pand mask,t1 +- paddd t1,h23 +- # h44 += [ (m[12-15] >> 8) | (1 << 24), (m[12-15] >> 8) | (1 << 24) ] +- mov 0x0c(m),%eax +- shr $8,%eax +- or $0x01000000,%eax +- movd %eax,t1 +- pshufd $0xc4,t1,t1 +- paddd t1,h44 +- +- # t1[0] = h0 * r0 + h2 * s3 +- # t1[1] = h1 * s4 + h3 * s2 +- movd r0,t1 +- movd s4,t2 +- punpcklqdq t2,t1 +- pmuludq h01,t1 +- movd s3,t2 +- movd s2,t3 +- punpcklqdq t3,t2 +- pmuludq h23,t2 +- paddq t2,t1 +- # t2[0] = h0 * r1 + h2 * s4 +- # t2[1] = h1 * r0 + h3 * s3 +- movd r1,t2 +- movd r0,t3 +- punpcklqdq t3,t2 +- pmuludq h01,t2 +- movd s4,t3 +- movd s3,t4 +- punpcklqdq t4,t3 +- pmuludq h23,t3 +- paddq t3,t2 +- # t3[0] = h4 * s1 +- # t3[1] = h4 * s2 +- movd s1,t3 +- movd s2,t4 +- punpcklqdq t4,t3 +- pmuludq h44,t3 +- # d0 = t1[0] + t1[1] + t3[0] +- # d1 = t2[0] + t2[1] + t3[1] +- movdqa t1,t4 +- punpcklqdq t2,t4 +- punpckhqdq t2,t1 +- paddq t4,t1 +- paddq t3,t1 +- movq t1,d0 +- psrldq $8,t1 +- movq t1,d1 +- +- # t1[0] = h0 * r2 + h2 * r0 +- # t1[1] = h1 * r1 + h3 * s4 +- movd r2,t1 +- movd r1,t2 +- punpcklqdq t2,t1 +- pmuludq h01,t1 +- movd r0,t2 +- movd s4,t3 +- punpcklqdq t3,t2 +- pmuludq h23,t2 +- paddq t2,t1 +- # t2[0] = h0 * r3 + h2 * r1 +- # t2[1] = h1 * r2 + h3 * r0 +- movd r3,t2 +- movd r2,t3 +- punpcklqdq t3,t2 +- pmuludq h01,t2 +- movd r1,t3 +- movd r0,t4 +- punpcklqdq t4,t3 +- pmuludq h23,t3 +- paddq t3,t2 +- # t3[0] = h4 * s3 +- # t3[1] = h4 * s4 +- movd s3,t3 +- movd s4,t4 +- punpcklqdq t4,t3 +- pmuludq h44,t3 +- # d2 = t1[0] + t1[1] + t3[0] +- # d3 = t2[0] + t2[1] + t3[1] +- movdqa t1,t4 +- punpcklqdq t2,t4 +- punpckhqdq t2,t1 +- paddq t4,t1 +- paddq t3,t1 +- movq t1,d2 +- psrldq $8,t1 +- movq t1,d3 +- +- # t1[0] = h0 * r4 + h2 * r2 +- # t1[1] = h1 * r3 + h3 * r1 +- movd r4,t1 +- movd r3,t2 +- punpcklqdq t2,t1 +- pmuludq h01,t1 +- movd r2,t2 +- movd r1,t3 +- punpcklqdq t3,t2 +- pmuludq h23,t2 +- paddq t2,t1 +- # t3[0] = h4 * r0 +- movd r0,t3 +- pmuludq h44,t3 +- # d4 = t1[0] + t1[1] + t3[0] +- movdqa t1,t4 +- psrldq $8,t4 +- paddq t4,t1 +- paddq t3,t1 +- movq t1,d4 +- +- # d1 += d0 >> 26 +- mov d0,%rax +- shr $26,%rax +- add %rax,d1 +- # h0 = d0 & 0x3ffffff +- mov d0,%rbx +- and $0x3ffffff,%ebx +- +- # d2 += d1 >> 26 +- mov d1,%rax +- shr $26,%rax +- add %rax,d2 +- # h1 = d1 & 0x3ffffff +- mov d1,%rax +- and $0x3ffffff,%eax +- mov %eax,h1 +- +- # d3 += d2 >> 26 +- mov d2,%rax +- shr $26,%rax +- add %rax,d3 +- # h2 = d2 & 0x3ffffff +- mov d2,%rax +- and $0x3ffffff,%eax +- mov %eax,h2 +- +- # d4 += d3 >> 26 +- mov d3,%rax +- shr $26,%rax +- add %rax,d4 +- # h3 = d3 & 0x3ffffff +- mov d3,%rax +- and $0x3ffffff,%eax +- mov %eax,h3 +- +- # h0 += (d4 >> 26) * 5 +- mov d4,%rax +- shr $26,%rax +- lea (%rax,%rax,4),%rax +- add %rax,%rbx +- # h4 = d4 & 0x3ffffff +- mov d4,%rax +- and $0x3ffffff,%eax +- mov %eax,h4 +- +- # h1 += h0 >> 26 +- mov %rbx,%rax +- shr $26,%rax +- add %eax,h1 +- # h0 = h0 & 0x3ffffff +- andl $0x3ffffff,%ebx +- mov %ebx,h0 +- +- add $0x10,m +- dec %rcx +- jnz .Ldoblock +- +- # Zeroing of key material +- mov %rcx,0x00(%rsp) +- mov %rcx,0x08(%rsp) +- +- add $0x10,%rsp +- pop %r12 +- pop %rbx +- ret +-ENDPROC(poly1305_block_sse2) +- +- +-#define u0 0x00(%r8) +-#define u1 0x04(%r8) +-#define u2 0x08(%r8) +-#define u3 0x0c(%r8) +-#define u4 0x10(%r8) +-#define hc0 %xmm0 +-#define hc1 %xmm1 +-#define hc2 %xmm2 +-#define hc3 %xmm5 +-#define hc4 %xmm6 +-#define ru0 %xmm7 +-#define ru1 %xmm8 +-#define ru2 %xmm9 +-#define ru3 %xmm10 +-#define ru4 %xmm11 +-#define sv1 %xmm12 +-#define sv2 %xmm13 +-#define sv3 %xmm14 +-#define sv4 %xmm15 +-#undef d0 +-#define d0 %r13 +- +-ENTRY(poly1305_2block_sse2) +- # %rdi: Accumulator h[5] +- # %rsi: 16 byte input block m +- # %rdx: Poly1305 key r[5] +- # %rcx: Doubleblock count +- # %r8: Poly1305 derived key r^2 u[5] +- +- # This two-block variant further improves performance by using loop +- # unrolled block processing. This is more straight forward and does +- # less byte shuffling, but requires a second Poly1305 key r^2: +- # h = (h + m) * r => h = (h + m1) * r^2 + m2 * r +- +- push %rbx +- push %r12 +- push %r13 +- +- # combine r0,u0 +- movd u0,ru0 +- movd r0,t1 +- punpcklqdq t1,ru0 +- +- # combine r1,u1 and s1=r1*5,v1=u1*5 +- movd u1,ru1 +- movd r1,t1 +- punpcklqdq t1,ru1 +- movdqa ru1,sv1 +- pslld $2,sv1 +- paddd ru1,sv1 +- +- # combine r2,u2 and s2=r2*5,v2=u2*5 +- movd u2,ru2 +- movd r2,t1 +- punpcklqdq t1,ru2 +- movdqa ru2,sv2 +- pslld $2,sv2 +- paddd ru2,sv2 +- +- # combine r3,u3 and s3=r3*5,v3=u3*5 +- movd u3,ru3 +- movd r3,t1 +- punpcklqdq t1,ru3 +- movdqa ru3,sv3 +- pslld $2,sv3 +- paddd ru3,sv3 +- +- # combine r4,u4 and s4=r4*5,v4=u4*5 +- movd u4,ru4 +- movd r4,t1 +- punpcklqdq t1,ru4 +- movdqa ru4,sv4 +- pslld $2,sv4 +- paddd ru4,sv4 +- +-.Ldoblock2: +- # hc0 = [ m[16-19] & 0x3ffffff, h0 + m[0-3] & 0x3ffffff ] +- movd 0x00(m),hc0 +- movd 0x10(m),t1 +- punpcklqdq t1,hc0 +- pand ANMASK(%rip),hc0 +- movd h0,t1 +- paddd t1,hc0 +- # hc1 = [ (m[19-22] >> 2) & 0x3ffffff, h1 + (m[3-6] >> 2) & 0x3ffffff ] +- movd 0x03(m),hc1 +- movd 0x13(m),t1 +- punpcklqdq t1,hc1 +- psrld $2,hc1 +- pand ANMASK(%rip),hc1 +- movd h1,t1 +- paddd t1,hc1 +- # hc2 = [ (m[22-25] >> 4) & 0x3ffffff, h2 + (m[6-9] >> 4) & 0x3ffffff ] +- movd 0x06(m),hc2 +- movd 0x16(m),t1 +- punpcklqdq t1,hc2 +- psrld $4,hc2 +- pand ANMASK(%rip),hc2 +- movd h2,t1 +- paddd t1,hc2 +- # hc3 = [ (m[25-28] >> 6) & 0x3ffffff, h3 + (m[9-12] >> 6) & 0x3ffffff ] +- movd 0x09(m),hc3 +- movd 0x19(m),t1 +- punpcklqdq t1,hc3 +- psrld $6,hc3 +- pand ANMASK(%rip),hc3 +- movd h3,t1 +- paddd t1,hc3 +- # hc4 = [ (m[28-31] >> 8) | (1<<24), h4 + (m[12-15] >> 8) | (1<<24) ] +- movd 0x0c(m),hc4 +- movd 0x1c(m),t1 +- punpcklqdq t1,hc4 +- psrld $8,hc4 +- por ORMASK(%rip),hc4 +- movd h4,t1 +- paddd t1,hc4 +- +- # t1 = [ hc0[1] * r0, hc0[0] * u0 ] +- movdqa ru0,t1 +- pmuludq hc0,t1 +- # t1 += [ hc1[1] * s4, hc1[0] * v4 ] +- movdqa sv4,t2 +- pmuludq hc1,t2 +- paddq t2,t1 +- # t1 += [ hc2[1] * s3, hc2[0] * v3 ] +- movdqa sv3,t2 +- pmuludq hc2,t2 +- paddq t2,t1 +- # t1 += [ hc3[1] * s2, hc3[0] * v2 ] +- movdqa sv2,t2 +- pmuludq hc3,t2 +- paddq t2,t1 +- # t1 += [ hc4[1] * s1, hc4[0] * v1 ] +- movdqa sv1,t2 +- pmuludq hc4,t2 +- paddq t2,t1 +- # d0 = t1[0] + t1[1] +- movdqa t1,t2 +- psrldq $8,t2 +- paddq t2,t1 +- movq t1,d0 +- +- # t1 = [ hc0[1] * r1, hc0[0] * u1 ] +- movdqa ru1,t1 +- pmuludq hc0,t1 +- # t1 += [ hc1[1] * r0, hc1[0] * u0 ] +- movdqa ru0,t2 +- pmuludq hc1,t2 +- paddq t2,t1 +- # t1 += [ hc2[1] * s4, hc2[0] * v4 ] +- movdqa sv4,t2 +- pmuludq hc2,t2 +- paddq t2,t1 +- # t1 += [ hc3[1] * s3, hc3[0] * v3 ] +- movdqa sv3,t2 +- pmuludq hc3,t2 +- paddq t2,t1 +- # t1 += [ hc4[1] * s2, hc4[0] * v2 ] +- movdqa sv2,t2 +- pmuludq hc4,t2 +- paddq t2,t1 +- # d1 = t1[0] + t1[1] +- movdqa t1,t2 +- psrldq $8,t2 +- paddq t2,t1 +- movq t1,d1 +- +- # t1 = [ hc0[1] * r2, hc0[0] * u2 ] +- movdqa ru2,t1 +- pmuludq hc0,t1 +- # t1 += [ hc1[1] * r1, hc1[0] * u1 ] +- movdqa ru1,t2 +- pmuludq hc1,t2 +- paddq t2,t1 +- # t1 += [ hc2[1] * r0, hc2[0] * u0 ] +- movdqa ru0,t2 +- pmuludq hc2,t2 +- paddq t2,t1 +- # t1 += [ hc3[1] * s4, hc3[0] * v4 ] +- movdqa sv4,t2 +- pmuludq hc3,t2 +- paddq t2,t1 +- # t1 += [ hc4[1] * s3, hc4[0] * v3 ] +- movdqa sv3,t2 +- pmuludq hc4,t2 +- paddq t2,t1 +- # d2 = t1[0] + t1[1] +- movdqa t1,t2 +- psrldq $8,t2 +- paddq t2,t1 +- movq t1,d2 +- +- # t1 = [ hc0[1] * r3, hc0[0] * u3 ] +- movdqa ru3,t1 +- pmuludq hc0,t1 +- # t1 += [ hc1[1] * r2, hc1[0] * u2 ] +- movdqa ru2,t2 +- pmuludq hc1,t2 +- paddq t2,t1 +- # t1 += [ hc2[1] * r1, hc2[0] * u1 ] +- movdqa ru1,t2 +- pmuludq hc2,t2 +- paddq t2,t1 +- # t1 += [ hc3[1] * r0, hc3[0] * u0 ] +- movdqa ru0,t2 +- pmuludq hc3,t2 +- paddq t2,t1 +- # t1 += [ hc4[1] * s4, hc4[0] * v4 ] +- movdqa sv4,t2 +- pmuludq hc4,t2 +- paddq t2,t1 +- # d3 = t1[0] + t1[1] +- movdqa t1,t2 +- psrldq $8,t2 +- paddq t2,t1 +- movq t1,d3 +- +- # t1 = [ hc0[1] * r4, hc0[0] * u4 ] +- movdqa ru4,t1 +- pmuludq hc0,t1 +- # t1 += [ hc1[1] * r3, hc1[0] * u3 ] +- movdqa ru3,t2 +- pmuludq hc1,t2 +- paddq t2,t1 +- # t1 += [ hc2[1] * r2, hc2[0] * u2 ] +- movdqa ru2,t2 +- pmuludq hc2,t2 +- paddq t2,t1 +- # t1 += [ hc3[1] * r1, hc3[0] * u1 ] +- movdqa ru1,t2 +- pmuludq hc3,t2 +- paddq t2,t1 +- # t1 += [ hc4[1] * r0, hc4[0] * u0 ] +- movdqa ru0,t2 +- pmuludq hc4,t2 +- paddq t2,t1 +- # d4 = t1[0] + t1[1] +- movdqa t1,t2 +- psrldq $8,t2 +- paddq t2,t1 +- movq t1,d4 +- +- # Now do a partial reduction mod (2^130)-5, carrying h0 -> h1 -> h2 -> +- # h3 -> h4 -> h0 -> h1 to get h0,h2,h3,h4 < 2^26 and h1 < 2^26 + a small +- # amount. Careful: we must not assume the carry bits 'd0 >> 26', +- # 'd1 >> 26', 'd2 >> 26', 'd3 >> 26', and '(d4 >> 26) * 5' fit in 32-bit +- # integers. It's true in a single-block implementation, but not here. +- +- # d1 += d0 >> 26 +- mov d0,%rax +- shr $26,%rax +- add %rax,d1 +- # h0 = d0 & 0x3ffffff +- mov d0,%rbx +- and $0x3ffffff,%ebx +- +- # d2 += d1 >> 26 +- mov d1,%rax +- shr $26,%rax +- add %rax,d2 +- # h1 = d1 & 0x3ffffff +- mov d1,%rax +- and $0x3ffffff,%eax +- mov %eax,h1 +- +- # d3 += d2 >> 26 +- mov d2,%rax +- shr $26,%rax +- add %rax,d3 +- # h2 = d2 & 0x3ffffff +- mov d2,%rax +- and $0x3ffffff,%eax +- mov %eax,h2 +- +- # d4 += d3 >> 26 +- mov d3,%rax +- shr $26,%rax +- add %rax,d4 +- # h3 = d3 & 0x3ffffff +- mov d3,%rax +- and $0x3ffffff,%eax +- mov %eax,h3 +- +- # h0 += (d4 >> 26) * 5 +- mov d4,%rax +- shr $26,%rax +- lea (%rax,%rax,4),%rax +- add %rax,%rbx +- # h4 = d4 & 0x3ffffff +- mov d4,%rax +- and $0x3ffffff,%eax +- mov %eax,h4 +- +- # h1 += h0 >> 26 +- mov %rbx,%rax +- shr $26,%rax +- add %eax,h1 +- # h0 = h0 & 0x3ffffff +- andl $0x3ffffff,%ebx +- mov %ebx,h0 +- +- add $0x20,m +- dec %rcx +- jnz .Ldoblock2 +- +- pop %r13 +- pop %r12 +- pop %rbx +- ret +-ENDPROC(poly1305_2block_sse2) +--- a/arch/x86/crypto/poly1305-x86_64-cryptogams.pl ++++ b/arch/x86/crypto/poly1305-x86_64-cryptogams.pl +@@ -1,11 +1,14 @@ +-#! /usr/bin/env perl +-# Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. ++#!/usr/bin/env perl ++# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + # +-# Licensed under the OpenSSL license (the "License"). You may not use +-# this file except in compliance with the License. You can obtain a copy +-# in the file LICENSE in the source distribution or at +-# https://www.openssl.org/source/license.html +- ++# Copyright (C) 2017-2018 Samuel Neves . All Rights Reserved. ++# Copyright (C) 2017-2019 Jason A. Donenfeld . All Rights Reserved. ++# Copyright (C) 2006-2017 CRYPTOGAMS by . All Rights Reserved. ++# ++# This code is taken from the OpenSSL project but the author, Andy Polyakov, ++# has relicensed it under the licenses specified in the SPDX header above. ++# The original headers, including the original license headers, are ++# included below for completeness. + # + # ==================================================================== + # Written by Andy Polyakov for the OpenSSL +@@ -32,7 +35,7 @@ + # Skylake-X system performance. Since we are likely to suppress + # AVX512F capability flag [at least on Skylake-X], conversion serves + # as kind of "investment protection". Note that next *lake processor, +-# Cannolake, has AVX512IFMA code path to execute... ++# Cannonlake, has AVX512IFMA code path to execute... + # + # Numbers are cycles per processed byte with poly1305_blocks alone, + # measured with rdtsc at fixed clock frequency. +@@ -68,39 +71,114 @@ $output = shift; + if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + + $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); ++$kernel=0; $kernel=1 if (!$flavour && !$output); + +-$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +-( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +-( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +-die "can't locate x86_64-xlate.pl"; +- +-if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` +- =~ /GNU assembler version ([2-9]\.[0-9]+)/) { +- $avx = ($1>=2.19) + ($1>=2.22) + ($1>=2.25) + ($1>=2.26); ++if (!$kernel) { ++ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; ++ ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or ++ ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or ++ die "can't locate x86_64-xlate.pl"; ++ ++ open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""; ++ *STDOUT=*OUT; ++ ++ if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` ++ =~ /GNU assembler version ([2-9]\.[0-9]+)/) { ++ $avx = ($1>=2.19) + ($1>=2.22) + ($1>=2.25); ++ } ++ ++ if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && ++ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/) { ++ $avx = ($1>=2.09) + ($1>=2.10) + ($1>=2.12); ++ $avx += 1 if ($1==2.11 && $2>=8); ++ } ++ ++ if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && ++ `ml64 2>&1` =~ /Version ([0-9]+)\./) { ++ $avx = ($1>=10) + ($1>=11); ++ } ++ ++ if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) { ++ $avx = ($2>=3.0) + ($2>3.0); ++ } ++} else { ++ $avx = 4; # The kernel uses ifdefs for this. + } + +-if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && +- `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)(?:\.([0-9]+))?/) { +- $avx = ($1>=2.09) + ($1>=2.10) + 2 * ($1>=2.12); +- $avx += 2 if ($1==2.11 && $2>=8); ++sub declare_function() { ++ my ($name, $align, $nargs) = @_; ++ if($kernel) { ++ $code .= ".align $align\n"; ++ $code .= "ENTRY($name)\n"; ++ $code .= ".L$name:\n"; ++ } else { ++ $code .= ".globl $name\n"; ++ $code .= ".type $name,\@function,$nargs\n"; ++ $code .= ".align $align\n"; ++ $code .= "$name:\n"; ++ } + } + +-if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && +- `ml64 2>&1` =~ /Version ([0-9]+)\./) { +- $avx = ($1>=10) + ($1>=12); ++sub end_function() { ++ my ($name) = @_; ++ if($kernel) { ++ $code .= "ENDPROC($name)\n"; ++ } else { ++ $code .= ".size $name,.-$name\n"; ++ } + } + +-if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) { +- $avx = ($2>=3.0) + ($2>3.0); +-} ++$code.=<<___ if $kernel; ++#include ++___ + +-open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\""; +-*STDOUT=*OUT; ++if ($avx) { ++$code.=<<___ if $kernel; ++.section .rodata ++___ ++$code.=<<___; ++.align 64 ++.Lconst: ++.Lmask24: ++.long 0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0 ++.L129: ++.long `1<<24`,0,`1<<24`,0,`1<<24`,0,`1<<24`,0 ++.Lmask26: ++.long 0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0 ++.Lpermd_avx2: ++.long 2,2,2,3,2,0,2,1 ++.Lpermd_avx512: ++.long 0,0,0,1, 0,2,0,3, 0,4,0,5, 0,6,0,7 ++ ++.L2_44_inp_permd: ++.long 0,1,1,2,2,3,7,7 ++.L2_44_inp_shift: ++.quad 0,12,24,64 ++.L2_44_mask: ++.quad 0xfffffffffff,0xfffffffffff,0x3ffffffffff,0xffffffffffffffff ++.L2_44_shift_rgt: ++.quad 44,44,42,64 ++.L2_44_shift_lft: ++.quad 8,8,10,64 ++ ++.align 64 ++.Lx_mask44: ++.quad 0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff ++.quad 0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff ++.Lx_mask42: ++.quad 0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff ++.quad 0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff ++___ ++} ++$code.=<<___ if (!$kernel); ++.asciz "Poly1305 for x86_64, CRYPTOGAMS by " ++.align 16 ++___ + + my ($ctx,$inp,$len,$padbit)=("%rdi","%rsi","%rdx","%rcx"); + my ($mac,$nonce)=($inp,$len); # *_emit arguments +-my ($d1,$d2,$d3, $r0,$r1,$s1)=map("%r$_",(8..13)); +-my ($h0,$h1,$h2)=("%r14","%rbx","%rbp"); ++my ($d1,$d2,$d3, $r0,$r1,$s1)=("%r8","%r9","%rdi","%r11","%r12","%r13"); ++my ($h0,$h1,$h2)=("%r14","%rbx","%r10"); + + sub poly1305_iteration { + # input: copy of $r1 in %rax, $h0-$h2, $r0-$r1 +@@ -155,19 +233,19 @@ ___ + + $code.=<<___; + .text +- ++___ ++$code.=<<___ if (!$kernel); + .extern OPENSSL_ia32cap_P + +-.globl poly1305_init +-.hidden poly1305_init +-.globl poly1305_blocks +-.hidden poly1305_blocks +-.globl poly1305_emit +-.hidden poly1305_emit +- +-.type poly1305_init,\@function,3 +-.align 32 +-poly1305_init: ++.globl poly1305_init_x86_64 ++.hidden poly1305_init_x86_64 ++.globl poly1305_blocks_x86_64 ++.hidden poly1305_blocks_x86_64 ++.globl poly1305_emit_x86_64 ++.hidden poly1305_emit_x86_64 ++___ ++&declare_function("poly1305_init_x86_64", 32, 3); ++$code.=<<___; + xor %rax,%rax + mov %rax,0($ctx) # initialize hash value + mov %rax,8($ctx) +@@ -175,11 +253,12 @@ poly1305_init: + + cmp \$0,$inp + je .Lno_key +- +- lea poly1305_blocks(%rip),%r10 +- lea poly1305_emit(%rip),%r11 + ___ +-$code.=<<___ if ($avx); ++$code.=<<___ if (!$kernel); ++ lea poly1305_blocks_x86_64(%rip),%r10 ++ lea poly1305_emit_x86_64(%rip),%r11 ++___ ++$code.=<<___ if (!$kernel && $avx); + mov OPENSSL_ia32cap_P+4(%rip),%r9 + lea poly1305_blocks_avx(%rip),%rax + lea poly1305_emit_avx(%rip),%rcx +@@ -187,12 +266,12 @@ $code.=<<___ if ($avx); + cmovc %rax,%r10 + cmovc %rcx,%r11 + ___ +-$code.=<<___ if ($avx>1); ++$code.=<<___ if (!$kernel && $avx>1); + lea poly1305_blocks_avx2(%rip),%rax + bt \$`5+32`,%r9 # AVX2? + cmovc %rax,%r10 + ___ +-$code.=<<___ if ($avx>3); ++$code.=<<___ if (!$kernel && $avx>3); + mov \$`(1<<31|1<<21|1<<16)`,%rax + shr \$32,%r9 + and %rax,%r9 +@@ -207,11 +286,11 @@ $code.=<<___; + mov %rax,24($ctx) + mov %rcx,32($ctx) + ___ +-$code.=<<___ if ($flavour !~ /elf32/); ++$code.=<<___ if (!$kernel && $flavour !~ /elf32/); + mov %r10,0(%rdx) + mov %r11,8(%rdx) + ___ +-$code.=<<___ if ($flavour =~ /elf32/); ++$code.=<<___ if (!$kernel && $flavour =~ /elf32/); + mov %r10d,0(%rdx) + mov %r11d,4(%rdx) + ___ +@@ -219,11 +298,11 @@ $code.=<<___; + mov \$1,%eax + .Lno_key: + ret +-.size poly1305_init,.-poly1305_init ++___ ++&end_function("poly1305_init_x86_64"); + +-.type poly1305_blocks,\@function,4 +-.align 32 +-poly1305_blocks: ++&declare_function("poly1305_blocks_x86_64", 32, 4); ++$code.=<<___; + .cfi_startproc + .Lblocks: + shr \$4,$len +@@ -231,8 +310,6 @@ poly1305_blocks: + + push %rbx + .cfi_push %rbx +- push %rbp +-.cfi_push %rbp + push %r12 + .cfi_push %r12 + push %r13 +@@ -241,6 +318,8 @@ poly1305_blocks: + .cfi_push %r14 + push %r15 + .cfi_push %r15 ++ push $ctx ++.cfi_push $ctx + .Lblocks_body: + + mov $len,%r15 # reassign $len +@@ -265,26 +344,29 @@ poly1305_blocks: + lea 16($inp),$inp + adc $padbit,$h2 + ___ ++ + &poly1305_iteration(); ++ + $code.=<<___; + mov $r1,%rax + dec %r15 # len-=16 + jnz .Loop + ++ mov 0(%rsp),$ctx ++.cfi_restore $ctx ++ + mov $h0,0($ctx) # store hash value + mov $h1,8($ctx) + mov $h2,16($ctx) + +- mov 0(%rsp),%r15 ++ mov 8(%rsp),%r15 + .cfi_restore %r15 +- mov 8(%rsp),%r14 ++ mov 16(%rsp),%r14 + .cfi_restore %r14 +- mov 16(%rsp),%r13 ++ mov 24(%rsp),%r13 + .cfi_restore %r13 +- mov 24(%rsp),%r12 ++ mov 32(%rsp),%r12 + .cfi_restore %r12 +- mov 32(%rsp),%rbp +-.cfi_restore %rbp + mov 40(%rsp),%rbx + .cfi_restore %rbx + lea 48(%rsp),%rsp +@@ -293,11 +375,11 @@ $code.=<<___; + .Lblocks_epilogue: + ret + .cfi_endproc +-.size poly1305_blocks,.-poly1305_blocks ++___ ++&end_function("poly1305_blocks_x86_64"); + +-.type poly1305_emit,\@function,3 +-.align 32 +-poly1305_emit: ++&declare_function("poly1305_emit_x86_64", 32, 3); ++$code.=<<___; + .Lemit: + mov 0($ctx),%r8 # load hash value + mov 8($ctx),%r9 +@@ -318,10 +400,14 @@ poly1305_emit: + mov %rcx,8($mac) + + ret +-.size poly1305_emit,.-poly1305_emit + ___ ++&end_function("poly1305_emit_x86_64"); + if ($avx) { + ++if($kernel) { ++ $code .= "#ifdef CONFIG_AS_AVX\n"; ++} ++ + ######################################################################## + # Layout of opaque area is following. + # +@@ -342,15 +428,19 @@ $code.=<<___; + .type __poly1305_block,\@abi-omnipotent + .align 32 + __poly1305_block: ++ push $ctx + ___ + &poly1305_iteration(); + $code.=<<___; ++ pop $ctx + ret + .size __poly1305_block,.-__poly1305_block + + .type __poly1305_init_avx,\@abi-omnipotent + .align 32 + __poly1305_init_avx: ++ push %rbp ++ mov %rsp,%rbp + mov $r0,$h0 + mov $r1,$h1 + xor $h2,$h2 +@@ -507,12 +597,13 @@ __poly1305_init_avx: + mov $d1#d,`16*8+8-64`($ctx) + + lea -48-64($ctx),$ctx # size [de-]optimization ++ pop %rbp + ret + .size __poly1305_init_avx,.-__poly1305_init_avx ++___ + +-.type poly1305_blocks_avx,\@function,4 +-.align 32 +-poly1305_blocks_avx: ++&declare_function("poly1305_blocks_avx", 32, 4); ++$code.=<<___; + .cfi_startproc + mov 20($ctx),%r8d # is_base2_26 + cmp \$128,$len +@@ -532,10 +623,11 @@ poly1305_blocks_avx: + test \$31,$len + jz .Leven_avx + +- push %rbx +-.cfi_push %rbx + push %rbp + .cfi_push %rbp ++ mov %rsp,%rbp ++ push %rbx ++.cfi_push %rbx + push %r12 + .cfi_push %r12 + push %r13 +@@ -645,20 +737,18 @@ poly1305_blocks_avx: + mov $h2#d,16($ctx) + .align 16 + .Ldone_avx: +- mov 0(%rsp),%r15 ++ pop %r15 + .cfi_restore %r15 +- mov 8(%rsp),%r14 ++ pop %r14 + .cfi_restore %r14 +- mov 16(%rsp),%r13 ++ pop %r13 + .cfi_restore %r13 +- mov 24(%rsp),%r12 ++ pop %r12 + .cfi_restore %r12 +- mov 32(%rsp),%rbp +-.cfi_restore %rbp +- mov 40(%rsp),%rbx ++ pop %rbx + .cfi_restore %rbx +- lea 48(%rsp),%rsp +-.cfi_adjust_cfa_offset -48 ++ pop %rbp ++.cfi_restore %rbp + .Lno_data_avx: + .Lblocks_avx_epilogue: + ret +@@ -667,10 +757,11 @@ poly1305_blocks_avx: + .align 32 + .Lbase2_64_avx: + .cfi_startproc +- push %rbx +-.cfi_push %rbx + push %rbp + .cfi_push %rbp ++ mov %rsp,%rbp ++ push %rbx ++.cfi_push %rbx + push %r12 + .cfi_push %r12 + push %r13 +@@ -736,22 +827,18 @@ poly1305_blocks_avx: + + .Lproceed_avx: + mov %r15,$len +- +- mov 0(%rsp),%r15 ++ pop %r15 + .cfi_restore %r15 +- mov 8(%rsp),%r14 ++ pop %r14 + .cfi_restore %r14 +- mov 16(%rsp),%r13 ++ pop %r13 + .cfi_restore %r13 +- mov 24(%rsp),%r12 ++ pop %r12 + .cfi_restore %r12 +- mov 32(%rsp),%rbp +-.cfi_restore %rbp +- mov 40(%rsp),%rbx ++ pop %rbx + .cfi_restore %rbx +- lea 48(%rsp),%rax +- lea 48(%rsp),%rsp +-.cfi_adjust_cfa_offset -48 ++ pop %rbp ++.cfi_restore %rbp + .Lbase2_64_avx_epilogue: + jmp .Ldo_avx + .cfi_endproc +@@ -768,8 +855,11 @@ poly1305_blocks_avx: + .Ldo_avx: + ___ + $code.=<<___ if (!$win64); ++ lea 8(%rsp),%r10 ++.cfi_def_cfa_register %r10 ++ and \$-32,%rsp ++ sub \$-8,%rsp + lea -0x58(%rsp),%r11 +-.cfi_def_cfa %r11,0x60 + sub \$0x178,%rsp + ___ + $code.=<<___ if ($win64); +@@ -1361,18 +1451,18 @@ $code.=<<___ if ($win64); + .Ldo_avx_epilogue: + ___ + $code.=<<___ if (!$win64); +- lea 0x58(%r11),%rsp +-.cfi_def_cfa %rsp,8 ++ lea -8(%r10),%rsp ++.cfi_def_cfa_register %rsp + ___ + $code.=<<___; + vzeroupper + ret + .cfi_endproc +-.size poly1305_blocks_avx,.-poly1305_blocks_avx ++___ ++&end_function("poly1305_blocks_avx"); + +-.type poly1305_emit_avx,\@function,3 +-.align 32 +-poly1305_emit_avx: ++&declare_function("poly1305_emit_avx", 32, 3); ++$code.=<<___; + cmpl \$0,20($ctx) # is_base2_26? + je .Lemit + +@@ -1423,41 +1513,51 @@ poly1305_emit_avx: + mov %rcx,8($mac) + + ret +-.size poly1305_emit_avx,.-poly1305_emit_avx + ___ ++&end_function("poly1305_emit_avx"); ++ ++if ($kernel) { ++ $code .= "#endif\n"; ++} + + if ($avx>1) { ++ ++if ($kernel) { ++ $code .= "#ifdef CONFIG_AS_AVX2\n"; ++} ++ + my ($H0,$H1,$H2,$H3,$H4, $MASK, $T4,$T0,$T1,$T2,$T3, $D0,$D1,$D2,$D3,$D4) = + map("%ymm$_",(0..15)); + my $S4=$MASK; + ++sub poly1305_blocks_avxN { ++ my ($avx512) = @_; ++ my $suffix = $avx512 ? "_avx512" : ""; + $code.=<<___; +-.type poly1305_blocks_avx2,\@function,4 +-.align 32 +-poly1305_blocks_avx2: + .cfi_startproc + mov 20($ctx),%r8d # is_base2_26 + cmp \$128,$len +- jae .Lblocks_avx2 ++ jae .Lblocks_avx2$suffix + test %r8d,%r8d + jz .Lblocks + +-.Lblocks_avx2: ++.Lblocks_avx2$suffix: + and \$-16,$len +- jz .Lno_data_avx2 ++ jz .Lno_data_avx2$suffix + + vzeroupper + + test %r8d,%r8d +- jz .Lbase2_64_avx2 ++ jz .Lbase2_64_avx2$suffix + + test \$63,$len +- jz .Leven_avx2 ++ jz .Leven_avx2$suffix + +- push %rbx +-.cfi_push %rbx + push %rbp + .cfi_push %rbp ++ mov %rsp,%rbp ++ push %rbx ++.cfi_push %rbx + push %r12 + .cfi_push %r12 + push %r13 +@@ -1466,7 +1566,7 @@ poly1305_blocks_avx2: + .cfi_push %r14 + push %r15 + .cfi_push %r15 +-.Lblocks_avx2_body: ++.Lblocks_avx2_body$suffix: + + mov $len,%r15 # reassign $len + +@@ -1513,7 +1613,7 @@ poly1305_blocks_avx2: + shr \$2,$s1 + add $r1,$s1 # s1 = r1 + (r1 >> 2) + +-.Lbase2_26_pre_avx2: ++.Lbase2_26_pre_avx2$suffix: + add 0($inp),$h0 # accumulate input + adc 8($inp),$h1 + lea 16($inp),$inp +@@ -1524,10 +1624,10 @@ poly1305_blocks_avx2: + mov $r1,%rax + + test \$63,%r15 +- jnz .Lbase2_26_pre_avx2 ++ jnz .Lbase2_26_pre_avx2$suffix + + test $padbit,$padbit # if $padbit is zero, +- jz .Lstore_base2_64_avx2 # store hash in base 2^64 format ++ jz .Lstore_base2_64_avx2$suffix # store hash in base 2^64 format + + ################################# base 2^64 -> base 2^26 + mov $h0,%rax +@@ -1548,57 +1648,56 @@ poly1305_blocks_avx2: + or $r1,$h2 # h[4] + + test %r15,%r15 +- jz .Lstore_base2_26_avx2 ++ jz .Lstore_base2_26_avx2$suffix + + vmovd %rax#d,%x#$H0 + vmovd %rdx#d,%x#$H1 + vmovd $h0#d,%x#$H2 + vmovd $h1#d,%x#$H3 + vmovd $h2#d,%x#$H4 +- jmp .Lproceed_avx2 ++ jmp .Lproceed_avx2$suffix + + .align 32 +-.Lstore_base2_64_avx2: ++.Lstore_base2_64_avx2$suffix: + mov $h0,0($ctx) + mov $h1,8($ctx) + mov $h2,16($ctx) # note that is_base2_26 is zeroed +- jmp .Ldone_avx2 ++ jmp .Ldone_avx2$suffix + + .align 16 +-.Lstore_base2_26_avx2: ++.Lstore_base2_26_avx2$suffix: + mov %rax#d,0($ctx) # store hash value base 2^26 + mov %rdx#d,4($ctx) + mov $h0#d,8($ctx) + mov $h1#d,12($ctx) + mov $h2#d,16($ctx) + .align 16 +-.Ldone_avx2: +- mov 0(%rsp),%r15 ++.Ldone_avx2$suffix: ++ pop %r15 + .cfi_restore %r15 +- mov 8(%rsp),%r14 ++ pop %r14 + .cfi_restore %r14 +- mov 16(%rsp),%r13 ++ pop %r13 + .cfi_restore %r13 +- mov 24(%rsp),%r12 ++ pop %r12 + .cfi_restore %r12 +- mov 32(%rsp),%rbp +-.cfi_restore %rbp +- mov 40(%rsp),%rbx ++ pop %rbx + .cfi_restore %rbx +- lea 48(%rsp),%rsp +-.cfi_adjust_cfa_offset -48 +-.Lno_data_avx2: +-.Lblocks_avx2_epilogue: ++ pop %rbp ++.cfi_restore %rbp ++.Lno_data_avx2$suffix: ++.Lblocks_avx2_epilogue$suffix: + ret + .cfi_endproc + + .align 32 +-.Lbase2_64_avx2: ++.Lbase2_64_avx2$suffix: + .cfi_startproc +- push %rbx +-.cfi_push %rbx + push %rbp + .cfi_push %rbp ++ mov %rsp,%rbp ++ push %rbx ++.cfi_push %rbx + push %r12 + .cfi_push %r12 + push %r13 +@@ -1607,7 +1706,7 @@ poly1305_blocks_avx2: + .cfi_push %r14 + push %r15 + .cfi_push %r15 +-.Lbase2_64_avx2_body: ++.Lbase2_64_avx2_body$suffix: + + mov $len,%r15 # reassign $len + +@@ -1624,9 +1723,9 @@ poly1305_blocks_avx2: + add $r1,$s1 # s1 = r1 + (r1 >> 2) + + test \$63,$len +- jz .Linit_avx2 ++ jz .Linit_avx2$suffix + +-.Lbase2_64_pre_avx2: ++.Lbase2_64_pre_avx2$suffix: + add 0($inp),$h0 # accumulate input + adc 8($inp),$h1 + lea 16($inp),$inp +@@ -1637,9 +1736,9 @@ poly1305_blocks_avx2: + mov $r1,%rax + + test \$63,%r15 +- jnz .Lbase2_64_pre_avx2 ++ jnz .Lbase2_64_pre_avx2$suffix + +-.Linit_avx2: ++.Linit_avx2$suffix: + ################################# base 2^64 -> base 2^26 + mov $h0,%rax + mov $h0,%rdx +@@ -1667,69 +1766,77 @@ poly1305_blocks_avx2: + + call __poly1305_init_avx + +-.Lproceed_avx2: ++.Lproceed_avx2$suffix: + mov %r15,$len # restore $len +- mov OPENSSL_ia32cap_P+8(%rip),%r10d ++___ ++$code.=<<___ if (!$kernel); ++ mov OPENSSL_ia32cap_P+8(%rip),%r9d + mov \$`(1<<31|1<<30|1<<16)`,%r11d +- +- mov 0(%rsp),%r15 ++___ ++$code.=<<___; ++ pop %r15 + .cfi_restore %r15 +- mov 8(%rsp),%r14 ++ pop %r14 + .cfi_restore %r14 +- mov 16(%rsp),%r13 ++ pop %r13 + .cfi_restore %r13 +- mov 24(%rsp),%r12 ++ pop %r12 + .cfi_restore %r12 +- mov 32(%rsp),%rbp +-.cfi_restore %rbp +- mov 40(%rsp),%rbx ++ pop %rbx + .cfi_restore %rbx +- lea 48(%rsp),%rax +- lea 48(%rsp),%rsp +-.cfi_adjust_cfa_offset -48 +-.Lbase2_64_avx2_epilogue: +- jmp .Ldo_avx2 ++ pop %rbp ++.cfi_restore %rbp ++.Lbase2_64_avx2_epilogue$suffix: ++ jmp .Ldo_avx2$suffix + .cfi_endproc + + .align 32 +-.Leven_avx2: ++.Leven_avx2$suffix: + .cfi_startproc +- mov OPENSSL_ia32cap_P+8(%rip),%r10d ++___ ++$code.=<<___ if (!$kernel); ++ mov OPENSSL_ia32cap_P+8(%rip),%r9d ++___ ++$code.=<<___; + vmovd 4*0($ctx),%x#$H0 # load hash value base 2^26 + vmovd 4*1($ctx),%x#$H1 + vmovd 4*2($ctx),%x#$H2 + vmovd 4*3($ctx),%x#$H3 + vmovd 4*4($ctx),%x#$H4 + +-.Ldo_avx2: ++.Ldo_avx2$suffix: + ___ +-$code.=<<___ if ($avx>2); ++$code.=<<___ if (!$kernel && $avx>2); + cmp \$512,$len + jb .Lskip_avx512 +- and %r11d,%r10d +- test \$`1<<16`,%r10d # check for AVX512F ++ and %r11d,%r9d ++ test \$`1<<16`,%r9d # check for AVX512F + jnz .Lblocks_avx512 +-.Lskip_avx512: ++.Lskip_avx512$suffix: ++___ ++$code.=<<___ if ($avx > 2 && $avx512 && $kernel); ++ cmp \$512,$len ++ jae .Lblocks_avx512 + ___ + $code.=<<___ if (!$win64); +- lea -8(%rsp),%r11 +-.cfi_def_cfa %r11,16 ++ lea 8(%rsp),%r10 ++.cfi_def_cfa_register %r10 + sub \$0x128,%rsp + ___ + $code.=<<___ if ($win64); +- lea -0xf8(%rsp),%r11 ++ lea 8(%rsp),%r10 + sub \$0x1c8,%rsp +- vmovdqa %xmm6,0x50(%r11) +- vmovdqa %xmm7,0x60(%r11) +- vmovdqa %xmm8,0x70(%r11) +- vmovdqa %xmm9,0x80(%r11) +- vmovdqa %xmm10,0x90(%r11) +- vmovdqa %xmm11,0xa0(%r11) +- vmovdqa %xmm12,0xb0(%r11) +- vmovdqa %xmm13,0xc0(%r11) +- vmovdqa %xmm14,0xd0(%r11) +- vmovdqa %xmm15,0xe0(%r11) +-.Ldo_avx2_body: ++ vmovdqa %xmm6,-0xb0(%r10) ++ vmovdqa %xmm7,-0xa0(%r10) ++ vmovdqa %xmm8,-0x90(%r10) ++ vmovdqa %xmm9,-0x80(%r10) ++ vmovdqa %xmm10,-0x70(%r10) ++ vmovdqa %xmm11,-0x60(%r10) ++ vmovdqa %xmm12,-0x50(%r10) ++ vmovdqa %xmm13,-0x40(%r10) ++ vmovdqa %xmm14,-0x30(%r10) ++ vmovdqa %xmm15,-0x20(%r10) ++.Ldo_avx2_body$suffix: + ___ + $code.=<<___; + lea .Lconst(%rip),%rcx +@@ -1794,11 +1901,11 @@ $code.=<<___; + + vpaddq $H2,$T2,$H2 # accumulate input + sub \$64,$len +- jz .Ltail_avx2 +- jmp .Loop_avx2 ++ jz .Ltail_avx2$suffix ++ jmp .Loop_avx2$suffix + + .align 32 +-.Loop_avx2: ++.Loop_avx2$suffix: + ################################################################ + # ((inp[0]*r^4+inp[4])*r^4+inp[ 8])*r^4 + # ((inp[1]*r^4+inp[5])*r^4+inp[ 9])*r^3 +@@ -1946,10 +2053,10 @@ $code.=<<___; + vpor 32(%rcx),$T4,$T4 # padbit, yes, always + + sub \$64,$len +- jnz .Loop_avx2 ++ jnz .Loop_avx2$suffix + + .byte 0x66,0x90 +-.Ltail_avx2: ++.Ltail_avx2$suffix: + ################################################################ + # while above multiplications were by r^4 in all lanes, in last + # iteration we multiply least significant lane by r^4 and most +@@ -2087,37 +2194,29 @@ $code.=<<___; + vmovd %x#$H4,`4*4-48-64`($ctx) + ___ + $code.=<<___ if ($win64); +- vmovdqa 0x50(%r11),%xmm6 +- vmovdqa 0x60(%r11),%xmm7 +- vmovdqa 0x70(%r11),%xmm8 +- vmovdqa 0x80(%r11),%xmm9 +- vmovdqa 0x90(%r11),%xmm10 +- vmovdqa 0xa0(%r11),%xmm11 +- vmovdqa 0xb0(%r11),%xmm12 +- vmovdqa 0xc0(%r11),%xmm13 +- vmovdqa 0xd0(%r11),%xmm14 +- vmovdqa 0xe0(%r11),%xmm15 +- lea 0xf8(%r11),%rsp +-.Ldo_avx2_epilogue: ++ vmovdqa -0xb0(%r10),%xmm6 ++ vmovdqa -0xa0(%r10),%xmm7 ++ vmovdqa -0x90(%r10),%xmm8 ++ vmovdqa -0x80(%r10),%xmm9 ++ vmovdqa -0x70(%r10),%xmm10 ++ vmovdqa -0x60(%r10),%xmm11 ++ vmovdqa -0x50(%r10),%xmm12 ++ vmovdqa -0x40(%r10),%xmm13 ++ vmovdqa -0x30(%r10),%xmm14 ++ vmovdqa -0x20(%r10),%xmm15 ++ lea -8(%r10),%rsp ++.Ldo_avx2_epilogue$suffix: + ___ + $code.=<<___ if (!$win64); +- lea 8(%r11),%rsp +-.cfi_def_cfa %rsp,8 ++ lea -8(%r10),%rsp ++.cfi_def_cfa_register %rsp + ___ + $code.=<<___; + vzeroupper + ret + .cfi_endproc +-.size poly1305_blocks_avx2,.-poly1305_blocks_avx2 + ___ +-####################################################################### +-if ($avx>2) { +-# On entry we have input length divisible by 64. But since inner loop +-# processes 128 bytes per iteration, cases when length is not divisible +-# by 128 are handled by passing tail 64 bytes to .Ltail_avx2. For this +-# reason stack layout is kept identical to poly1305_blocks_avx2. If not +-# for this tail, we wouldn't have to even allocate stack frame... +- ++if($avx > 2 && $avx512) { + my ($R0,$R1,$R2,$R3,$R4, $S1,$S2,$S3,$S4) = map("%zmm$_",(16..24)); + my ($M0,$M1,$M2,$M3,$M4) = map("%zmm$_",(25..29)); + my $PADBIT="%zmm30"; +@@ -2128,32 +2227,29 @@ map(s/%y/%z/,($H0,$H1,$H2,$H3,$H4)); + map(s/%y/%z/,($MASK)); + + $code.=<<___; +-.type poly1305_blocks_avx512,\@function,4 +-.align 32 +-poly1305_blocks_avx512: + .cfi_startproc + .Lblocks_avx512: + mov \$15,%eax + kmovw %eax,%k2 + ___ + $code.=<<___ if (!$win64); +- lea -8(%rsp),%r11 +-.cfi_def_cfa %r11,16 ++ lea 8(%rsp),%r10 ++.cfi_def_cfa_register %r10 + sub \$0x128,%rsp + ___ + $code.=<<___ if ($win64); +- lea -0xf8(%rsp),%r11 ++ lea 8(%rsp),%r10 + sub \$0x1c8,%rsp +- vmovdqa %xmm6,0x50(%r11) +- vmovdqa %xmm7,0x60(%r11) +- vmovdqa %xmm8,0x70(%r11) +- vmovdqa %xmm9,0x80(%r11) +- vmovdqa %xmm10,0x90(%r11) +- vmovdqa %xmm11,0xa0(%r11) +- vmovdqa %xmm12,0xb0(%r11) +- vmovdqa %xmm13,0xc0(%r11) +- vmovdqa %xmm14,0xd0(%r11) +- vmovdqa %xmm15,0xe0(%r11) ++ vmovdqa %xmm6,-0xb0(%r10) ++ vmovdqa %xmm7,-0xa0(%r10) ++ vmovdqa %xmm8,-0x90(%r10) ++ vmovdqa %xmm9,-0x80(%r10) ++ vmovdqa %xmm10,-0x70(%r10) ++ vmovdqa %xmm11,-0x60(%r10) ++ vmovdqa %xmm12,-0x50(%r10) ++ vmovdqa %xmm13,-0x40(%r10) ++ vmovdqa %xmm14,-0x30(%r10) ++ vmovdqa %xmm15,-0x20(%r10) + .Ldo_avx512_body: + ___ + $code.=<<___; +@@ -2679,7 +2775,7 @@ $code.=<<___; + + lea 0x90(%rsp),%rax # size optimization for .Ltail_avx2 + add \$64,$len +- jnz .Ltail_avx2 ++ jnz .Ltail_avx2$suffix + + vpsubq $T2,$H2,$H2 # undo input accumulation + vmovd %x#$H0,`4*0-48-64`($ctx)# save partially reduced +@@ -2690,29 +2786,61 @@ $code.=<<___; + vzeroall + ___ + $code.=<<___ if ($win64); +- movdqa 0x50(%r11),%xmm6 +- movdqa 0x60(%r11),%xmm7 +- movdqa 0x70(%r11),%xmm8 +- movdqa 0x80(%r11),%xmm9 +- movdqa 0x90(%r11),%xmm10 +- movdqa 0xa0(%r11),%xmm11 +- movdqa 0xb0(%r11),%xmm12 +- movdqa 0xc0(%r11),%xmm13 +- movdqa 0xd0(%r11),%xmm14 +- movdqa 0xe0(%r11),%xmm15 +- lea 0xf8(%r11),%rsp ++ movdqa -0xb0(%r10),%xmm6 ++ movdqa -0xa0(%r10),%xmm7 ++ movdqa -0x90(%r10),%xmm8 ++ movdqa -0x80(%r10),%xmm9 ++ movdqa -0x70(%r10),%xmm10 ++ movdqa -0x60(%r10),%xmm11 ++ movdqa -0x50(%r10),%xmm12 ++ movdqa -0x40(%r10),%xmm13 ++ movdqa -0x30(%r10),%xmm14 ++ movdqa -0x20(%r10),%xmm15 ++ lea -8(%r10),%rsp + .Ldo_avx512_epilogue: + ___ + $code.=<<___ if (!$win64); +- lea 8(%r11),%rsp +-.cfi_def_cfa %rsp,8 ++ lea -8(%r10),%rsp ++.cfi_def_cfa_register %rsp + ___ + $code.=<<___; + ret + .cfi_endproc +-.size poly1305_blocks_avx512,.-poly1305_blocks_avx512 + ___ +-if ($avx>3) { ++ ++} ++ ++} ++ ++&declare_function("poly1305_blocks_avx2", 32, 4); ++poly1305_blocks_avxN(0); ++&end_function("poly1305_blocks_avx2"); ++ ++if($kernel) { ++ $code .= "#endif\n"; ++} ++ ++####################################################################### ++if ($avx>2) { ++# On entry we have input length divisible by 64. But since inner loop ++# processes 128 bytes per iteration, cases when length is not divisible ++# by 128 are handled by passing tail 64 bytes to .Ltail_avx2. For this ++# reason stack layout is kept identical to poly1305_blocks_avx2. If not ++# for this tail, we wouldn't have to even allocate stack frame... ++ ++if($kernel) { ++ $code .= "#ifdef CONFIG_AS_AVX512\n"; ++} ++ ++&declare_function("poly1305_blocks_avx512", 32, 4); ++poly1305_blocks_avxN(1); ++&end_function("poly1305_blocks_avx512"); ++ ++if ($kernel) { ++ $code .= "#endif\n"; ++} ++ ++if (!$kernel && $avx>3) { + ######################################################################## + # VPMADD52 version using 2^44 radix. + # +@@ -3753,45 +3881,9 @@ poly1305_emit_base2_44: + .size poly1305_emit_base2_44,.-poly1305_emit_base2_44 + ___ + } } } +-$code.=<<___; +-.align 64 +-.Lconst: +-.Lmask24: +-.long 0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0 +-.L129: +-.long `1<<24`,0,`1<<24`,0,`1<<24`,0,`1<<24`,0 +-.Lmask26: +-.long 0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0 +-.Lpermd_avx2: +-.long 2,2,2,3,2,0,2,1 +-.Lpermd_avx512: +-.long 0,0,0,1, 0,2,0,3, 0,4,0,5, 0,6,0,7 +- +-.L2_44_inp_permd: +-.long 0,1,1,2,2,3,7,7 +-.L2_44_inp_shift: +-.quad 0,12,24,64 +-.L2_44_mask: +-.quad 0xfffffffffff,0xfffffffffff,0x3ffffffffff,0xffffffffffffffff +-.L2_44_shift_rgt: +-.quad 44,44,42,64 +-.L2_44_shift_lft: +-.quad 8,8,10,64 +- +-.align 64 +-.Lx_mask44: +-.quad 0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff +-.quad 0xfffffffffff,0xfffffffffff,0xfffffffffff,0xfffffffffff +-.Lx_mask42: +-.quad 0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff +-.quad 0x3ffffffffff,0x3ffffffffff,0x3ffffffffff,0x3ffffffffff +-___ + } +-$code.=<<___; +-.asciz "Poly1305 for x86_64, CRYPTOGAMS by " +-.align 16 +-___ + ++if (!$kernel) + { # chacha20-poly1305 helpers + my ($out,$inp,$otp,$len)=$win64 ? ("%rcx","%rdx","%r8", "%r9") : # Win64 order + ("%rdi","%rsi","%rdx","%rcx"); # Unix order +@@ -4038,17 +4130,17 @@ avx_handler: + + .section .pdata + .align 4 +- .rva .LSEH_begin_poly1305_init +- .rva .LSEH_end_poly1305_init +- .rva .LSEH_info_poly1305_init +- +- .rva .LSEH_begin_poly1305_blocks +- .rva .LSEH_end_poly1305_blocks +- .rva .LSEH_info_poly1305_blocks +- +- .rva .LSEH_begin_poly1305_emit +- .rva .LSEH_end_poly1305_emit +- .rva .LSEH_info_poly1305_emit ++ .rva .LSEH_begin_poly1305_init_x86_64 ++ .rva .LSEH_end_poly1305_init_x86_64 ++ .rva .LSEH_info_poly1305_init_x86_64 ++ ++ .rva .LSEH_begin_poly1305_blocks_x86_64 ++ .rva .LSEH_end_poly1305_blocks_x86_64 ++ .rva .LSEH_info_poly1305_blocks_x86_64 ++ ++ .rva .LSEH_begin_poly1305_emit_x86_64 ++ .rva .LSEH_end_poly1305_emit_x86_64 ++ .rva .LSEH_info_poly1305_emit_x86_64 + ___ + $code.=<<___ if ($avx); + .rva .LSEH_begin_poly1305_blocks_avx +@@ -4088,20 +4180,20 @@ ___ + $code.=<<___; + .section .xdata + .align 8 +-.LSEH_info_poly1305_init: ++.LSEH_info_poly1305_init_x86_64: + .byte 9,0,0,0 + .rva se_handler +- .rva .LSEH_begin_poly1305_init,.LSEH_begin_poly1305_init ++ .rva .LSEH_begin_poly1305_init_x86_64,.LSEH_begin_poly1305_init_x86_64 + +-.LSEH_info_poly1305_blocks: ++.LSEH_info_poly1305_blocks_x86_64: + .byte 9,0,0,0 + .rva se_handler + .rva .Lblocks_body,.Lblocks_epilogue + +-.LSEH_info_poly1305_emit: ++.LSEH_info_poly1305_emit_x86_64: + .byte 9,0,0,0 + .rva se_handler +- .rva .LSEH_begin_poly1305_emit,.LSEH_begin_poly1305_emit ++ .rva .LSEH_begin_poly1305_emit_x86_64,.LSEH_begin_poly1305_emit_x86_64 + ___ + $code.=<<___ if ($avx); + .LSEH_info_poly1305_blocks_avx_1: +@@ -4148,12 +4240,26 @@ $code.=<<___ if ($avx>2); + ___ + } + ++open SELF,$0; ++while() { ++ next if (/^#!/); ++ last if (!s/^#/\/\// and !/^$/); ++ print; ++} ++close SELF; ++ + foreach (split('\n',$code)) { + s/\`([^\`]*)\`/eval($1)/ge; + s/%r([a-z]+)#d/%e$1/g; + s/%r([0-9]+)#d/%r$1d/g; + s/%x#%[yz]/%x/g or s/%y#%z/%y/g or s/%z#%[yz]/%z/g; + ++ if ($kernel) { ++ s/(^\.type.*),[0-9]+$/\1/; ++ s/(^\.type.*),\@abi-omnipotent+$/\1,\@function/; ++ next if /^\.cfi.*/; ++ } ++ + print $_,"\n"; + } + close STDOUT; +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -1,8 +1,6 @@ +-// SPDX-License-Identifier: GPL-2.0-or-later ++// SPDX-License-Identifier: GPL-2.0 OR MIT + /* +- * Poly1305 authenticator algorithm, RFC7539, SIMD glue code +- * +- * Copyright (C) 2015 Martin Willi ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. + */ + + #include +@@ -13,279 +11,170 @@ + #include + #include + #include ++#include + #include + +-asmlinkage void poly1305_block_sse2(u32 *h, const u8 *src, +- const u32 *r, unsigned int blocks); +-asmlinkage void poly1305_2block_sse2(u32 *h, const u8 *src, const u32 *r, +- unsigned int blocks, const u32 *u); +-asmlinkage void poly1305_4block_avx2(u32 *h, const u8 *src, const u32 *r, +- unsigned int blocks, const u32 *u); ++asmlinkage void poly1305_init_x86_64(void *ctx, ++ const u8 key[POLY1305_KEY_SIZE]); ++asmlinkage void poly1305_blocks_x86_64(void *ctx, const u8 *inp, ++ const size_t len, const u32 padbit); ++asmlinkage void poly1305_emit_x86_64(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], ++ const u32 nonce[4]); ++asmlinkage void poly1305_emit_avx(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], ++ const u32 nonce[4]); ++asmlinkage void poly1305_blocks_avx(void *ctx, const u8 *inp, const size_t len, ++ const u32 padbit); ++asmlinkage void poly1305_blocks_avx2(void *ctx, const u8 *inp, const size_t len, ++ const u32 padbit); ++asmlinkage void poly1305_blocks_avx512(void *ctx, const u8 *inp, ++ const size_t len, const u32 padbit); + +-static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_simd); ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx); + static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx2); ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(poly1305_use_avx512); + +-static inline u64 mlt(u64 a, u64 b) +-{ +- return a * b; +-} +- +-static inline u32 sr(u64 v, u_char n) +-{ +- return v >> n; +-} +- +-static inline u32 and(u32 v, u32 mask) +-{ +- return v & mask; +-} +- +-static void poly1305_simd_mult(u32 *a, const u32 *b) +-{ +- u8 m[POLY1305_BLOCK_SIZE]; +- +- memset(m, 0, sizeof(m)); +- /* The poly1305 block function adds a hi-bit to the accumulator which +- * we don't need for key multiplication; compensate for it. */ +- a[4] -= 1 << 24; +- poly1305_block_sse2(a, m, b, 1); +-} +- +-static void poly1305_integer_setkey(struct poly1305_key *key, const u8 *raw_key) +-{ +- /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ +- key->r[0] = (get_unaligned_le32(raw_key + 0) >> 0) & 0x3ffffff; +- key->r[1] = (get_unaligned_le32(raw_key + 3) >> 2) & 0x3ffff03; +- key->r[2] = (get_unaligned_le32(raw_key + 6) >> 4) & 0x3ffc0ff; +- key->r[3] = (get_unaligned_le32(raw_key + 9) >> 6) & 0x3f03fff; +- key->r[4] = (get_unaligned_le32(raw_key + 12) >> 8) & 0x00fffff; +-} ++struct poly1305_arch_internal { ++ union { ++ struct { ++ u32 h[5]; ++ u32 is_base2_26; ++ }; ++ u64 hs[3]; ++ }; ++ u64 r[2]; ++ u64 pad; ++ struct { u32 r2, r1, r4, r3; } rn[9]; ++}; + +-static void poly1305_integer_blocks(struct poly1305_state *state, +- const struct poly1305_key *key, +- const void *src, +- unsigned int nblocks, u32 hibit) ++/* The AVX code uses base 2^26, while the scalar code uses base 2^64. If we hit ++ * the unfortunate situation of using AVX and then having to go back to scalar ++ * -- because the user is silly and has called the update function from two ++ * separate contexts -- then we need to convert back to the original base before ++ * proceeding. It is possible to reason that the initial reduction below is ++ * sufficient given the implementation invariants. However, for an avoidance of ++ * doubt and because this is not performance critical, we do the full reduction ++ * anyway. Z3 proof of below function: https://xn--4db.cc/ltPtHCKN/py ++ */ ++static void convert_to_base2_64(void *ctx) + { +- u32 r0, r1, r2, r3, r4; +- u32 s1, s2, s3, s4; +- u32 h0, h1, h2, h3, h4; +- u64 d0, d1, d2, d3, d4; ++ struct poly1305_arch_internal *state = ctx; ++ u32 cy; + +- if (!nblocks) ++ if (!state->is_base2_26) + return; + +- r0 = key->r[0]; +- r1 = key->r[1]; +- r2 = key->r[2]; +- r3 = key->r[3]; +- r4 = key->r[4]; +- +- s1 = r1 * 5; +- s2 = r2 * 5; +- s3 = r3 * 5; +- s4 = r4 * 5; +- +- h0 = state->h[0]; +- h1 = state->h[1]; +- h2 = state->h[2]; +- h3 = state->h[3]; +- h4 = state->h[4]; +- +- do { +- /* h += m[i] */ +- h0 += (get_unaligned_le32(src + 0) >> 0) & 0x3ffffff; +- h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; +- h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff; +- h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff; +- h4 += (get_unaligned_le32(src + 12) >> 8) | (hibit << 24); +- +- /* h *= r */ +- d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + +- mlt(h3, s2) + mlt(h4, s1); +- d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + +- mlt(h3, s3) + mlt(h4, s2); +- d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + +- mlt(h3, s4) + mlt(h4, s3); +- d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + +- mlt(h3, r0) + mlt(h4, s4); +- d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + +- mlt(h3, r1) + mlt(h4, r0); +- +- /* (partial) h %= p */ +- d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff); +- d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff); +- d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff); +- d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff); +- h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff); +- h1 += h0 >> 26; h0 = h0 & 0x3ffffff; +- +- src += POLY1305_BLOCK_SIZE; +- } while (--nblocks); +- +- state->h[0] = h0; +- state->h[1] = h1; +- state->h[2] = h2; +- state->h[3] = h3; +- state->h[4] = h4; +-} +- +-static void poly1305_integer_emit(const struct poly1305_state *state, void *dst) +-{ +- u32 h0, h1, h2, h3, h4; +- u32 g0, g1, g2, g3, g4; +- u32 mask; +- +- /* fully carry h */ +- h0 = state->h[0]; +- h1 = state->h[1]; +- h2 = state->h[2]; +- h3 = state->h[3]; +- h4 = state->h[4]; +- +- h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; +- h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; +- h4 += (h3 >> 26); h3 = h3 & 0x3ffffff; +- h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff; +- h1 += (h0 >> 26); h0 = h0 & 0x3ffffff; +- +- /* compute h + -p */ +- g0 = h0 + 5; +- g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff; +- g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff; +- g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff; +- g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff; +- +- /* select h if h < p, or h + -p if h >= p */ +- mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; +- g0 &= mask; +- g1 &= mask; +- g2 &= mask; +- g3 &= mask; +- g4 &= mask; +- mask = ~mask; +- h0 = (h0 & mask) | g0; +- h1 = (h1 & mask) | g1; +- h2 = (h2 & mask) | g2; +- h3 = (h3 & mask) | g3; +- h4 = (h4 & mask) | g4; +- +- /* h = h % (2^128) */ +- put_unaligned_le32((h0 >> 0) | (h1 << 26), dst + 0); +- put_unaligned_le32((h1 >> 6) | (h2 << 20), dst + 4); +- put_unaligned_le32((h2 >> 12) | (h3 << 14), dst + 8); +- put_unaligned_le32((h3 >> 18) | (h4 << 8), dst + 12); +-} +- +-void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key) +-{ +- poly1305_integer_setkey(desc->opaque_r, key); +- desc->s[0] = get_unaligned_le32(key + 16); +- desc->s[1] = get_unaligned_le32(key + 20); +- desc->s[2] = get_unaligned_le32(key + 24); +- desc->s[3] = get_unaligned_le32(key + 28); +- poly1305_core_init(&desc->h); +- desc->buflen = 0; +- desc->sset = true; +- desc->rset = 1; +-} +-EXPORT_SYMBOL_GPL(poly1305_init_arch); +- +-static unsigned int crypto_poly1305_setdesckey(struct poly1305_desc_ctx *dctx, +- const u8 *src, unsigned int srclen) +-{ +- if (!dctx->sset) { +- if (!dctx->rset && srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_integer_setkey(dctx->r, src); +- src += POLY1305_BLOCK_SIZE; +- srclen -= POLY1305_BLOCK_SIZE; +- dctx->rset = 1; +- } +- if (srclen >= POLY1305_BLOCK_SIZE) { +- dctx->s[0] = get_unaligned_le32(src + 0); +- dctx->s[1] = get_unaligned_le32(src + 4); +- dctx->s[2] = get_unaligned_le32(src + 8); +- dctx->s[3] = get_unaligned_le32(src + 12); +- src += POLY1305_BLOCK_SIZE; +- srclen -= POLY1305_BLOCK_SIZE; +- dctx->sset = true; +- } ++ cy = state->h[0] >> 26; state->h[0] &= 0x3ffffff; state->h[1] += cy; ++ cy = state->h[1] >> 26; state->h[1] &= 0x3ffffff; state->h[2] += cy; ++ cy = state->h[2] >> 26; state->h[2] &= 0x3ffffff; state->h[3] += cy; ++ cy = state->h[3] >> 26; state->h[3] &= 0x3ffffff; state->h[4] += cy; ++ state->hs[0] = ((u64)state->h[2] << 52) | ((u64)state->h[1] << 26) | state->h[0]; ++ state->hs[1] = ((u64)state->h[4] << 40) | ((u64)state->h[3] << 14) | (state->h[2] >> 12); ++ state->hs[2] = state->h[4] >> 24; ++#define ULT(a, b) ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1)) ++ cy = (state->hs[2] >> 2) + (state->hs[2] & ~3ULL); ++ state->hs[2] &= 3; ++ state->hs[0] += cy; ++ state->hs[1] += (cy = ULT(state->hs[0], cy)); ++ state->hs[2] += ULT(state->hs[1], cy); ++#undef ULT ++ state->is_base2_26 = 0; ++} ++ ++static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_KEY_SIZE]) ++{ ++ poly1305_init_x86_64(ctx, key); ++} ++ ++static void poly1305_simd_blocks(void *ctx, const u8 *inp, size_t len, ++ const u32 padbit) ++{ ++ struct poly1305_arch_internal *state = ctx; ++ ++ /* SIMD disables preemption, so relax after processing each page. */ ++ BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE || ++ PAGE_SIZE % POLY1305_BLOCK_SIZE); ++ ++ if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) || ++ (len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) || ++ !crypto_simd_usable()) { ++ convert_to_base2_64(ctx); ++ poly1305_blocks_x86_64(ctx, inp, len, padbit); ++ return; + } +- return srclen; +-} + +-static unsigned int poly1305_scalar_blocks(struct poly1305_desc_ctx *dctx, +- const u8 *src, unsigned int srclen) +-{ +- unsigned int datalen; ++ for (;;) { ++ const size_t bytes = min_t(size_t, len, PAGE_SIZE); + +- if (unlikely(!dctx->sset)) { +- datalen = crypto_poly1305_setdesckey(dctx, src, srclen); +- src += srclen - datalen; +- srclen = datalen; +- } +- if (srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_integer_blocks(&dctx->h, dctx->opaque_r, src, +- srclen / POLY1305_BLOCK_SIZE, 1); +- srclen %= POLY1305_BLOCK_SIZE; ++ kernel_fpu_begin(); ++ if (IS_ENABLED(CONFIG_AS_AVX512) && static_branch_likely(&poly1305_use_avx512)) ++ poly1305_blocks_avx512(ctx, inp, bytes, padbit); ++ else if (IS_ENABLED(CONFIG_AS_AVX2) && static_branch_likely(&poly1305_use_avx2)) ++ poly1305_blocks_avx2(ctx, inp, bytes, padbit); ++ else ++ poly1305_blocks_avx(ctx, inp, bytes, padbit); ++ kernel_fpu_end(); ++ len -= bytes; ++ if (!len) ++ break; ++ inp += bytes; + } +- return srclen; + } + +-static unsigned int poly1305_simd_blocks(struct poly1305_desc_ctx *dctx, +- const u8 *src, unsigned int srclen) +-{ +- unsigned int blocks, datalen; ++static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], ++ const u32 nonce[4]) ++{ ++ struct poly1305_arch_internal *state = ctx; ++ ++ if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) || ++ !state->is_base2_26 || !crypto_simd_usable()) { ++ convert_to_base2_64(ctx); ++ poly1305_emit_x86_64(ctx, mac, nonce); ++ } else ++ poly1305_emit_avx(ctx, mac, nonce); ++} ++ ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++{ ++ poly1305_simd_init(&dctx->h, key); ++ dctx->s[0] = get_unaligned_le32(&key[16]); ++ dctx->s[1] = get_unaligned_le32(&key[20]); ++ dctx->s[2] = get_unaligned_le32(&key[24]); ++ dctx->s[3] = get_unaligned_le32(&key[28]); ++ dctx->buflen = 0; ++ dctx->sset = true; ++} ++EXPORT_SYMBOL(poly1305_init_arch); + ++static unsigned int crypto_poly1305_setdctxkey(struct poly1305_desc_ctx *dctx, ++ const u8 *inp, unsigned int len) ++{ ++ unsigned int acc = 0; + if (unlikely(!dctx->sset)) { +- datalen = crypto_poly1305_setdesckey(dctx, src, srclen); +- src += srclen - datalen; +- srclen = datalen; +- } +- +- if (IS_ENABLED(CONFIG_AS_AVX2) && +- static_branch_likely(&poly1305_use_avx2) && +- srclen >= POLY1305_BLOCK_SIZE * 4) { +- if (unlikely(dctx->rset < 4)) { +- if (dctx->rset < 2) { +- dctx->r[1] = dctx->r[0]; +- poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r); +- } +- dctx->r[2] = dctx->r[1]; +- poly1305_simd_mult(dctx->r[2].r, dctx->r[0].r); +- dctx->r[3] = dctx->r[2]; +- poly1305_simd_mult(dctx->r[3].r, dctx->r[0].r); +- dctx->rset = 4; ++ if (!dctx->rset && len >= POLY1305_BLOCK_SIZE) { ++ poly1305_simd_init(&dctx->h, inp); ++ inp += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ acc += POLY1305_BLOCK_SIZE; ++ dctx->rset = 1; + } +- blocks = srclen / (POLY1305_BLOCK_SIZE * 4); +- poly1305_4block_avx2(dctx->h.h, src, dctx->r[0].r, blocks, +- dctx->r[1].r); +- src += POLY1305_BLOCK_SIZE * 4 * blocks; +- srclen -= POLY1305_BLOCK_SIZE * 4 * blocks; +- } +- +- if (likely(srclen >= POLY1305_BLOCK_SIZE * 2)) { +- if (unlikely(dctx->rset < 2)) { +- dctx->r[1] = dctx->r[0]; +- poly1305_simd_mult(dctx->r[1].r, dctx->r[0].r); +- dctx->rset = 2; ++ if (len >= POLY1305_BLOCK_SIZE) { ++ dctx->s[0] = get_unaligned_le32(&inp[0]); ++ dctx->s[1] = get_unaligned_le32(&inp[4]); ++ dctx->s[2] = get_unaligned_le32(&inp[8]); ++ dctx->s[3] = get_unaligned_le32(&inp[12]); ++ inp += POLY1305_BLOCK_SIZE; ++ len -= POLY1305_BLOCK_SIZE; ++ acc += POLY1305_BLOCK_SIZE; ++ dctx->sset = true; + } +- blocks = srclen / (POLY1305_BLOCK_SIZE * 2); +- poly1305_2block_sse2(dctx->h.h, src, dctx->r[0].r, +- blocks, dctx->r[1].r); +- src += POLY1305_BLOCK_SIZE * 2 * blocks; +- srclen -= POLY1305_BLOCK_SIZE * 2 * blocks; +- } +- if (srclen >= POLY1305_BLOCK_SIZE) { +- poly1305_block_sse2(dctx->h.h, src, dctx->r[0].r, 1); +- srclen -= POLY1305_BLOCK_SIZE; + } +- return srclen; ++ return acc; + } + + void poly1305_update_arch(struct poly1305_desc_ctx *dctx, const u8 *src, + unsigned int srclen) + { +- unsigned int bytes; ++ unsigned int bytes, used; + + if (unlikely(dctx->buflen)) { + bytes = min(srclen, POLY1305_BLOCK_SIZE - dctx->buflen); +@@ -295,31 +184,19 @@ void poly1305_update_arch(struct poly130 + dctx->buflen += bytes; + + if (dctx->buflen == POLY1305_BLOCK_SIZE) { +- if (static_branch_likely(&poly1305_use_simd) && +- likely(crypto_simd_usable())) { +- kernel_fpu_begin(); +- poly1305_simd_blocks(dctx, dctx->buf, +- POLY1305_BLOCK_SIZE); +- kernel_fpu_end(); +- } else { +- poly1305_scalar_blocks(dctx, dctx->buf, +- POLY1305_BLOCK_SIZE); +- } ++ if (likely(!crypto_poly1305_setdctxkey(dctx, dctx->buf, POLY1305_BLOCK_SIZE))) ++ poly1305_simd_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 1); + dctx->buflen = 0; + } + } + + if (likely(srclen >= POLY1305_BLOCK_SIZE)) { +- if (static_branch_likely(&poly1305_use_simd) && +- likely(crypto_simd_usable())) { +- kernel_fpu_begin(); +- bytes = poly1305_simd_blocks(dctx, src, srclen); +- kernel_fpu_end(); +- } else { +- bytes = poly1305_scalar_blocks(dctx, src, srclen); +- } +- src += srclen - bytes; +- srclen = bytes; ++ bytes = round_down(srclen, POLY1305_BLOCK_SIZE); ++ srclen -= bytes; ++ used = crypto_poly1305_setdctxkey(dctx, src, bytes); ++ if (likely(bytes - used)) ++ poly1305_simd_blocks(&dctx->h, src + used, bytes - used, 1); ++ src += bytes; + } + + if (unlikely(srclen)) { +@@ -329,31 +206,17 @@ void poly1305_update_arch(struct poly130 + } + EXPORT_SYMBOL(poly1305_update_arch); + +-void poly1305_final_arch(struct poly1305_desc_ctx *desc, u8 *dst) ++void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst) + { +- __le32 digest[4]; +- u64 f = 0; +- +- if (unlikely(desc->buflen)) { +- desc->buf[desc->buflen++] = 1; +- memset(desc->buf + desc->buflen, 0, +- POLY1305_BLOCK_SIZE - desc->buflen); +- poly1305_integer_blocks(&desc->h, desc->opaque_r, desc->buf, 1, 0); ++ if (unlikely(dctx->buflen)) { ++ dctx->buf[dctx->buflen++] = 1; ++ memset(dctx->buf + dctx->buflen, 0, ++ POLY1305_BLOCK_SIZE - dctx->buflen); ++ poly1305_simd_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0); + } + +- poly1305_integer_emit(&desc->h, digest); +- +- /* mac = (h + s) % (2^128) */ +- f = (f >> 32) + le32_to_cpu(digest[0]) + desc->s[0]; +- put_unaligned_le32(f, dst + 0); +- f = (f >> 32) + le32_to_cpu(digest[1]) + desc->s[1]; +- put_unaligned_le32(f, dst + 4); +- f = (f >> 32) + le32_to_cpu(digest[2]) + desc->s[2]; +- put_unaligned_le32(f, dst + 8); +- f = (f >> 32) + le32_to_cpu(digest[3]) + desc->s[3]; +- put_unaligned_le32(f, dst + 12); +- +- *desc = (struct poly1305_desc_ctx){}; ++ poly1305_simd_emit(&dctx->h, dst, dctx->s); ++ *dctx = (struct poly1305_desc_ctx){}; + } + EXPORT_SYMBOL(poly1305_final_arch); + +@@ -361,38 +224,34 @@ static int crypto_poly1305_init(struct s + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + +- poly1305_core_init(&dctx->h); +- dctx->buflen = 0; +- dctx->rset = 0; +- dctx->sset = false; +- ++ *dctx = (struct poly1305_desc_ctx){}; + return 0; + } + +-static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) ++static int crypto_poly1305_update(struct shash_desc *desc, ++ const u8 *src, unsigned int srclen) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + +- if (unlikely(!dctx->sset)) +- return -ENOKEY; +- +- poly1305_final_arch(dctx, dst); ++ poly1305_update_arch(dctx, src, srclen); + return 0; + } + +-static int poly1305_simd_update(struct shash_desc *desc, +- const u8 *src, unsigned int srclen) ++static int crypto_poly1305_final(struct shash_desc *desc, u8 *dst) + { + struct poly1305_desc_ctx *dctx = shash_desc_ctx(desc); + +- poly1305_update_arch(dctx, src, srclen); ++ if (unlikely(!dctx->sset)) ++ return -ENOKEY; ++ ++ poly1305_final_arch(dctx, dst); + return 0; + } + + static struct shash_alg alg = { + .digestsize = POLY1305_DIGEST_SIZE, + .init = crypto_poly1305_init, +- .update = poly1305_simd_update, ++ .update = crypto_poly1305_update, + .final = crypto_poly1305_final, + .descsize = sizeof(struct poly1305_desc_ctx), + .base = { +@@ -406,17 +265,19 @@ static struct shash_alg alg = { + + static int __init poly1305_simd_mod_init(void) + { +- if (!boot_cpu_has(X86_FEATURE_XMM2)) +- return 0; +- +- static_branch_enable(&poly1305_use_simd); +- +- if (IS_ENABLED(CONFIG_AS_AVX2) && +- boot_cpu_has(X86_FEATURE_AVX) && ++ if (IS_ENABLED(CONFIG_AS_AVX) && boot_cpu_has(X86_FEATURE_AVX) && ++ cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) ++ static_branch_enable(&poly1305_use_avx); ++ if (IS_ENABLED(CONFIG_AS_AVX2) && boot_cpu_has(X86_FEATURE_AVX) && + boot_cpu_has(X86_FEATURE_AVX2) && + cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM, NULL)) + static_branch_enable(&poly1305_use_avx2); +- ++ if (IS_ENABLED(CONFIG_AS_AVX512) && boot_cpu_has(X86_FEATURE_AVX) && ++ boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_AVX512F) && ++ cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM | XFEATURE_MASK_AVX512, NULL) && ++ /* Skylake downclocks unacceptably much when using zmm, but later generations are fast. */ ++ boot_cpu_data.x86_model != INTEL_FAM6_SKYLAKE_X) ++ static_branch_enable(&poly1305_use_avx512); + return IS_REACHABLE(CONFIG_CRYPTO_HASH) ? crypto_register_shash(&alg) : 0; + } + +@@ -430,7 +291,7 @@ module_init(poly1305_simd_mod_init); + module_exit(poly1305_simd_mod_exit); + + MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Martin Willi "); ++MODULE_AUTHOR("Jason A. Donenfeld "); + MODULE_DESCRIPTION("Poly1305 authenticator"); + MODULE_ALIAS_CRYPTO("poly1305"); + MODULE_ALIAS_CRYPTO("poly1305-simd"); +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -90,7 +90,7 @@ config CRYPTO_LIB_DES + config CRYPTO_LIB_POLY1305_RSIZE + int + default 2 if MIPS +- default 4 if X86_64 ++ default 11 if X86_64 + default 9 if ARM || ARM64 + default 1 + diff --git a/ipq806x/backport-5.4/080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch b/ipq806x/backport-5.4/080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch new file mode 100644 index 0000000..b95b998 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0044-crypto-arm-arm64-mips-poly1305-remove-redundant-non-.patch @@ -0,0 +1,171 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 5 Jan 2020 22:40:49 -0500 +Subject: [PATCH] crypto: {arm,arm64,mips}/poly1305 - remove redundant + non-reduction from emit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 31899908a0d248b030b4464425b86c717e0007d4 upstream. + +This appears to be some kind of copy and paste error, and is actually +dead code. + +Pre: f = 0 ⇒ (f >> 32) = 0 + f = (f >> 32) + le32_to_cpu(digest[0]); +Post: 0 ≤ f < 2³² + put_unaligned_le32(f, dst); + +Pre: 0 ≤ f < 2³² ⇒ (f >> 32) = 0 + f = (f >> 32) + le32_to_cpu(digest[1]); +Post: 0 ≤ f < 2³² + put_unaligned_le32(f, dst + 4); + +Pre: 0 ≤ f < 2³² ⇒ (f >> 32) = 0 + f = (f >> 32) + le32_to_cpu(digest[2]); +Post: 0 ≤ f < 2³² + put_unaligned_le32(f, dst + 8); + +Pre: 0 ≤ f < 2³² ⇒ (f >> 32) = 0 + f = (f >> 32) + le32_to_cpu(digest[3]); +Post: 0 ≤ f < 2³² + put_unaligned_le32(f, dst + 12); + +Therefore this sequence is redundant. And Andy's code appears to handle +misalignment acceptably. + +Signed-off-by: Jason A. Donenfeld +Tested-by: Ard Biesheuvel +Reviewed-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/poly1305-glue.c | 18 ++---------------- + arch/arm64/crypto/poly1305-glue.c | 18 ++---------------- + arch/mips/crypto/poly1305-glue.c | 18 ++---------------- + 3 files changed, 6 insertions(+), 48 deletions(-) + +--- a/arch/arm/crypto/poly1305-glue.c ++++ b/arch/arm/crypto/poly1305-glue.c +@@ -20,7 +20,7 @@ + + void poly1305_init_arm(void *state, const u8 *key); + void poly1305_blocks_arm(void *state, const u8 *src, u32 len, u32 hibit); +-void poly1305_emit_arm(void *state, __le32 *digest, const u32 *nonce); ++void poly1305_emit_arm(void *state, u8 *digest, const u32 *nonce); + + void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit) + { +@@ -179,9 +179,6 @@ EXPORT_SYMBOL(poly1305_update_arch); + + void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst) + { +- __le32 digest[4]; +- u64 f = 0; +- + if (unlikely(dctx->buflen)) { + dctx->buf[dctx->buflen++] = 1; + memset(dctx->buf + dctx->buflen, 0, +@@ -189,18 +186,7 @@ void poly1305_final_arch(struct poly1305 + poly1305_blocks_arm(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0); + } + +- poly1305_emit_arm(&dctx->h, digest, dctx->s); +- +- /* mac = (h + s) % (2^128) */ +- f = (f >> 32) + le32_to_cpu(digest[0]); +- put_unaligned_le32(f, dst); +- f = (f >> 32) + le32_to_cpu(digest[1]); +- put_unaligned_le32(f, dst + 4); +- f = (f >> 32) + le32_to_cpu(digest[2]); +- put_unaligned_le32(f, dst + 8); +- f = (f >> 32) + le32_to_cpu(digest[3]); +- put_unaligned_le32(f, dst + 12); +- ++ poly1305_emit_arm(&dctx->h, dst, dctx->s); + *dctx = (struct poly1305_desc_ctx){}; + } + EXPORT_SYMBOL(poly1305_final_arch); +--- a/arch/arm64/crypto/poly1305-glue.c ++++ b/arch/arm64/crypto/poly1305-glue.c +@@ -21,7 +21,7 @@ + asmlinkage void poly1305_init_arm64(void *state, const u8 *key); + asmlinkage void poly1305_blocks(void *state, const u8 *src, u32 len, u32 hibit); + asmlinkage void poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit); +-asmlinkage void poly1305_emit(void *state, __le32 *digest, const u32 *nonce); ++asmlinkage void poly1305_emit(void *state, u8 *digest, const u32 *nonce); + + static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); + +@@ -162,9 +162,6 @@ EXPORT_SYMBOL(poly1305_update_arch); + + void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst) + { +- __le32 digest[4]; +- u64 f = 0; +- + if (unlikely(dctx->buflen)) { + dctx->buf[dctx->buflen++] = 1; + memset(dctx->buf + dctx->buflen, 0, +@@ -172,18 +169,7 @@ void poly1305_final_arch(struct poly1305 + poly1305_blocks(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0); + } + +- poly1305_emit(&dctx->h, digest, dctx->s); +- +- /* mac = (h + s) % (2^128) */ +- f = (f >> 32) + le32_to_cpu(digest[0]); +- put_unaligned_le32(f, dst); +- f = (f >> 32) + le32_to_cpu(digest[1]); +- put_unaligned_le32(f, dst + 4); +- f = (f >> 32) + le32_to_cpu(digest[2]); +- put_unaligned_le32(f, dst + 8); +- f = (f >> 32) + le32_to_cpu(digest[3]); +- put_unaligned_le32(f, dst + 12); +- ++ poly1305_emit(&dctx->h, dst, dctx->s); + *dctx = (struct poly1305_desc_ctx){}; + } + EXPORT_SYMBOL(poly1305_final_arch); +--- a/arch/mips/crypto/poly1305-glue.c ++++ b/arch/mips/crypto/poly1305-glue.c +@@ -15,7 +15,7 @@ + + asmlinkage void poly1305_init_mips(void *state, const u8 *key); + asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit); +-asmlinkage void poly1305_emit_mips(void *state, __le32 *digest, const u32 *nonce); ++asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce); + + void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) + { +@@ -134,9 +134,6 @@ EXPORT_SYMBOL(poly1305_update_arch); + + void poly1305_final_arch(struct poly1305_desc_ctx *dctx, u8 *dst) + { +- __le32 digest[4]; +- u64 f = 0; +- + if (unlikely(dctx->buflen)) { + dctx->buf[dctx->buflen++] = 1; + memset(dctx->buf + dctx->buflen, 0, +@@ -144,18 +141,7 @@ void poly1305_final_arch(struct poly1305 + poly1305_blocks_mips(&dctx->h, dctx->buf, POLY1305_BLOCK_SIZE, 0); + } + +- poly1305_emit_mips(&dctx->h, digest, dctx->s); +- +- /* mac = (h + s) % (2^128) */ +- f = (f >> 32) + le32_to_cpu(digest[0]); +- put_unaligned_le32(f, dst); +- f = (f >> 32) + le32_to_cpu(digest[1]); +- put_unaligned_le32(f, dst + 4); +- f = (f >> 32) + le32_to_cpu(digest[2]); +- put_unaligned_le32(f, dst + 8); +- f = (f >> 32) + le32_to_cpu(digest[3]); +- put_unaligned_le32(f, dst + 12); +- ++ poly1305_emit_mips(&dctx->h, dst, dctx->s); + *dctx = (struct poly1305_desc_ctx){}; + } + EXPORT_SYMBOL(poly1305_final_arch); diff --git a/ipq806x/backport-5.4/080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch b/ipq806x/backport-5.4/080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch new file mode 100644 index 0000000..fa8d8fd --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0045-crypto-curve25519-Fix-selftest-build-error.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 8 Jan 2020 12:37:35 +0800 +Subject: [PATCH] crypto: curve25519 - Fix selftest build error + +commit a8bdf2c42ee4d1ee42af1f3601f85de94e70a421 upstream. + +If CRYPTO_CURVE25519 is y, CRYPTO_LIB_CURVE25519_GENERIC will be +y, but CRYPTO_LIB_CURVE25519 may be set to m, this causes build +errors: + +lib/crypto/curve25519-selftest.o: In function `curve25519': +curve25519-selftest.c:(.text.unlikely+0xc): undefined reference to `curve25519_arch' +lib/crypto/curve25519-selftest.o: In function `curve25519_selftest': +curve25519-selftest.c:(.init.text+0x17e): undefined reference to `curve25519_base_arch' + +This is because the curve25519 self-test code is being controlled +by the GENERIC option rather than the overall CURVE25519 option, +as is the case with blake2s. To recap, the GENERIC and ARCH options +for CURVE25519 are internal only and selected by users such as +the Crypto API, or the externally visible CURVE25519 option which +in turn is selected by wireguard. The self-test is specific to the +the external CURVE25519 option and should not be enabled by the +Crypto API. + +This patch fixes this by splitting the GENERIC module from the +CURVE25519 module with the latter now containing just the self-test. + +Reported-by: Hulk Robot +Fixes: aa127963f1ca ("crypto: lib/curve25519 - re-add selftests") +Signed-off-by: Herbert Xu +Reviewed-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + lib/crypto/Makefile | 9 ++++++--- + lib/crypto/curve25519-generic.c | 24 ++++++++++++++++++++++++ + lib/crypto/curve25519.c | 7 ------- + 3 files changed, 30 insertions(+), 10 deletions(-) + create mode 100644 lib/crypto/curve25519-generic.c + +--- a/lib/crypto/Makefile ++++ b/lib/crypto/Makefile +@@ -19,9 +19,12 @@ libblake2s-y += blake2s.o + obj-$(CONFIG_CRYPTO_LIB_CHACHA20POLY1305) += libchacha20poly1305.o + libchacha20poly1305-y += chacha20poly1305.o + +-obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC) += libcurve25519.o +-libcurve25519-y := curve25519-fiat32.o +-libcurve25519-$(CONFIG_ARCH_SUPPORTS_INT128) := curve25519-hacl64.o ++obj-$(CONFIG_CRYPTO_LIB_CURVE25519_GENERIC) += libcurve25519-generic.o ++libcurve25519-generic-y := curve25519-fiat32.o ++libcurve25519-generic-$(CONFIG_ARCH_SUPPORTS_INT128) := curve25519-hacl64.o ++libcurve25519-generic-y += curve25519-generic.o ++ ++obj-$(CONFIG_CRYPTO_LIB_CURVE25519) += libcurve25519.o + libcurve25519-y += curve25519.o + + obj-$(CONFIG_CRYPTO_LIB_DES) += libdes.o +--- /dev/null ++++ b/lib/crypto/curve25519-generic.c +@@ -0,0 +1,24 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This is an implementation of the Curve25519 ECDH algorithm, using either ++ * a 32-bit implementation or a 64-bit implementation with 128-bit integers, ++ * depending on what is supported by the target compiler. ++ * ++ * Information: https://cr.yp.to/ecdh.html ++ */ ++ ++#include ++#include ++ ++const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 }; ++const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 }; ++ ++EXPORT_SYMBOL(curve25519_null_point); ++EXPORT_SYMBOL(curve25519_base_point); ++EXPORT_SYMBOL(curve25519_generic); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Curve25519 scalar multiplication"); ++MODULE_AUTHOR("Jason A. Donenfeld "); +--- a/lib/crypto/curve25519.c ++++ b/lib/crypto/curve25519.c +@@ -15,13 +15,6 @@ + + bool curve25519_selftest(void); + +-const u8 curve25519_null_point[CURVE25519_KEY_SIZE] __aligned(32) = { 0 }; +-const u8 curve25519_base_point[CURVE25519_KEY_SIZE] __aligned(32) = { 9 }; +- +-EXPORT_SYMBOL(curve25519_null_point); +-EXPORT_SYMBOL(curve25519_base_point); +-EXPORT_SYMBOL(curve25519_generic); +- + static int __init mod_init(void) + { + if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) && diff --git a/ipq806x/backport-5.4/080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch b/ipq806x/backport-5.4/080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch new file mode 100644 index 0000000..27f0417 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0046-crypto-x86-poly1305-fix-.gitignore-typo.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 16 Jan 2020 18:23:55 +0100 +Subject: [PATCH] crypto: x86/poly1305 - fix .gitignore typo + +commit 1f6868995326cc82102049e349d8dbd116bdb656 upstream. + +Admist the kbuild robot induced changes, the .gitignore file for the +generated file wasn't updated with the non-clashing filename. This +commit adjusts that. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/.gitignore | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/crypto/.gitignore ++++ b/arch/x86/crypto/.gitignore +@@ -1 +1 @@ +-poly1305-x86_64.S ++poly1305-x86_64-cryptogams.S diff --git a/ipq806x/backport-5.4/080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch b/ipq806x/backport-5.4/080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch new file mode 100644 index 0000000..eda9695 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0047-crypto-chacha20poly1305-add-back-missing-test-vector.patch @@ -0,0 +1,1858 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 16 Jan 2020 21:26:34 +0100 +Subject: [PATCH] crypto: chacha20poly1305 - add back missing test vectors and + test chunking + +commit 72c7943792c9e7788ddd182337bcf8f650cf56f5 upstream. + +When this was originally ported, the 12-byte nonce vectors were left out +to keep things simple. I agree that we don't need nor want a library +interface for 12-byte nonces. But these test vectors were specially +crafted to look at issues in the underlying primitives and related +interactions. Therefore, we actually want to keep around all of the +test vectors, and simply have a helper function to test them with. + +Secondly, the sglist-based chunking code in the library interface is +rather complicated, so this adds a developer-only test for ensuring that +all the book keeping is correct, across a wide array of possibilities. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + lib/crypto/chacha20poly1305-selftest.c | 1712 +++++++++++++++++++++++- + 1 file changed, 1698 insertions(+), 14 deletions(-) + +--- a/lib/crypto/chacha20poly1305-selftest.c ++++ b/lib/crypto/chacha20poly1305-selftest.c +@@ -4,6 +4,7 @@ + */ + + #include ++#include + #include + + #include +@@ -1926,6 +1927,1104 @@ static const u8 enc_key012[] __initconst + 0x65, 0x91, 0x6e, 0x2a, 0x79, 0x22, 0xda, 0x64 + }; + ++/* wycheproof - rfc7539 */ ++static const u8 enc_input013[] __initconst = { ++ 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, ++ 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, ++ 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, ++ 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, ++ 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, ++ 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, ++ 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, ++ 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, ++ 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, ++ 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, ++ 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, ++ 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, ++ 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, ++ 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, ++ 0x74, 0x2e ++}; ++static const u8 enc_output013[] __initconst = { ++ 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, ++ 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, ++ 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, ++ 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, ++ 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, ++ 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, ++ 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, ++ 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, ++ 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, ++ 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, ++ 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, ++ 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, ++ 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, ++ 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, ++ 0x61, 0x16, 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, ++ 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, ++ 0x06, 0x91 ++}; ++static const u8 enc_assoc013[] __initconst = { ++ 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, ++ 0xc4, 0xc5, 0xc6, 0xc7 ++}; ++static const u8 enc_nonce013[] __initconst = { ++ 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, ++ 0x44, 0x45, 0x46, 0x47 ++}; ++static const u8 enc_key013[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input014[] __initconst = { }; ++static const u8 enc_output014[] __initconst = { ++ 0x76, 0xac, 0xb3, 0x42, 0xcf, 0x31, 0x66, 0xa5, ++ 0xb6, 0x3c, 0x0c, 0x0e, 0xa1, 0x38, 0x3c, 0x8d ++}; ++static const u8 enc_assoc014[] __initconst = { }; ++static const u8 enc_nonce014[] __initconst = { ++ 0x4d, 0xa5, 0xbf, 0x8d, 0xfd, 0x58, 0x52, 0xc1, ++ 0xea, 0x12, 0x37, 0x9d ++}; ++static const u8 enc_key014[] __initconst = { ++ 0x80, 0xba, 0x31, 0x92, 0xc8, 0x03, 0xce, 0x96, ++ 0x5e, 0xa3, 0x71, 0xd5, 0xff, 0x07, 0x3c, 0xf0, ++ 0xf4, 0x3b, 0x6a, 0x2a, 0xb5, 0x76, 0xb2, 0x08, ++ 0x42, 0x6e, 0x11, 0x40, 0x9c, 0x09, 0xb9, 0xb0 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input015[] __initconst = { }; ++static const u8 enc_output015[] __initconst = { ++ 0x90, 0x6f, 0xa6, 0x28, 0x4b, 0x52, 0xf8, 0x7b, ++ 0x73, 0x59, 0xcb, 0xaa, 0x75, 0x63, 0xc7, 0x09 ++}; ++static const u8 enc_assoc015[] __initconst = { ++ 0xbd, 0x50, 0x67, 0x64, 0xf2, 0xd2, 0xc4, 0x10 ++}; ++static const u8 enc_nonce015[] __initconst = { ++ 0xa9, 0x2e, 0xf0, 0xac, 0x99, 0x1d, 0xd5, 0x16, ++ 0xa3, 0xc6, 0xf6, 0x89 ++}; ++static const u8 enc_key015[] __initconst = { ++ 0x7a, 0x4c, 0xd7, 0x59, 0x17, 0x2e, 0x02, 0xeb, ++ 0x20, 0x4d, 0xb2, 0xc3, 0xf5, 0xc7, 0x46, 0x22, ++ 0x7d, 0xf5, 0x84, 0xfc, 0x13, 0x45, 0x19, 0x63, ++ 0x91, 0xdb, 0xb9, 0x57, 0x7a, 0x25, 0x07, 0x42 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input016[] __initconst = { ++ 0x2a ++}; ++static const u8 enc_output016[] __initconst = { ++ 0x3a, 0xca, 0xc2, 0x7d, 0xec, 0x09, 0x68, 0x80, ++ 0x1e, 0x9f, 0x6e, 0xde, 0xd6, 0x9d, 0x80, 0x75, ++ 0x22 ++}; ++static const u8 enc_assoc016[] __initconst = { }; ++static const u8 enc_nonce016[] __initconst = { ++ 0x99, 0xe2, 0x3e, 0xc4, 0x89, 0x85, 0xbc, 0xcd, ++ 0xee, 0xab, 0x60, 0xf1 ++}; ++static const u8 enc_key016[] __initconst = { ++ 0xcc, 0x56, 0xb6, 0x80, 0x55, 0x2e, 0xb7, 0x50, ++ 0x08, 0xf5, 0x48, 0x4b, 0x4c, 0xb8, 0x03, 0xfa, ++ 0x50, 0x63, 0xeb, 0xd6, 0xea, 0xb9, 0x1f, 0x6a, ++ 0xb6, 0xae, 0xf4, 0x91, 0x6a, 0x76, 0x62, 0x73 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input017[] __initconst = { ++ 0x51 ++}; ++static const u8 enc_output017[] __initconst = { ++ 0xc4, 0x16, 0x83, 0x10, 0xca, 0x45, 0xb1, 0xf7, ++ 0xc6, 0x6c, 0xad, 0x4e, 0x99, 0xe4, 0x3f, 0x72, ++ 0xb9 ++}; ++static const u8 enc_assoc017[] __initconst = { ++ 0x91, 0xca, 0x6c, 0x59, 0x2c, 0xbc, 0xca, 0x53 ++}; ++static const u8 enc_nonce017[] __initconst = { ++ 0xab, 0x0d, 0xca, 0x71, 0x6e, 0xe0, 0x51, 0xd2, ++ 0x78, 0x2f, 0x44, 0x03 ++}; ++static const u8 enc_key017[] __initconst = { ++ 0x46, 0xf0, 0x25, 0x49, 0x65, 0xf7, 0x69, 0xd5, ++ 0x2b, 0xdb, 0x4a, 0x70, 0xb4, 0x43, 0x19, 0x9f, ++ 0x8e, 0xf2, 0x07, 0x52, 0x0d, 0x12, 0x20, 0xc5, ++ 0x5e, 0x4b, 0x70, 0xf0, 0xfd, 0xa6, 0x20, 0xee ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input018[] __initconst = { ++ 0x5c, 0x60 ++}; ++static const u8 enc_output018[] __initconst = { ++ 0x4d, 0x13, 0x91, 0xe8, 0xb6, 0x1e, 0xfb, 0x39, ++ 0xc1, 0x22, 0x19, 0x54, 0x53, 0x07, 0x7b, 0x22, ++ 0xe5, 0xe2 ++}; ++static const u8 enc_assoc018[] __initconst = { }; ++static const u8 enc_nonce018[] __initconst = { ++ 0x46, 0x1a, 0xf1, 0x22, 0xe9, 0xf2, 0xe0, 0x34, ++ 0x7e, 0x03, 0xf2, 0xdb ++}; ++static const u8 enc_key018[] __initconst = { ++ 0x2f, 0x7f, 0x7e, 0x4f, 0x59, 0x2b, 0xb3, 0x89, ++ 0x19, 0x49, 0x89, 0x74, 0x35, 0x07, 0xbf, 0x3e, ++ 0xe9, 0xcb, 0xde, 0x17, 0x86, 0xb6, 0x69, 0x5f, ++ 0xe6, 0xc0, 0x25, 0xfd, 0x9b, 0xa4, 0xc1, 0x00 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input019[] __initconst = { ++ 0xdd, 0xf2 ++}; ++static const u8 enc_output019[] __initconst = { ++ 0xb6, 0x0d, 0xea, 0xd0, 0xfd, 0x46, 0x97, 0xec, ++ 0x2e, 0x55, 0x58, 0x23, 0x77, 0x19, 0xd0, 0x24, ++ 0x37, 0xa2 ++}; ++static const u8 enc_assoc019[] __initconst = { ++ 0x88, 0x36, 0x4f, 0xc8, 0x06, 0x05, 0x18, 0xbf ++}; ++static const u8 enc_nonce019[] __initconst = { ++ 0x61, 0x54, 0x6b, 0xa5, 0xf1, 0x72, 0x05, 0x90, ++ 0xb6, 0x04, 0x0a, 0xc6 ++}; ++static const u8 enc_key019[] __initconst = { ++ 0xc8, 0x83, 0x3d, 0xce, 0x5e, 0xa9, 0xf2, 0x48, ++ 0xaa, 0x20, 0x30, 0xea, 0xcf, 0xe7, 0x2b, 0xff, ++ 0xe6, 0x9a, 0x62, 0x0c, 0xaf, 0x79, 0x33, 0x44, ++ 0xe5, 0x71, 0x8f, 0xe0, 0xd7, 0xab, 0x1a, 0x58 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input020[] __initconst = { ++ 0xab, 0x85, 0xe9, 0xc1, 0x57, 0x17, 0x31 ++}; ++static const u8 enc_output020[] __initconst = { ++ 0x5d, 0xfe, 0x34, 0x40, 0xdb, 0xb3, 0xc3, 0xed, ++ 0x7a, 0x43, 0x4e, 0x26, 0x02, 0xd3, 0x94, 0x28, ++ 0x1e, 0x0a, 0xfa, 0x9f, 0xb7, 0xaa, 0x42 ++}; ++static const u8 enc_assoc020[] __initconst = { }; ++static const u8 enc_nonce020[] __initconst = { ++ 0x3c, 0x4e, 0x65, 0x4d, 0x66, 0x3f, 0xa4, 0x59, ++ 0x6d, 0xc5, 0x5b, 0xb7 ++}; ++static const u8 enc_key020[] __initconst = { ++ 0x55, 0x56, 0x81, 0x58, 0xd3, 0xa6, 0x48, 0x3f, ++ 0x1f, 0x70, 0x21, 0xea, 0xb6, 0x9b, 0x70, 0x3f, ++ 0x61, 0x42, 0x51, 0xca, 0xdc, 0x1a, 0xf5, 0xd3, ++ 0x4a, 0x37, 0x4f, 0xdb, 0xfc, 0x5a, 0xda, 0xc7 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input021[] __initconst = { ++ 0x4e, 0xe5, 0xcd, 0xa2, 0x0d, 0x42, 0x90 ++}; ++static const u8 enc_output021[] __initconst = { ++ 0x4b, 0xd4, 0x72, 0x12, 0x94, 0x1c, 0xe3, 0x18, ++ 0x5f, 0x14, 0x08, 0xee, 0x7f, 0xbf, 0x18, 0xf5, ++ 0xab, 0xad, 0x6e, 0x22, 0x53, 0xa1, 0xba ++}; ++static const u8 enc_assoc021[] __initconst = { ++ 0x84, 0xe4, 0x6b, 0xe8, 0xc0, 0x91, 0x90, 0x53 ++}; ++static const u8 enc_nonce021[] __initconst = { ++ 0x58, 0x38, 0x93, 0x75, 0xc6, 0x9e, 0xe3, 0x98, ++ 0xde, 0x94, 0x83, 0x96 ++}; ++static const u8 enc_key021[] __initconst = { ++ 0xe3, 0xc0, 0x9e, 0x7f, 0xab, 0x1a, 0xef, 0xb5, ++ 0x16, 0xda, 0x6a, 0x33, 0x02, 0x2a, 0x1d, 0xd4, ++ 0xeb, 0x27, 0x2c, 0x80, 0xd5, 0x40, 0xc5, 0xda, ++ 0x52, 0xa7, 0x30, 0xf3, 0x4d, 0x84, 0x0d, 0x7f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input022[] __initconst = { ++ 0xbe, 0x33, 0x08, 0xf7, 0x2a, 0x2c, 0x6a, 0xed ++}; ++static const u8 enc_output022[] __initconst = { ++ 0x8e, 0x94, 0x39, 0xa5, 0x6e, 0xee, 0xc8, 0x17, ++ 0xfb, 0xe8, 0xa6, 0xed, 0x8f, 0xab, 0xb1, 0x93, ++ 0x75, 0x39, 0xdd, 0x6c, 0x00, 0xe9, 0x00, 0x21 ++}; ++static const u8 enc_assoc022[] __initconst = { }; ++static const u8 enc_nonce022[] __initconst = { ++ 0x4f, 0x07, 0xaf, 0xed, 0xfd, 0xc3, 0xb6, 0xc2, ++ 0x36, 0x18, 0x23, 0xd3 ++}; ++static const u8 enc_key022[] __initconst = { ++ 0x51, 0xe4, 0xbf, 0x2b, 0xad, 0x92, 0xb7, 0xaf, ++ 0xf1, 0xa4, 0xbc, 0x05, 0x55, 0x0b, 0xa8, 0x1d, ++ 0xf4, 0xb9, 0x6f, 0xab, 0xf4, 0x1c, 0x12, 0xc7, ++ 0xb0, 0x0e, 0x60, 0xe4, 0x8d, 0xb7, 0xe1, 0x52 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input023[] __initconst = { ++ 0xa4, 0xc9, 0xc2, 0x80, 0x1b, 0x71, 0xf7, 0xdf ++}; ++static const u8 enc_output023[] __initconst = { ++ 0xb9, 0xb9, 0x10, 0x43, 0x3a, 0xf0, 0x52, 0xb0, ++ 0x45, 0x30, 0xf5, 0x1a, 0xee, 0xe0, 0x24, 0xe0, ++ 0xa4, 0x45, 0xa6, 0x32, 0x8f, 0xa6, 0x7a, 0x18 ++}; ++static const u8 enc_assoc023[] __initconst = { ++ 0x66, 0xc0, 0xae, 0x70, 0x07, 0x6c, 0xb1, 0x4d ++}; ++static const u8 enc_nonce023[] __initconst = { ++ 0xb4, 0xea, 0x66, 0x6e, 0xe1, 0x19, 0x56, 0x33, ++ 0x66, 0x48, 0x4a, 0x78 ++}; ++static const u8 enc_key023[] __initconst = { ++ 0x11, 0x31, 0xc1, 0x41, 0x85, 0x77, 0xa0, 0x54, ++ 0xde, 0x7a, 0x4a, 0xc5, 0x51, 0x95, 0x0f, 0x1a, ++ 0x05, 0x3f, 0x9a, 0xe4, 0x6e, 0x5b, 0x75, 0xfe, ++ 0x4a, 0xbd, 0x56, 0x08, 0xd7, 0xcd, 0xda, 0xdd ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input024[] __initconst = { ++ 0x42, 0xba, 0xae, 0x59, 0x78, 0xfe, 0xaf, 0x5c, ++ 0x36, 0x8d, 0x14, 0xe0 ++}; ++static const u8 enc_output024[] __initconst = { ++ 0xff, 0x7d, 0xc2, 0x03, 0xb2, 0x6c, 0x46, 0x7a, ++ 0x6b, 0x50, 0xdb, 0x33, 0x57, 0x8c, 0x0f, 0x27, ++ 0x58, 0xc2, 0xe1, 0x4e, 0x36, 0xd4, 0xfc, 0x10, ++ 0x6d, 0xcb, 0x29, 0xb4 ++}; ++static const u8 enc_assoc024[] __initconst = { }; ++static const u8 enc_nonce024[] __initconst = { ++ 0x9a, 0x59, 0xfc, 0xe2, 0x6d, 0xf0, 0x00, 0x5e, ++ 0x07, 0x53, 0x86, 0x56 ++}; ++static const u8 enc_key024[] __initconst = { ++ 0x99, 0xb6, 0x2b, 0xd5, 0xaf, 0xbe, 0x3f, 0xb0, ++ 0x15, 0xbd, 0xe9, 0x3f, 0x0a, 0xbf, 0x48, 0x39, ++ 0x57, 0xa1, 0xc3, 0xeb, 0x3c, 0xa5, 0x9c, 0xb5, ++ 0x0b, 0x39, 0xf7, 0xf8, 0xa9, 0xcc, 0x51, 0xbe ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input025[] __initconst = { ++ 0xfd, 0xc8, 0x5b, 0x94, 0xa4, 0xb2, 0xa6, 0xb7, ++ 0x59, 0xb1, 0xa0, 0xda ++}; ++static const u8 enc_output025[] __initconst = { ++ 0x9f, 0x88, 0x16, 0xde, 0x09, 0x94, 0xe9, 0x38, ++ 0xd9, 0xe5, 0x3f, 0x95, 0xd0, 0x86, 0xfc, 0x6c, ++ 0x9d, 0x8f, 0xa9, 0x15, 0xfd, 0x84, 0x23, 0xa7, ++ 0xcf, 0x05, 0x07, 0x2f ++}; ++static const u8 enc_assoc025[] __initconst = { ++ 0xa5, 0x06, 0xe1, 0xa5, 0xc6, 0x90, 0x93, 0xf9 ++}; ++static const u8 enc_nonce025[] __initconst = { ++ 0x58, 0xdb, 0xd4, 0xad, 0x2c, 0x4a, 0xd3, 0x5d, ++ 0xd9, 0x06, 0xe9, 0xce ++}; ++static const u8 enc_key025[] __initconst = { ++ 0x85, 0xf3, 0x5b, 0x62, 0x82, 0xcf, 0xf4, 0x40, ++ 0xbc, 0x10, 0x20, 0xc8, 0x13, 0x6f, 0xf2, 0x70, ++ 0x31, 0x11, 0x0f, 0xa6, 0x3e, 0xc1, 0x6f, 0x1e, ++ 0x82, 0x51, 0x18, 0xb0, 0x06, 0xb9, 0x12, 0x57 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input026[] __initconst = { ++ 0x51, 0xf8, 0xc1, 0xf7, 0x31, 0xea, 0x14, 0xac, ++ 0xdb, 0x21, 0x0a, 0x6d, 0x97, 0x3e, 0x07 ++}; ++static const u8 enc_output026[] __initconst = { ++ 0x0b, 0x29, 0x63, 0x8e, 0x1f, 0xbd, 0xd6, 0xdf, ++ 0x53, 0x97, 0x0b, 0xe2, 0x21, 0x00, 0x42, 0x2a, ++ 0x91, 0x34, 0x08, 0x7d, 0x67, 0xa4, 0x6e, 0x79, ++ 0x17, 0x8d, 0x0a, 0x93, 0xf5, 0xe1, 0xd2 ++}; ++static const u8 enc_assoc026[] __initconst = { }; ++static const u8 enc_nonce026[] __initconst = { ++ 0x68, 0xab, 0x7f, 0xdb, 0xf6, 0x19, 0x01, 0xda, ++ 0xd4, 0x61, 0xd2, 0x3c ++}; ++static const u8 enc_key026[] __initconst = { ++ 0x67, 0x11, 0x96, 0x27, 0xbd, 0x98, 0x8e, 0xda, ++ 0x90, 0x62, 0x19, 0xe0, 0x8c, 0x0d, 0x0d, 0x77, ++ 0x9a, 0x07, 0xd2, 0x08, 0xce, 0x8a, 0x4f, 0xe0, ++ 0x70, 0x9a, 0xf7, 0x55, 0xee, 0xec, 0x6d, 0xcb ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input027[] __initconst = { ++ 0x97, 0x46, 0x9d, 0xa6, 0x67, 0xd6, 0x11, 0x0f, ++ 0x9c, 0xbd, 0xa1, 0xd1, 0xa2, 0x06, 0x73 ++}; ++static const u8 enc_output027[] __initconst = { ++ 0x32, 0xdb, 0x66, 0xc4, 0xa3, 0x81, 0x9d, 0x81, ++ 0x55, 0x74, 0x55, 0xe5, 0x98, 0x0f, 0xed, 0xfe, ++ 0xae, 0x30, 0xde, 0xc9, 0x4e, 0x6a, 0xd3, 0xa9, ++ 0xee, 0xa0, 0x6a, 0x0d, 0x70, 0x39, 0x17 ++}; ++static const u8 enc_assoc027[] __initconst = { ++ 0x64, 0x53, 0xa5, 0x33, 0x84, 0x63, 0x22, 0x12 ++}; ++static const u8 enc_nonce027[] __initconst = { ++ 0xd9, 0x5b, 0x32, 0x43, 0xaf, 0xae, 0xf7, 0x14, ++ 0xc5, 0x03, 0x5b, 0x6a ++}; ++static const u8 enc_key027[] __initconst = { ++ 0xe6, 0xf1, 0x11, 0x8d, 0x41, 0xe4, 0xb4, 0x3f, ++ 0xb5, 0x82, 0x21, 0xb7, 0xed, 0x79, 0x67, 0x38, ++ 0x34, 0xe0, 0xd8, 0xac, 0x5c, 0x4f, 0xa6, 0x0b, ++ 0xbc, 0x8b, 0xc4, 0x89, 0x3a, 0x58, 0x89, 0x4d ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input028[] __initconst = { ++ 0x54, 0x9b, 0x36, 0x5a, 0xf9, 0x13, 0xf3, 0xb0, ++ 0x81, 0x13, 0x1c, 0xcb, 0x6b, 0x82, 0x55, 0x88 ++}; ++static const u8 enc_output028[] __initconst = { ++ 0xe9, 0x11, 0x0e, 0x9f, 0x56, 0xab, 0x3c, 0xa4, ++ 0x83, 0x50, 0x0c, 0xea, 0xba, 0xb6, 0x7a, 0x13, ++ 0x83, 0x6c, 0xca, 0xbf, 0x15, 0xa6, 0xa2, 0x2a, ++ 0x51, 0xc1, 0x07, 0x1c, 0xfa, 0x68, 0xfa, 0x0c ++}; ++static const u8 enc_assoc028[] __initconst = { }; ++static const u8 enc_nonce028[] __initconst = { ++ 0x2f, 0xcb, 0x1b, 0x38, 0xa9, 0x9e, 0x71, 0xb8, ++ 0x47, 0x40, 0xad, 0x9b ++}; ++static const u8 enc_key028[] __initconst = { ++ 0x59, 0xd4, 0xea, 0xfb, 0x4d, 0xe0, 0xcf, 0xc7, ++ 0xd3, 0xdb, 0x99, 0xa8, 0xf5, 0x4b, 0x15, 0xd7, ++ 0xb3, 0x9f, 0x0a, 0xcc, 0x8d, 0xa6, 0x97, 0x63, ++ 0xb0, 0x19, 0xc1, 0x69, 0x9f, 0x87, 0x67, 0x4a ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input029[] __initconst = { ++ 0x55, 0xa4, 0x65, 0x64, 0x4f, 0x5b, 0x65, 0x09, ++ 0x28, 0xcb, 0xee, 0x7c, 0x06, 0x32, 0x14, 0xd6 ++}; ++static const u8 enc_output029[] __initconst = { ++ 0xe4, 0xb1, 0x13, 0xcb, 0x77, 0x59, 0x45, 0xf3, ++ 0xd3, 0xa8, 0xae, 0x9e, 0xc1, 0x41, 0xc0, 0x0c, ++ 0x7c, 0x43, 0xf1, 0x6c, 0xe0, 0x96, 0xd0, 0xdc, ++ 0x27, 0xc9, 0x58, 0x49, 0xdc, 0x38, 0x3b, 0x7d ++}; ++static const u8 enc_assoc029[] __initconst = { ++ 0x03, 0x45, 0x85, 0x62, 0x1a, 0xf8, 0xd7, 0xff ++}; ++static const u8 enc_nonce029[] __initconst = { ++ 0x11, 0x8a, 0x69, 0x64, 0xc2, 0xd3, 0xe3, 0x80, ++ 0x07, 0x1f, 0x52, 0x66 ++}; ++static const u8 enc_key029[] __initconst = { ++ 0xb9, 0x07, 0xa4, 0x50, 0x75, 0x51, 0x3f, 0xe8, ++ 0xa8, 0x01, 0x9e, 0xde, 0xe3, 0xf2, 0x59, 0x14, ++ 0x87, 0xb2, 0xa0, 0x30, 0xb0, 0x3c, 0x6e, 0x1d, ++ 0x77, 0x1c, 0x86, 0x25, 0x71, 0xd2, 0xea, 0x1e ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input030[] __initconst = { ++ 0x3f, 0xf1, 0x51, 0x4b, 0x1c, 0x50, 0x39, 0x15, ++ 0x91, 0x8f, 0x0c, 0x0c, 0x31, 0x09, 0x4a, 0x6e, ++ 0x1f ++}; ++static const u8 enc_output030[] __initconst = { ++ 0x02, 0xcc, 0x3a, 0xcb, 0x5e, 0xe1, 0xfc, 0xdd, ++ 0x12, 0xa0, 0x3b, 0xb8, 0x57, 0x97, 0x64, 0x74, ++ 0xd3, 0xd8, 0x3b, 0x74, 0x63, 0xa2, 0xc3, 0x80, ++ 0x0f, 0xe9, 0x58, 0xc2, 0x8e, 0xaa, 0x29, 0x08, ++ 0x13 ++}; ++static const u8 enc_assoc030[] __initconst = { }; ++static const u8 enc_nonce030[] __initconst = { ++ 0x45, 0xaa, 0xa3, 0xe5, 0xd1, 0x6d, 0x2d, 0x42, ++ 0xdc, 0x03, 0x44, 0x5d ++}; ++static const u8 enc_key030[] __initconst = { ++ 0x3b, 0x24, 0x58, 0xd8, 0x17, 0x6e, 0x16, 0x21, ++ 0xc0, 0xcc, 0x24, 0xc0, 0xc0, 0xe2, 0x4c, 0x1e, ++ 0x80, 0xd7, 0x2f, 0x7e, 0xe9, 0x14, 0x9a, 0x4b, ++ 0x16, 0x61, 0x76, 0x62, 0x96, 0x16, 0xd0, 0x11 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input031[] __initconst = { ++ 0x63, 0x85, 0x8c, 0xa3, 0xe2, 0xce, 0x69, 0x88, ++ 0x7b, 0x57, 0x8a, 0x3c, 0x16, 0x7b, 0x42, 0x1c, ++ 0x9c ++}; ++static const u8 enc_output031[] __initconst = { ++ 0x35, 0x76, 0x64, 0x88, 0xd2, 0xbc, 0x7c, 0x2b, ++ 0x8d, 0x17, 0xcb, 0xbb, 0x9a, 0xbf, 0xad, 0x9e, ++ 0x6d, 0x1f, 0x39, 0x1e, 0x65, 0x7b, 0x27, 0x38, ++ 0xdd, 0xa0, 0x84, 0x48, 0xcb, 0xa2, 0x81, 0x1c, ++ 0xeb ++}; ++static const u8 enc_assoc031[] __initconst = { ++ 0x9a, 0xaf, 0x29, 0x9e, 0xee, 0xa7, 0x8f, 0x79 ++}; ++static const u8 enc_nonce031[] __initconst = { ++ 0xf0, 0x38, 0x4f, 0xb8, 0x76, 0x12, 0x14, 0x10, ++ 0x63, 0x3d, 0x99, 0x3d ++}; ++static const u8 enc_key031[] __initconst = { ++ 0xf6, 0x0c, 0x6a, 0x1b, 0x62, 0x57, 0x25, 0xf7, ++ 0x6c, 0x70, 0x37, 0xb4, 0x8f, 0xe3, 0x57, 0x7f, ++ 0xa7, 0xf7, 0xb8, 0x7b, 0x1b, 0xd5, 0xa9, 0x82, ++ 0x17, 0x6d, 0x18, 0x23, 0x06, 0xff, 0xb8, 0x70 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input032[] __initconst = { ++ 0x10, 0xf1, 0xec, 0xf9, 0xc6, 0x05, 0x84, 0x66, ++ 0x5d, 0x9a, 0xe5, 0xef, 0xe2, 0x79, 0xe7, 0xf7, ++ 0x37, 0x7e, 0xea, 0x69, 0x16, 0xd2, 0xb1, 0x11 ++}; ++static const u8 enc_output032[] __initconst = { ++ 0x42, 0xf2, 0x6c, 0x56, 0xcb, 0x4b, 0xe2, 0x1d, ++ 0x9d, 0x8d, 0x0c, 0x80, 0xfc, 0x99, 0xdd, 0xe0, ++ 0x0d, 0x75, 0xf3, 0x80, 0x74, 0xbf, 0xe7, 0x64, ++ 0x54, 0xaa, 0x7e, 0x13, 0xd4, 0x8f, 0xff, 0x7d, ++ 0x75, 0x57, 0x03, 0x94, 0x57, 0x04, 0x0a, 0x3a ++}; ++static const u8 enc_assoc032[] __initconst = { }; ++static const u8 enc_nonce032[] __initconst = { ++ 0xe6, 0xb1, 0xad, 0xf2, 0xfd, 0x58, 0xa8, 0x76, ++ 0x2c, 0x65, 0xf3, 0x1b ++}; ++static const u8 enc_key032[] __initconst = { ++ 0x02, 0x12, 0xa8, 0xde, 0x50, 0x07, 0xed, 0x87, ++ 0xb3, 0x3f, 0x1a, 0x70, 0x90, 0xb6, 0x11, 0x4f, ++ 0x9e, 0x08, 0xce, 0xfd, 0x96, 0x07, 0xf2, 0xc2, ++ 0x76, 0xbd, 0xcf, 0xdb, 0xc5, 0xce, 0x9c, 0xd7 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input033[] __initconst = { ++ 0x92, 0x22, 0xf9, 0x01, 0x8e, 0x54, 0xfd, 0x6d, ++ 0xe1, 0x20, 0x08, 0x06, 0xa9, 0xee, 0x8e, 0x4c, ++ 0xc9, 0x04, 0xd2, 0x9f, 0x25, 0xcb, 0xa1, 0x93 ++}; ++static const u8 enc_output033[] __initconst = { ++ 0x12, 0x30, 0x32, 0x43, 0x7b, 0x4b, 0xfd, 0x69, ++ 0x20, 0xe8, 0xf7, 0xe7, 0xe0, 0x08, 0x7a, 0xe4, ++ 0x88, 0x9e, 0xbe, 0x7a, 0x0a, 0xd0, 0xe9, 0x00, ++ 0x3c, 0xf6, 0x8f, 0x17, 0x95, 0x50, 0xda, 0x63, ++ 0xd3, 0xb9, 0x6c, 0x2d, 0x55, 0x41, 0x18, 0x65 ++}; ++static const u8 enc_assoc033[] __initconst = { ++ 0x3e, 0x8b, 0xc5, 0xad, 0xe1, 0x82, 0xff, 0x08 ++}; ++static const u8 enc_nonce033[] __initconst = { ++ 0x6b, 0x28, 0x2e, 0xbe, 0xcc, 0x54, 0x1b, 0xcd, ++ 0x78, 0x34, 0xed, 0x55 ++}; ++static const u8 enc_key033[] __initconst = { ++ 0xc5, 0xbc, 0x09, 0x56, 0x56, 0x46, 0xe7, 0xed, ++ 0xda, 0x95, 0x4f, 0x1f, 0x73, 0x92, 0x23, 0xda, ++ 0xda, 0x20, 0xb9, 0x5c, 0x44, 0xab, 0x03, 0x3d, ++ 0x0f, 0xae, 0x4b, 0x02, 0x83, 0xd1, 0x8b, 0xe3 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input034[] __initconst = { ++ 0xb0, 0x53, 0x99, 0x92, 0x86, 0xa2, 0x82, 0x4f, ++ 0x42, 0xcc, 0x8c, 0x20, 0x3a, 0xb2, 0x4e, 0x2c, ++ 0x97, 0xa6, 0x85, 0xad, 0xcc, 0x2a, 0xd3, 0x26, ++ 0x62, 0x55, 0x8e, 0x55, 0xa5, 0xc7, 0x29 ++}; ++static const u8 enc_output034[] __initconst = { ++ 0x45, 0xc7, 0xd6, 0xb5, 0x3a, 0xca, 0xd4, 0xab, ++ 0xb6, 0x88, 0x76, 0xa6, 0xe9, 0x6a, 0x48, 0xfb, ++ 0x59, 0x52, 0x4d, 0x2c, 0x92, 0xc9, 0xd8, 0xa1, ++ 0x89, 0xc9, 0xfd, 0x2d, 0xb9, 0x17, 0x46, 0x56, ++ 0x6d, 0x3c, 0xa1, 0x0e, 0x31, 0x1b, 0x69, 0x5f, ++ 0x3e, 0xae, 0x15, 0x51, 0x65, 0x24, 0x93 ++}; ++static const u8 enc_assoc034[] __initconst = { }; ++static const u8 enc_nonce034[] __initconst = { ++ 0x04, 0xa9, 0xbe, 0x03, 0x50, 0x8a, 0x5f, 0x31, ++ 0x37, 0x1a, 0x6f, 0xd2 ++}; ++static const u8 enc_key034[] __initconst = { ++ 0x2e, 0xb5, 0x1c, 0x46, 0x9a, 0xa8, 0xeb, 0x9e, ++ 0x6c, 0x54, 0xa8, 0x34, 0x9b, 0xae, 0x50, 0xa2, ++ 0x0f, 0x0e, 0x38, 0x27, 0x11, 0xbb, 0xa1, 0x15, ++ 0x2c, 0x42, 0x4f, 0x03, 0xb6, 0x67, 0x1d, 0x71 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input035[] __initconst = { ++ 0xf4, 0x52, 0x06, 0xab, 0xc2, 0x55, 0x52, 0xb2, ++ 0xab, 0xc9, 0xab, 0x7f, 0xa2, 0x43, 0x03, 0x5f, ++ 0xed, 0xaa, 0xdd, 0xc3, 0xb2, 0x29, 0x39, 0x56, ++ 0xf1, 0xea, 0x6e, 0x71, 0x56, 0xe7, 0xeb ++}; ++static const u8 enc_output035[] __initconst = { ++ 0x46, 0xa8, 0x0c, 0x41, 0x87, 0x02, 0x47, 0x20, ++ 0x08, 0x46, 0x27, 0x58, 0x00, 0x80, 0xdd, 0xe5, ++ 0xa3, 0xf4, 0xa1, 0x10, 0x93, 0xa7, 0x07, 0x6e, ++ 0xd6, 0xf3, 0xd3, 0x26, 0xbc, 0x7b, 0x70, 0x53, ++ 0x4d, 0x4a, 0xa2, 0x83, 0x5a, 0x52, 0xe7, 0x2d, ++ 0x14, 0xdf, 0x0e, 0x4f, 0x47, 0xf2, 0x5f ++}; ++static const u8 enc_assoc035[] __initconst = { ++ 0x37, 0x46, 0x18, 0xa0, 0x6e, 0xa9, 0x8a, 0x48 ++}; ++static const u8 enc_nonce035[] __initconst = { ++ 0x47, 0x0a, 0x33, 0x9e, 0xcb, 0x32, 0x19, 0xb8, ++ 0xb8, 0x1a, 0x1f, 0x8b ++}; ++static const u8 enc_key035[] __initconst = { ++ 0x7f, 0x5b, 0x74, 0xc0, 0x7e, 0xd1, 0xb4, 0x0f, ++ 0xd1, 0x43, 0x58, 0xfe, 0x2f, 0xf2, 0xa7, 0x40, ++ 0xc1, 0x16, 0xc7, 0x70, 0x65, 0x10, 0xe6, 0xa4, ++ 0x37, 0xf1, 0x9e, 0xa4, 0x99, 0x11, 0xce, 0xc4 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input036[] __initconst = { ++ 0xb9, 0xc5, 0x54, 0xcb, 0xc3, 0x6a, 0xc1, 0x8a, ++ 0xe8, 0x97, 0xdf, 0x7b, 0xee, 0xca, 0xc1, 0xdb, ++ 0xeb, 0x4e, 0xaf, 0xa1, 0x56, 0xbb, 0x60, 0xce, ++ 0x2e, 0x5d, 0x48, 0xf0, 0x57, 0x15, 0xe6, 0x78 ++}; ++static const u8 enc_output036[] __initconst = { ++ 0xea, 0x29, 0xaf, 0xa4, 0x9d, 0x36, 0xe8, 0x76, ++ 0x0f, 0x5f, 0xe1, 0x97, 0x23, 0xb9, 0x81, 0x1e, ++ 0xd5, 0xd5, 0x19, 0x93, 0x4a, 0x44, 0x0f, 0x50, ++ 0x81, 0xac, 0x43, 0x0b, 0x95, 0x3b, 0x0e, 0x21, ++ 0x22, 0x25, 0x41, 0xaf, 0x46, 0xb8, 0x65, 0x33, ++ 0xc6, 0xb6, 0x8d, 0x2f, 0xf1, 0x08, 0xa7, 0xea ++}; ++static const u8 enc_assoc036[] __initconst = { }; ++static const u8 enc_nonce036[] __initconst = { ++ 0x72, 0xcf, 0xd9, 0x0e, 0xf3, 0x02, 0x6c, 0xa2, ++ 0x2b, 0x7e, 0x6e, 0x6a ++}; ++static const u8 enc_key036[] __initconst = { ++ 0xe1, 0x73, 0x1d, 0x58, 0x54, 0xe1, 0xb7, 0x0c, ++ 0xb3, 0xff, 0xe8, 0xb7, 0x86, 0xa2, 0xb3, 0xeb, ++ 0xf0, 0x99, 0x43, 0x70, 0x95, 0x47, 0x57, 0xb9, ++ 0xdc, 0x8c, 0x7b, 0xc5, 0x35, 0x46, 0x34, 0xa3 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input037[] __initconst = { ++ 0x6b, 0x26, 0x04, 0x99, 0x6c, 0xd3, 0x0c, 0x14, ++ 0xa1, 0x3a, 0x52, 0x57, 0xed, 0x6c, 0xff, 0xd3, ++ 0xbc, 0x5e, 0x29, 0xd6, 0xb9, 0x7e, 0xb1, 0x79, ++ 0x9e, 0xb3, 0x35, 0xe2, 0x81, 0xea, 0x45, 0x1e ++}; ++static const u8 enc_output037[] __initconst = { ++ 0x6d, 0xad, 0x63, 0x78, 0x97, 0x54, 0x4d, 0x8b, ++ 0xf6, 0xbe, 0x95, 0x07, 0xed, 0x4d, 0x1b, 0xb2, ++ 0xe9, 0x54, 0xbc, 0x42, 0x7e, 0x5d, 0xe7, 0x29, ++ 0xda, 0xf5, 0x07, 0x62, 0x84, 0x6f, 0xf2, 0xf4, ++ 0x7b, 0x99, 0x7d, 0x93, 0xc9, 0x82, 0x18, 0x9d, ++ 0x70, 0x95, 0xdc, 0x79, 0x4c, 0x74, 0x62, 0x32 ++}; ++static const u8 enc_assoc037[] __initconst = { ++ 0x23, 0x33, 0xe5, 0xce, 0x0f, 0x93, 0xb0, 0x59 ++}; ++static const u8 enc_nonce037[] __initconst = { ++ 0x26, 0x28, 0x80, 0xd4, 0x75, 0xf3, 0xda, 0xc5, ++ 0x34, 0x0d, 0xd1, 0xb8 ++}; ++static const u8 enc_key037[] __initconst = { ++ 0x27, 0xd8, 0x60, 0x63, 0x1b, 0x04, 0x85, 0xa4, ++ 0x10, 0x70, 0x2f, 0xea, 0x61, 0xbc, 0x87, 0x3f, ++ 0x34, 0x42, 0x26, 0x0c, 0xad, 0xed, 0x4a, 0xbd, ++ 0xe2, 0x5b, 0x78, 0x6a, 0x2d, 0x97, 0xf1, 0x45 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input038[] __initconst = { ++ 0x97, 0x3d, 0x0c, 0x75, 0x38, 0x26, 0xba, 0xe4, ++ 0x66, 0xcf, 0x9a, 0xbb, 0x34, 0x93, 0x15, 0x2e, ++ 0x9d, 0xe7, 0x81, 0x9e, 0x2b, 0xd0, 0xc7, 0x11, ++ 0x71, 0x34, 0x6b, 0x4d, 0x2c, 0xeb, 0xf8, 0x04, ++ 0x1a, 0xa3, 0xce, 0xdc, 0x0d, 0xfd, 0x7b, 0x46, ++ 0x7e, 0x26, 0x22, 0x8b, 0xc8, 0x6c, 0x9a ++}; ++static const u8 enc_output038[] __initconst = { ++ 0xfb, 0xa7, 0x8a, 0xe4, 0xf9, 0xd8, 0x08, 0xa6, ++ 0x2e, 0x3d, 0xa4, 0x0b, 0xe2, 0xcb, 0x77, 0x00, ++ 0xc3, 0x61, 0x3d, 0x9e, 0xb2, 0xc5, 0x29, 0xc6, ++ 0x52, 0xe7, 0x6a, 0x43, 0x2c, 0x65, 0x8d, 0x27, ++ 0x09, 0x5f, 0x0e, 0xb8, 0xf9, 0x40, 0xc3, 0x24, ++ 0x98, 0x1e, 0xa9, 0x35, 0xe5, 0x07, 0xf9, 0x8f, ++ 0x04, 0x69, 0x56, 0xdb, 0x3a, 0x51, 0x29, 0x08, ++ 0xbd, 0x7a, 0xfc, 0x8f, 0x2a, 0xb0, 0xa9 ++}; ++static const u8 enc_assoc038[] __initconst = { }; ++static const u8 enc_nonce038[] __initconst = { ++ 0xe7, 0x4a, 0x51, 0x5e, 0x7e, 0x21, 0x02, 0xb9, ++ 0x0b, 0xef, 0x55, 0xd2 ++}; ++static const u8 enc_key038[] __initconst = { ++ 0xcf, 0x0d, 0x40, 0xa4, 0x64, 0x4e, 0x5f, 0x51, ++ 0x81, 0x51, 0x65, 0xd5, 0x30, 0x1b, 0x22, 0x63, ++ 0x1f, 0x45, 0x44, 0xc4, 0x9a, 0x18, 0x78, 0xe3, ++ 0xa0, 0xa5, 0xe8, 0xe1, 0xaa, 0xe0, 0xf2, 0x64 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input039[] __initconst = { ++ 0xa9, 0x89, 0x95, 0x50, 0x4d, 0xf1, 0x6f, 0x74, ++ 0x8b, 0xfb, 0x77, 0x85, 0xff, 0x91, 0xee, 0xb3, ++ 0xb6, 0x60, 0xea, 0x9e, 0xd3, 0x45, 0x0c, 0x3d, ++ 0x5e, 0x7b, 0x0e, 0x79, 0xef, 0x65, 0x36, 0x59, ++ 0xa9, 0x97, 0x8d, 0x75, 0x54, 0x2e, 0xf9, 0x1c, ++ 0x45, 0x67, 0x62, 0x21, 0x56, 0x40, 0xb9 ++}; ++static const u8 enc_output039[] __initconst = { ++ 0xa1, 0xff, 0xed, 0x80, 0x76, 0x18, 0x29, 0xec, ++ 0xce, 0x24, 0x2e, 0x0e, 0x88, 0xb1, 0x38, 0x04, ++ 0x90, 0x16, 0xbc, 0xa0, 0x18, 0xda, 0x2b, 0x6e, ++ 0x19, 0x98, 0x6b, 0x3e, 0x31, 0x8c, 0xae, 0x8d, ++ 0x80, 0x61, 0x98, 0xfb, 0x4c, 0x52, 0x7c, 0xc3, ++ 0x93, 0x50, 0xeb, 0xdd, 0xea, 0xc5, 0x73, 0xc4, ++ 0xcb, 0xf0, 0xbe, 0xfd, 0xa0, 0xb7, 0x02, 0x42, ++ 0xc6, 0x40, 0xd7, 0xcd, 0x02, 0xd7, 0xa3 ++}; ++static const u8 enc_assoc039[] __initconst = { ++ 0xb3, 0xe4, 0x06, 0x46, 0x83, 0xb0, 0x2d, 0x84 ++}; ++static const u8 enc_nonce039[] __initconst = { ++ 0xd4, 0xd8, 0x07, 0x34, 0x16, 0x83, 0x82, 0x5b, ++ 0x31, 0xcd, 0x4d, 0x95 ++}; ++static const u8 enc_key039[] __initconst = { ++ 0x6c, 0xbf, 0xd7, 0x1c, 0x64, 0x5d, 0x18, 0x4c, ++ 0xf5, 0xd2, 0x3c, 0x40, 0x2b, 0xdb, 0x0d, 0x25, ++ 0xec, 0x54, 0x89, 0x8c, 0x8a, 0x02, 0x73, 0xd4, ++ 0x2e, 0xb5, 0xbe, 0x10, 0x9f, 0xdc, 0xb2, 0xac ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input040[] __initconst = { ++ 0xd0, 0x96, 0x80, 0x31, 0x81, 0xbe, 0xef, 0x9e, ++ 0x00, 0x8f, 0xf8, 0x5d, 0x5d, 0xdc, 0x38, 0xdd, ++ 0xac, 0xf0, 0xf0, 0x9e, 0xe5, 0xf7, 0xe0, 0x7f, ++ 0x1e, 0x40, 0x79, 0xcb, 0x64, 0xd0, 0xdc, 0x8f, ++ 0x5e, 0x67, 0x11, 0xcd, 0x49, 0x21, 0xa7, 0x88, ++ 0x7d, 0xe7, 0x6e, 0x26, 0x78, 0xfd, 0xc6, 0x76, ++ 0x18, 0xf1, 0x18, 0x55, 0x86, 0xbf, 0xea, 0x9d, ++ 0x4c, 0x68, 0x5d, 0x50, 0xe4, 0xbb, 0x9a, 0x82 ++}; ++static const u8 enc_output040[] __initconst = { ++ 0x9a, 0x4e, 0xf2, 0x2b, 0x18, 0x16, 0x77, 0xb5, ++ 0x75, 0x5c, 0x08, 0xf7, 0x47, 0xc0, 0xf8, 0xd8, ++ 0xe8, 0xd4, 0xc1, 0x8a, 0x9c, 0xc2, 0x40, 0x5c, ++ 0x12, 0xbb, 0x51, 0xbb, 0x18, 0x72, 0xc8, 0xe8, ++ 0xb8, 0x77, 0x67, 0x8b, 0xec, 0x44, 0x2c, 0xfc, ++ 0xbb, 0x0f, 0xf4, 0x64, 0xa6, 0x4b, 0x74, 0x33, ++ 0x2c, 0xf0, 0x72, 0x89, 0x8c, 0x7e, 0x0e, 0xdd, ++ 0xf6, 0x23, 0x2e, 0xa6, 0xe2, 0x7e, 0xfe, 0x50, ++ 0x9f, 0xf3, 0x42, 0x7a, 0x0f, 0x32, 0xfa, 0x56, ++ 0x6d, 0x9c, 0xa0, 0xa7, 0x8a, 0xef, 0xc0, 0x13 ++}; ++static const u8 enc_assoc040[] __initconst = { }; ++static const u8 enc_nonce040[] __initconst = { ++ 0xd6, 0x10, 0x40, 0xa3, 0x13, 0xed, 0x49, 0x28, ++ 0x23, 0xcc, 0x06, 0x5b ++}; ++static const u8 enc_key040[] __initconst = { ++ 0x5b, 0x1d, 0x10, 0x35, 0xc0, 0xb1, 0x7e, 0xe0, ++ 0xb0, 0x44, 0x47, 0x67, 0xf8, 0x0a, 0x25, 0xb8, ++ 0xc1, 0xb7, 0x41, 0xf4, 0xb5, 0x0a, 0x4d, 0x30, ++ 0x52, 0x22, 0x6b, 0xaa, 0x1c, 0x6f, 0xb7, 0x01 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input041[] __initconst = { ++ 0x94, 0xee, 0x16, 0x6d, 0x6d, 0x6e, 0xcf, 0x88, ++ 0x32, 0x43, 0x71, 0x36, 0xb4, 0xae, 0x80, 0x5d, ++ 0x42, 0x88, 0x64, 0x35, 0x95, 0x86, 0xd9, 0x19, ++ 0x3a, 0x25, 0x01, 0x62, 0x93, 0xed, 0xba, 0x44, ++ 0x3c, 0x58, 0xe0, 0x7e, 0x7b, 0x71, 0x95, 0xec, ++ 0x5b, 0xd8, 0x45, 0x82, 0xa9, 0xd5, 0x6c, 0x8d, ++ 0x4a, 0x10, 0x8c, 0x7d, 0x7c, 0xe3, 0x4e, 0x6c, ++ 0x6f, 0x8e, 0xa1, 0xbe, 0xc0, 0x56, 0x73, 0x17 ++}; ++static const u8 enc_output041[] __initconst = { ++ 0x5f, 0xbb, 0xde, 0xcc, 0x34, 0xbe, 0x20, 0x16, ++ 0x14, 0xf6, 0x36, 0x03, 0x1e, 0xeb, 0x42, 0xf1, ++ 0xca, 0xce, 0x3c, 0x79, 0xa1, 0x2c, 0xff, 0xd8, ++ 0x71, 0xee, 0x8e, 0x73, 0x82, 0x0c, 0x82, 0x97, ++ 0x49, 0xf1, 0xab, 0xb4, 0x29, 0x43, 0x67, 0x84, ++ 0x9f, 0xb6, 0xc2, 0xaa, 0x56, 0xbd, 0xa8, 0xa3, ++ 0x07, 0x8f, 0x72, 0x3d, 0x7c, 0x1c, 0x85, 0x20, ++ 0x24, 0xb0, 0x17, 0xb5, 0x89, 0x73, 0xfb, 0x1e, ++ 0x09, 0x26, 0x3d, 0xa7, 0xb4, 0xcb, 0x92, 0x14, ++ 0x52, 0xf9, 0x7d, 0xca, 0x40, 0xf5, 0x80, 0xec ++}; ++static const u8 enc_assoc041[] __initconst = { ++ 0x71, 0x93, 0xf6, 0x23, 0x66, 0x33, 0x21, 0xa2 ++}; ++static const u8 enc_nonce041[] __initconst = { ++ 0xd3, 0x1c, 0x21, 0xab, 0xa1, 0x75, 0xb7, 0x0d, ++ 0xe4, 0xeb, 0xb1, 0x9c ++}; ++static const u8 enc_key041[] __initconst = { ++ 0x97, 0xd6, 0x35, 0xc4, 0xf4, 0x75, 0x74, 0xd9, ++ 0x99, 0x8a, 0x90, 0x87, 0x5d, 0xa1, 0xd3, 0xa2, ++ 0x84, 0xb7, 0x55, 0xb2, 0xd3, 0x92, 0x97, 0xa5, ++ 0x72, 0x52, 0x35, 0x19, 0x0e, 0x10, 0xa9, 0x7e ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input042[] __initconst = { ++ 0xb4, 0x29, 0xeb, 0x80, 0xfb, 0x8f, 0xe8, 0xba, ++ 0xed, 0xa0, 0xc8, 0x5b, 0x9c, 0x33, 0x34, 0x58, ++ 0xe7, 0xc2, 0x99, 0x2e, 0x55, 0x84, 0x75, 0x06, ++ 0x9d, 0x12, 0xd4, 0x5c, 0x22, 0x21, 0x75, 0x64, ++ 0x12, 0x15, 0x88, 0x03, 0x22, 0x97, 0xef, 0xf5, ++ 0x67, 0x83, 0x74, 0x2a, 0x5f, 0xc2, 0x2d, 0x74, ++ 0x10, 0xff, 0xb2, 0x9d, 0x66, 0x09, 0x86, 0x61, ++ 0xd7, 0x6f, 0x12, 0x6c, 0x3c, 0x27, 0x68, 0x9e, ++ 0x43, 0xb3, 0x72, 0x67, 0xca, 0xc5, 0xa3, 0xa6, ++ 0xd3, 0xab, 0x49, 0xe3, 0x91, 0xda, 0x29, 0xcd, ++ 0x30, 0x54, 0xa5, 0x69, 0x2e, 0x28, 0x07, 0xe4, ++ 0xc3, 0xea, 0x46, 0xc8, 0x76, 0x1d, 0x50, 0xf5, ++ 0x92 ++}; ++static const u8 enc_output042[] __initconst = { ++ 0xd0, 0x10, 0x2f, 0x6c, 0x25, 0x8b, 0xf4, 0x97, ++ 0x42, 0xce, 0xc3, 0x4c, 0xf2, 0xd0, 0xfe, 0xdf, ++ 0x23, 0xd1, 0x05, 0xfb, 0x4c, 0x84, 0xcf, 0x98, ++ 0x51, 0x5e, 0x1b, 0xc9, 0xa6, 0x4f, 0x8a, 0xd5, ++ 0xbe, 0x8f, 0x07, 0x21, 0xbd, 0xe5, 0x06, 0x45, ++ 0xd0, 0x00, 0x83, 0xc3, 0xa2, 0x63, 0xa3, 0x10, ++ 0x53, 0xb7, 0x60, 0x24, 0x5f, 0x52, 0xae, 0x28, ++ 0x66, 0xa5, 0xec, 0x83, 0xb1, 0x9f, 0x61, 0xbe, ++ 0x1d, 0x30, 0xd5, 0xc5, 0xd9, 0xfe, 0xcc, 0x4c, ++ 0xbb, 0xe0, 0x8f, 0xd3, 0x85, 0x81, 0x3a, 0x2a, ++ 0xa3, 0x9a, 0x00, 0xff, 0x9c, 0x10, 0xf7, 0xf2, ++ 0x37, 0x02, 0xad, 0xd1, 0xe4, 0xb2, 0xff, 0xa3, ++ 0x1c, 0x41, 0x86, 0x5f, 0xc7, 0x1d, 0xe1, 0x2b, ++ 0x19, 0x61, 0x21, 0x27, 0xce, 0x49, 0x99, 0x3b, ++ 0xb0 ++}; ++static const u8 enc_assoc042[] __initconst = { }; ++static const u8 enc_nonce042[] __initconst = { ++ 0x17, 0xc8, 0x6a, 0x8a, 0xbb, 0xb7, 0xe0, 0x03, ++ 0xac, 0xde, 0x27, 0x99 ++}; ++static const u8 enc_key042[] __initconst = { ++ 0xfe, 0x6e, 0x55, 0xbd, 0xae, 0xd1, 0xf7, 0x28, ++ 0x4c, 0xa5, 0xfc, 0x0f, 0x8c, 0x5f, 0x2b, 0x8d, ++ 0xf5, 0x6d, 0xc0, 0xf4, 0x9e, 0x8c, 0xa6, 0x6a, ++ 0x41, 0x99, 0x5e, 0x78, 0x33, 0x51, 0xf9, 0x01 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input043[] __initconst = { ++ 0xce, 0xb5, 0x34, 0xce, 0x50, 0xdc, 0x23, 0xff, ++ 0x63, 0x8a, 0xce, 0x3e, 0xf6, 0x3a, 0xb2, 0xcc, ++ 0x29, 0x73, 0xee, 0xad, 0xa8, 0x07, 0x85, 0xfc, ++ 0x16, 0x5d, 0x06, 0xc2, 0xf5, 0x10, 0x0f, 0xf5, ++ 0xe8, 0xab, 0x28, 0x82, 0xc4, 0x75, 0xaf, 0xcd, ++ 0x05, 0xcc, 0xd4, 0x9f, 0x2e, 0x7d, 0x8f, 0x55, ++ 0xef, 0x3a, 0x72, 0xe3, 0xdc, 0x51, 0xd6, 0x85, ++ 0x2b, 0x8e, 0x6b, 0x9e, 0x7a, 0xec, 0xe5, 0x7b, ++ 0xe6, 0x55, 0x6b, 0x0b, 0x6d, 0x94, 0x13, 0xe3, ++ 0x3f, 0xc5, 0xfc, 0x24, 0xa9, 0xa2, 0x05, 0xad, ++ 0x59, 0x57, 0x4b, 0xb3, 0x9d, 0x94, 0x4a, 0x92, ++ 0xdc, 0x47, 0x97, 0x0d, 0x84, 0xa6, 0xad, 0x31, ++ 0x76 ++}; ++static const u8 enc_output043[] __initconst = { ++ 0x75, 0x45, 0x39, 0x1b, 0x51, 0xde, 0x01, 0xd5, ++ 0xc5, 0x3d, 0xfa, 0xca, 0x77, 0x79, 0x09, 0x06, ++ 0x3e, 0x58, 0xed, 0xee, 0x4b, 0xb1, 0x22, 0x7e, ++ 0x71, 0x10, 0xac, 0x4d, 0x26, 0x20, 0xc2, 0xae, ++ 0xc2, 0xf8, 0x48, 0xf5, 0x6d, 0xee, 0xb0, 0x37, ++ 0xa8, 0xdc, 0xed, 0x75, 0xaf, 0xa8, 0xa6, 0xc8, ++ 0x90, 0xe2, 0xde, 0xe4, 0x2f, 0x95, 0x0b, 0xb3, ++ 0x3d, 0x9e, 0x24, 0x24, 0xd0, 0x8a, 0x50, 0x5d, ++ 0x89, 0x95, 0x63, 0x97, 0x3e, 0xd3, 0x88, 0x70, ++ 0xf3, 0xde, 0x6e, 0xe2, 0xad, 0xc7, 0xfe, 0x07, ++ 0x2c, 0x36, 0x6c, 0x14, 0xe2, 0xcf, 0x7c, 0xa6, ++ 0x2f, 0xb3, 0xd3, 0x6b, 0xee, 0x11, 0x68, 0x54, ++ 0x61, 0xb7, 0x0d, 0x44, 0xef, 0x8c, 0x66, 0xc5, ++ 0xc7, 0xbb, 0xf1, 0x0d, 0xca, 0xdd, 0x7f, 0xac, ++ 0xf6 ++}; ++static const u8 enc_assoc043[] __initconst = { ++ 0xa1, 0x1c, 0x40, 0xb6, 0x03, 0x76, 0x73, 0x30 ++}; ++static const u8 enc_nonce043[] __initconst = { ++ 0x46, 0x36, 0x2f, 0x45, 0xd6, 0x37, 0x9e, 0x63, ++ 0xe5, 0x22, 0x94, 0x60 ++}; ++static const u8 enc_key043[] __initconst = { ++ 0xaa, 0xbc, 0x06, 0x34, 0x74, 0xe6, 0x5c, 0x4c, ++ 0x3e, 0x9b, 0xdc, 0x48, 0x0d, 0xea, 0x97, 0xb4, ++ 0x51, 0x10, 0xc8, 0x61, 0x88, 0x46, 0xff, 0x6b, ++ 0x15, 0xbd, 0xd2, 0xa4, 0xa5, 0x68, 0x2c, 0x4e ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input044[] __initconst = { ++ 0xe5, 0xcc, 0xaa, 0x44, 0x1b, 0xc8, 0x14, 0x68, ++ 0x8f, 0x8f, 0x6e, 0x8f, 0x28, 0xb5, 0x00, 0xb2 ++}; ++static const u8 enc_output044[] __initconst = { ++ 0x7e, 0x72, 0xf5, 0xa1, 0x85, 0xaf, 0x16, 0xa6, ++ 0x11, 0x92, 0x1b, 0x43, 0x8f, 0x74, 0x9f, 0x0b, ++ 0x12, 0x42, 0xc6, 0x70, 0x73, 0x23, 0x34, 0x02, ++ 0x9a, 0xdf, 0xe1, 0xc5, 0x00, 0x16, 0x51, 0xe4 ++}; ++static const u8 enc_assoc044[] __initconst = { ++ 0x02 ++}; ++static const u8 enc_nonce044[] __initconst = { ++ 0x87, 0x34, 0x5f, 0x10, 0x55, 0xfd, 0x9e, 0x21, ++ 0x02, 0xd5, 0x06, 0x56 ++}; ++static const u8 enc_key044[] __initconst = { ++ 0x7d, 0x00, 0xb4, 0x80, 0x95, 0xad, 0xfa, 0x32, ++ 0x72, 0x05, 0x06, 0x07, 0xb2, 0x64, 0x18, 0x50, ++ 0x02, 0xba, 0x99, 0x95, 0x7c, 0x49, 0x8b, 0xe0, ++ 0x22, 0x77, 0x0f, 0x2c, 0xe2, 0xf3, 0x14, 0x3c ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input045[] __initconst = { ++ 0x02, 0xcd, 0xe1, 0x68, 0xfb, 0xa3, 0xf5, 0x44, ++ 0xbb, 0xd0, 0x33, 0x2f, 0x7a, 0xde, 0xad, 0xa8 ++}; ++static const u8 enc_output045[] __initconst = { ++ 0x85, 0xf2, 0x9a, 0x71, 0x95, 0x57, 0xcd, 0xd1, ++ 0x4d, 0x1f, 0x8f, 0xff, 0xab, 0x6d, 0x9e, 0x60, ++ 0x73, 0x2c, 0xa3, 0x2b, 0xec, 0xd5, 0x15, 0xa1, ++ 0xed, 0x35, 0x3f, 0x54, 0x2e, 0x99, 0x98, 0x58 ++}; ++static const u8 enc_assoc045[] __initconst = { ++ 0xb6, 0x48 ++}; ++static const u8 enc_nonce045[] __initconst = { ++ 0x87, 0xa3, 0x16, 0x3e, 0xc0, 0x59, 0x8a, 0xd9, ++ 0x5b, 0x3a, 0xa7, 0x13 ++}; ++static const u8 enc_key045[] __initconst = { ++ 0x64, 0x32, 0x71, 0x7f, 0x1d, 0xb8, 0x5e, 0x41, ++ 0xac, 0x78, 0x36, 0xbc, 0xe2, 0x51, 0x85, 0xa0, ++ 0x80, 0xd5, 0x76, 0x2b, 0x9e, 0x2b, 0x18, 0x44, ++ 0x4b, 0x6e, 0xc7, 0x2c, 0x3b, 0xd8, 0xe4, 0xdc ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input046[] __initconst = { ++ 0x16, 0xdd, 0xd2, 0x3f, 0xf5, 0x3f, 0x3d, 0x23, ++ 0xc0, 0x63, 0x34, 0x48, 0x70, 0x40, 0xeb, 0x47 ++}; ++static const u8 enc_output046[] __initconst = { ++ 0xc1, 0xb2, 0x95, 0x93, 0x6d, 0x56, 0xfa, 0xda, ++ 0xc0, 0x3e, 0x5f, 0x74, 0x2b, 0xff, 0x73, 0xa1, ++ 0x39, 0xc4, 0x57, 0xdb, 0xab, 0x66, 0x38, 0x2b, ++ 0xab, 0xb3, 0xb5, 0x58, 0x00, 0xcd, 0xa5, 0xb8 ++}; ++static const u8 enc_assoc046[] __initconst = { ++ 0xbd, 0x4c, 0xd0, 0x2f, 0xc7, 0x50, 0x2b, 0xbd, ++ 0xbd, 0xf6, 0xc9, 0xa3, 0xcb, 0xe8, 0xf0 ++}; ++static const u8 enc_nonce046[] __initconst = { ++ 0x6f, 0x57, 0x3a, 0xa8, 0x6b, 0xaa, 0x49, 0x2b, ++ 0xa4, 0x65, 0x96, 0xdf ++}; ++static const u8 enc_key046[] __initconst = { ++ 0x8e, 0x34, 0xcf, 0x73, 0xd2, 0x45, 0xa1, 0x08, ++ 0x2a, 0x92, 0x0b, 0x86, 0x36, 0x4e, 0xb8, 0x96, ++ 0xc4, 0x94, 0x64, 0x67, 0xbc, 0xb3, 0xd5, 0x89, ++ 0x29, 0xfc, 0xb3, 0x66, 0x90, 0xe6, 0x39, 0x4f ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input047[] __initconst = { ++ 0x62, 0x3b, 0x78, 0x50, 0xc3, 0x21, 0xe2, 0xcf, ++ 0x0c, 0x6f, 0xbc, 0xc8, 0xdf, 0xd1, 0xaf, 0xf2 ++}; ++static const u8 enc_output047[] __initconst = { ++ 0xc8, 0x4c, 0x9b, 0xb7, 0xc6, 0x1c, 0x1b, 0xcb, ++ 0x17, 0x77, 0x2a, 0x1c, 0x50, 0x0c, 0x50, 0x95, ++ 0xdb, 0xad, 0xf7, 0xa5, 0x13, 0x8c, 0xa0, 0x34, ++ 0x59, 0xa2, 0xcd, 0x65, 0x83, 0x1e, 0x09, 0x2f ++}; ++static const u8 enc_assoc047[] __initconst = { ++ 0x89, 0xcc, 0xe9, 0xfb, 0x47, 0x44, 0x1d, 0x07, ++ 0xe0, 0x24, 0x5a, 0x66, 0xfe, 0x8b, 0x77, 0x8b ++}; ++static const u8 enc_nonce047[] __initconst = { ++ 0x1a, 0x65, 0x18, 0xf0, 0x2e, 0xde, 0x1d, 0xa6, ++ 0x80, 0x92, 0x66, 0xd9 ++}; ++static const u8 enc_key047[] __initconst = { ++ 0xcb, 0x55, 0x75, 0xf5, 0xc7, 0xc4, 0x5c, 0x91, ++ 0xcf, 0x32, 0x0b, 0x13, 0x9f, 0xb5, 0x94, 0x23, ++ 0x75, 0x60, 0xd0, 0xa3, 0xe6, 0xf8, 0x65, 0xa6, ++ 0x7d, 0x4f, 0x63, 0x3f, 0x2c, 0x08, 0xf0, 0x16 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input048[] __initconst = { ++ 0x87, 0xb3, 0xa4, 0xd7, 0xb2, 0x6d, 0x8d, 0x32, ++ 0x03, 0xa0, 0xde, 0x1d, 0x64, 0xef, 0x82, 0xe3 ++}; ++static const u8 enc_output048[] __initconst = { ++ 0x94, 0xbc, 0x80, 0x62, 0x1e, 0xd1, 0xe7, 0x1b, ++ 0x1f, 0xd2, 0xb5, 0xc3, 0xa1, 0x5e, 0x35, 0x68, ++ 0x33, 0x35, 0x11, 0x86, 0x17, 0x96, 0x97, 0x84, ++ 0x01, 0x59, 0x8b, 0x96, 0x37, 0x22, 0xf5, 0xb3 ++}; ++static const u8 enc_assoc048[] __initconst = { ++ 0xd1, 0x9f, 0x2d, 0x98, 0x90, 0x95, 0xf7, 0xab, ++ 0x03, 0xa5, 0xfd, 0xe8, 0x44, 0x16, 0xe0, 0x0c, ++ 0x0e ++}; ++static const u8 enc_nonce048[] __initconst = { ++ 0x56, 0x4d, 0xee, 0x49, 0xab, 0x00, 0xd2, 0x40, ++ 0xfc, 0x10, 0x68, 0xc3 ++}; ++static const u8 enc_key048[] __initconst = { ++ 0xa5, 0x56, 0x9e, 0x72, 0x9a, 0x69, 0xb2, 0x4b, ++ 0xa6, 0xe0, 0xff, 0x15, 0xc4, 0x62, 0x78, 0x97, ++ 0x43, 0x68, 0x24, 0xc9, 0x41, 0xe9, 0xd0, 0x0b, ++ 0x2e, 0x93, 0xfd, 0xdc, 0x4b, 0xa7, 0x76, 0x57 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input049[] __initconst = { ++ 0xe6, 0x01, 0xb3, 0x85, 0x57, 0x79, 0x7d, 0xa2, ++ 0xf8, 0xa4, 0x10, 0x6a, 0x08, 0x9d, 0x1d, 0xa6 ++}; ++static const u8 enc_output049[] __initconst = { ++ 0x29, 0x9b, 0x5d, 0x3f, 0x3d, 0x03, 0xc0, 0x87, ++ 0x20, 0x9a, 0x16, 0xe2, 0x85, 0x14, 0x31, 0x11, ++ 0x4b, 0x45, 0x4e, 0xd1, 0x98, 0xde, 0x11, 0x7e, ++ 0x83, 0xec, 0x49, 0xfa, 0x8d, 0x85, 0x08, 0xd6 ++}; ++static const u8 enc_assoc049[] __initconst = { ++ 0x5e, 0x64, 0x70, 0xfa, 0xcd, 0x99, 0xc1, 0xd8, ++ 0x1e, 0x37, 0xcd, 0x44, 0x01, 0x5f, 0xe1, 0x94, ++ 0x80, 0xa2, 0xa4, 0xd3, 0x35, 0x2a, 0x4f, 0xf5, ++ 0x60, 0xc0, 0x64, 0x0f, 0xdb, 0xda ++}; ++static const u8 enc_nonce049[] __initconst = { ++ 0xdf, 0x87, 0x13, 0xe8, 0x7e, 0xc3, 0xdb, 0xcf, ++ 0xad, 0x14, 0xd5, 0x3e ++}; ++static const u8 enc_key049[] __initconst = { ++ 0x56, 0x20, 0x74, 0x65, 0xb4, 0xe4, 0x8e, 0x6d, ++ 0x04, 0x63, 0x0f, 0x4a, 0x42, 0xf3, 0x5c, 0xfc, ++ 0x16, 0x3a, 0xb2, 0x89, 0xc2, 0x2a, 0x2b, 0x47, ++ 0x84, 0xf6, 0xf9, 0x29, 0x03, 0x30, 0xbe, 0xe0 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input050[] __initconst = { ++ 0xdc, 0x9e, 0x9e, 0xaf, 0x11, 0xe3, 0x14, 0x18, ++ 0x2d, 0xf6, 0xa4, 0xeb, 0xa1, 0x7a, 0xec, 0x9c ++}; ++static const u8 enc_output050[] __initconst = { ++ 0x60, 0x5b, 0xbf, 0x90, 0xae, 0xb9, 0x74, 0xf6, ++ 0x60, 0x2b, 0xc7, 0x78, 0x05, 0x6f, 0x0d, 0xca, ++ 0x38, 0xea, 0x23, 0xd9, 0x90, 0x54, 0xb4, 0x6b, ++ 0x42, 0xff, 0xe0, 0x04, 0x12, 0x9d, 0x22, 0x04 ++}; ++static const u8 enc_assoc050[] __initconst = { ++ 0xba, 0x44, 0x6f, 0x6f, 0x9a, 0x0c, 0xed, 0x22, ++ 0x45, 0x0f, 0xeb, 0x10, 0x73, 0x7d, 0x90, 0x07, ++ 0xfd, 0x69, 0xab, 0xc1, 0x9b, 0x1d, 0x4d, 0x90, ++ 0x49, 0xa5, 0x55, 0x1e, 0x86, 0xec, 0x2b, 0x37 ++}; ++static const u8 enc_nonce050[] __initconst = { ++ 0x8d, 0xf4, 0xb1, 0x5a, 0x88, 0x8c, 0x33, 0x28, ++ 0x6a, 0x7b, 0x76, 0x51 ++}; ++static const u8 enc_key050[] __initconst = { ++ 0x39, 0x37, 0x98, 0x6a, 0xf8, 0x6d, 0xaf, 0xc1, ++ 0xba, 0x0c, 0x46, 0x72, 0xd8, 0xab, 0xc4, 0x6c, ++ 0x20, 0x70, 0x62, 0x68, 0x2d, 0x9c, 0x26, 0x4a, ++ 0xb0, 0x6d, 0x6c, 0x58, 0x07, 0x20, 0x51, 0x30 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input051[] __initconst = { ++ 0x81, 0xce, 0x84, 0xed, 0xe9, 0xb3, 0x58, 0x59, ++ 0xcc, 0x8c, 0x49, 0xa8, 0xf6, 0xbe, 0x7d, 0xc6 ++}; ++static const u8 enc_output051[] __initconst = { ++ 0x7b, 0x7c, 0xe0, 0xd8, 0x24, 0x80, 0x9a, 0x70, ++ 0xde, 0x32, 0x56, 0x2c, 0xcf, 0x2c, 0x2b, 0xbd, ++ 0x15, 0xd4, 0x4a, 0x00, 0xce, 0x0d, 0x19, 0xb4, ++ 0x23, 0x1f, 0x92, 0x1e, 0x22, 0xbc, 0x0a, 0x43 ++}; ++static const u8 enc_assoc051[] __initconst = { ++ 0xd4, 0x1a, 0x82, 0x8d, 0x5e, 0x71, 0x82, 0x92, ++ 0x47, 0x02, 0x19, 0x05, 0x40, 0x2e, 0xa2, 0x57, ++ 0xdc, 0xcb, 0xc3, 0xb8, 0x0f, 0xcd, 0x56, 0x75, ++ 0x05, 0x6b, 0x68, 0xbb, 0x59, 0xe6, 0x2e, 0x88, ++ 0x73 ++}; ++static const u8 enc_nonce051[] __initconst = { ++ 0xbe, 0x40, 0xe5, 0xf1, 0xa1, 0x18, 0x17, 0xa0, ++ 0xa8, 0xfa, 0x89, 0x49 ++}; ++static const u8 enc_key051[] __initconst = { ++ 0x36, 0x37, 0x2a, 0xbc, 0xdb, 0x78, 0xe0, 0x27, ++ 0x96, 0x46, 0xac, 0x3d, 0x17, 0x6b, 0x96, 0x74, ++ 0xe9, 0x15, 0x4e, 0xec, 0xf0, 0xd5, 0x46, 0x9c, ++ 0x65, 0x1e, 0xc7, 0xe1, 0x6b, 0x4c, 0x11, 0x99 ++}; ++ ++/* wycheproof - misc */ ++static const u8 enc_input052[] __initconst = { ++ 0xa6, 0x67, 0x47, 0xc8, 0x9e, 0x85, 0x7a, 0xf3, ++ 0xa1, 0x8e, 0x2c, 0x79, 0x50, 0x00, 0x87, 0xed ++}; ++static const u8 enc_output052[] __initconst = { ++ 0xca, 0x82, 0xbf, 0xf3, 0xe2, 0xf3, 0x10, 0xcc, ++ 0xc9, 0x76, 0x67, 0x2c, 0x44, 0x15, 0xe6, 0x9b, ++ 0x57, 0x63, 0x8c, 0x62, 0xa5, 0xd8, 0x5d, 0xed, ++ 0x77, 0x4f, 0x91, 0x3c, 0x81, 0x3e, 0xa0, 0x32 ++}; ++static const u8 enc_assoc052[] __initconst = { ++ 0x3f, 0x2d, 0xd4, 0x9b, 0xbf, 0x09, 0xd6, 0x9a, ++ 0x78, 0xa3, 0xd8, 0x0e, 0xa2, 0x56, 0x66, 0x14, ++ 0xfc, 0x37, 0x94, 0x74, 0x19, 0x6c, 0x1a, 0xae, ++ 0x84, 0x58, 0x3d, 0xa7, 0x3d, 0x7f, 0xf8, 0x5c, ++ 0x6f, 0x42, 0xca, 0x42, 0x05, 0x6a, 0x97, 0x92, ++ 0xcc, 0x1b, 0x9f, 0xb3, 0xc7, 0xd2, 0x61 ++}; ++static const u8 enc_nonce052[] __initconst = { ++ 0x84, 0xc8, 0x7d, 0xae, 0x4e, 0xee, 0x27, 0x73, ++ 0x0e, 0xc3, 0x5d, 0x12 ++}; ++static const u8 enc_key052[] __initconst = { ++ 0x9f, 0x14, 0x79, 0xed, 0x09, 0x7d, 0x7f, 0xe5, ++ 0x29, 0xc1, 0x1f, 0x2f, 0x5a, 0xdd, 0x9a, 0xaf, ++ 0xf4, 0xa1, 0xca, 0x0b, 0x68, 0x99, 0x7a, 0x2c, ++ 0xb7, 0xf7, 0x97, 0x49, 0xbd, 0x90, 0xaa, 0xf4 ++}; ++ + /* wycheproof - misc */ + static const u8 enc_input053[] __initconst = { + 0x25, 0x6d, 0x40, 0x88, 0x80, 0x94, 0x17, 0x83, +@@ -2760,6 +3859,126 @@ static const u8 enc_key073[] __initconst + }; + + /* wycheproof - checking for int overflows */ ++static const u8 enc_input074[] __initconst = { ++ 0xd4, 0x50, 0x0b, 0xf0, 0x09, 0x49, 0x35, 0x51, ++ 0xc3, 0x80, 0xad, 0xf5, 0x2c, 0x57, 0x3a, 0x69, ++ 0xdf, 0x7e, 0x8b, 0x76, 0x24, 0x63, 0x33, 0x0f, ++ 0xac, 0xc1, 0x6a, 0x57, 0x26, 0xbe, 0x71, 0x90, ++ 0xc6, 0x3c, 0x5a, 0x1c, 0x92, 0x65, 0x84, 0xa0, ++ 0x96, 0x75, 0x68, 0x28, 0xdc, 0xdc, 0x64, 0xac, ++ 0xdf, 0x96, 0x3d, 0x93, 0x1b, 0xf1, 0xda, 0xe2, ++ 0x38, 0xf3, 0xf1, 0x57, 0x22, 0x4a, 0xc4, 0xb5, ++ 0x42, 0xd7, 0x85, 0xb0, 0xdd, 0x84, 0xdb, 0x6b, ++ 0xe3, 0xbc, 0x5a, 0x36, 0x63, 0xe8, 0x41, 0x49, ++ 0xff, 0xbe, 0xd0, 0x9e, 0x54, 0xf7, 0x8f, 0x16, ++ 0xa8, 0x22, 0x3b, 0x24, 0xcb, 0x01, 0x9f, 0x58, ++ 0xb2, 0x1b, 0x0e, 0x55, 0x1e, 0x7a, 0xa0, 0x73, ++ 0x27, 0x62, 0x95, 0x51, 0x37, 0x6c, 0xcb, 0xc3, ++ 0x93, 0x76, 0x71, 0xa0, 0x62, 0x9b, 0xd9, 0x5c, ++ 0x99, 0x15, 0xc7, 0x85, 0x55, 0x77, 0x1e, 0x7a ++}; ++static const u8 enc_output074[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x0b, 0x30, 0x0d, 0x8d, 0xa5, 0x6c, 0x21, 0x85, ++ 0x75, 0x52, 0x79, 0x55, 0x3c, 0x4c, 0x82, 0xca ++}; ++static const u8 enc_assoc074[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce074[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x00, 0x02, 0x50, 0x6e ++}; ++static const u8 enc_key074[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ ++static const u8 enc_input075[] __initconst = { ++ 0x7d, 0xe8, 0x7f, 0x67, 0x29, 0x94, 0x52, 0x75, ++ 0xd0, 0x65, 0x5d, 0xa4, 0xc7, 0xfd, 0xe4, 0x56, ++ 0x9e, 0x16, 0xf1, 0x11, 0xb5, 0xeb, 0x26, 0xc2, ++ 0x2d, 0x85, 0x9e, 0x3f, 0xf8, 0x22, 0xec, 0xed, ++ 0x3a, 0x6d, 0xd9, 0xa6, 0x0f, 0x22, 0x95, 0x7f, ++ 0x7b, 0x7c, 0x85, 0x7e, 0x88, 0x22, 0xeb, 0x9f, ++ 0xe0, 0xb8, 0xd7, 0x02, 0x21, 0x41, 0xf2, 0xd0, ++ 0xb4, 0x8f, 0x4b, 0x56, 0x12, 0xd3, 0x22, 0xa8, ++ 0x8d, 0xd0, 0xfe, 0x0b, 0x4d, 0x91, 0x79, 0x32, ++ 0x4f, 0x7c, 0x6c, 0x9e, 0x99, 0x0e, 0xfb, 0xd8, ++ 0x0e, 0x5e, 0xd6, 0x77, 0x58, 0x26, 0x49, 0x8b, ++ 0x1e, 0xfe, 0x0f, 0x71, 0xa0, 0xf3, 0xec, 0x5b, ++ 0x29, 0xcb, 0x28, 0xc2, 0x54, 0x0a, 0x7d, 0xcd, ++ 0x51, 0xb7, 0xda, 0xae, 0xe0, 0xff, 0x4a, 0x7f, ++ 0x3a, 0xc1, 0xee, 0x54, 0xc2, 0x9e, 0xe4, 0xc1, ++ 0x70, 0xde, 0x40, 0x8f, 0x66, 0x69, 0x21, 0x94 ++}; ++static const u8 enc_output075[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xc5, 0x78, 0xe2, 0xaa, 0x44, 0xd3, 0x09, 0xb7, ++ 0xb6, 0xa5, 0x19, 0x3b, 0xdc, 0x61, 0x18, 0xf5 ++}; ++static const u8 enc_assoc075[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_nonce075[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x00, 0x03, 0x18, 0xa5 ++}; ++static const u8 enc_key075[] __initconst = { ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 ++}; ++ ++/* wycheproof - checking for int overflows */ + static const u8 enc_input076[] __initconst = { + 0x1b, 0x99, 0x6f, 0x9a, 0x3c, 0xcc, 0x67, 0x85, + 0xde, 0x22, 0xff, 0x5b, 0x8a, 0xdd, 0x95, 0x02, +@@ -3349,6 +4568,286 @@ static const u8 enc_key085[] __initconst + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + }; + ++/* wycheproof - special case tag */ ++static const u8 enc_input086[] __initconst = { ++ 0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6, ++ 0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd, ++ 0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b, ++ 0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2, ++ 0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19, ++ 0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4, ++ 0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63, ++ 0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d ++}; ++static const u8 enc_output086[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ++}; ++static const u8 enc_assoc086[] __initconst = { ++ 0x85, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xa6, 0x90, 0x2f, 0xcb, 0xc8, 0x83, 0xbb, 0xc1, ++ 0x80, 0xb2, 0x56, 0xae, 0x34, 0xad, 0x7f, 0x00 ++}; ++static const u8 enc_nonce086[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b ++}; ++static const u8 enc_key086[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - special case tag */ ++static const u8 enc_input087[] __initconst = { ++ 0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6, ++ 0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd, ++ 0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b, ++ 0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2, ++ 0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19, ++ 0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4, ++ 0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63, ++ 0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d ++}; ++static const u8 enc_output087[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_assoc087[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x24, 0x7e, 0x50, 0x64, 0x2a, 0x1c, 0x0a, 0x2f, ++ 0x8f, 0x77, 0x21, 0x96, 0x09, 0xdb, 0xa9, 0x58 ++}; ++static const u8 enc_nonce087[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b ++}; ++static const u8 enc_key087[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - special case tag */ ++static const u8 enc_input088[] __initconst = { ++ 0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6, ++ 0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd, ++ 0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b, ++ 0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2, ++ 0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19, ++ 0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4, ++ 0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63, ++ 0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d ++}; ++static const u8 enc_output088[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static const u8 enc_assoc088[] __initconst = { ++ 0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xd9, 0xe7, 0x2c, 0x06, 0x4a, 0xc8, 0x96, 0x1f, ++ 0x3f, 0xa5, 0x85, 0xe0, 0xe2, 0xab, 0xd6, 0x00 ++}; ++static const u8 enc_nonce088[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b ++}; ++static const u8 enc_key088[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - special case tag */ ++static const u8 enc_input089[] __initconst = { ++ 0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6, ++ 0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd, ++ 0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b, ++ 0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2, ++ 0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19, ++ 0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4, ++ 0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63, ++ 0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d ++}; ++static const u8 enc_output089[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 ++}; ++static const u8 enc_assoc089[] __initconst = { ++ 0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x95, 0xaf, 0x0f, 0x4d, 0x0b, 0x68, 0x6e, 0xae, ++ 0xcc, 0xca, 0x43, 0x07, 0xd5, 0x96, 0xf5, 0x02 ++}; ++static const u8 enc_nonce089[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b ++}; ++static const u8 enc_key089[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - special case tag */ ++static const u8 enc_input090[] __initconst = { ++ 0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6, ++ 0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd, ++ 0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b, ++ 0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2, ++ 0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19, ++ 0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4, ++ 0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63, ++ 0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d ++}; ++static const u8 enc_output090[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, ++ 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f ++}; ++static const u8 enc_assoc090[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x85, 0x40, 0xb4, 0x64, 0x35, 0x77, 0x07, 0xbe, ++ 0x3a, 0x39, 0xd5, 0x5c, 0x34, 0xf8, 0xbc, 0xb3 ++}; ++static const u8 enc_nonce090[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b ++}; ++static const u8 enc_key090[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - special case tag */ ++static const u8 enc_input091[] __initconst = { ++ 0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6, ++ 0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd, ++ 0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b, ++ 0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2, ++ 0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19, ++ 0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4, ++ 0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63, ++ 0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d ++}; ++static const u8 enc_output091[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_assoc091[] __initconst = { ++ 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x66, 0x23, 0xd9, 0x90, 0xb8, 0x98, 0xd8, 0x30, ++ 0xd2, 0x12, 0xaf, 0x23, 0x83, 0x33, 0x07, 0x01 ++}; ++static const u8 enc_nonce091[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b ++}; ++static const u8 enc_key091[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ ++/* wycheproof - special case tag */ ++static const u8 enc_input092[] __initconst = { ++ 0x9a, 0x49, 0xc4, 0x0f, 0x8b, 0x48, 0xd7, 0xc6, ++ 0x6d, 0x1d, 0xb4, 0xe5, 0x3f, 0x20, 0xf2, 0xdd, ++ 0x4a, 0xaa, 0x24, 0x1d, 0xda, 0xb2, 0x6b, 0x5b, ++ 0xc0, 0xe2, 0x18, 0xb7, 0x2c, 0x33, 0x90, 0xf2, ++ 0xdf, 0x3e, 0xbd, 0x01, 0x76, 0x70, 0x44, 0x19, ++ 0x97, 0x2b, 0xcd, 0xbc, 0x6b, 0xbc, 0xb3, 0xe4, ++ 0xe7, 0x4a, 0x71, 0x52, 0x8e, 0xf5, 0x12, 0x63, ++ 0xce, 0x24, 0xe0, 0xd5, 0x75, 0xe0, 0xe4, 0x4d ++}; ++static const u8 enc_output092[] __initconst = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++}; ++static const u8 enc_assoc092[] __initconst = { ++ 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0x5f, 0x16, 0xd0, 0x9f, 0x17, 0x78, 0x72, 0x11, ++ 0xb7, 0xd4, 0x84, 0xe0, 0x24, 0xf8, 0x97, 0x01 ++}; ++static const u8 enc_nonce092[] __initconst = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b ++}; ++static const u8 enc_key092[] __initconst = { ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f ++}; ++ + /* wycheproof - edge case intermediate sums in poly1305 */ + static const u8 enc_input093[] __initconst = { + 0x00, 0x52, 0x35, 0xd2, 0xa9, 0x19, 0xf2, 0x8d, +@@ -4455,6 +5954,86 @@ chacha20poly1305_enc_vectors[] __initcon + sizeof(enc_input011), sizeof(enc_assoc011), sizeof(enc_nonce011) }, + { enc_input012, enc_output012, enc_assoc012, enc_nonce012, enc_key012, + sizeof(enc_input012), sizeof(enc_assoc012), sizeof(enc_nonce012) }, ++ { enc_input013, enc_output013, enc_assoc013, enc_nonce013, enc_key013, ++ sizeof(enc_input013), sizeof(enc_assoc013), sizeof(enc_nonce013) }, ++ { enc_input014, enc_output014, enc_assoc014, enc_nonce014, enc_key014, ++ sizeof(enc_input014), sizeof(enc_assoc014), sizeof(enc_nonce014) }, ++ { enc_input015, enc_output015, enc_assoc015, enc_nonce015, enc_key015, ++ sizeof(enc_input015), sizeof(enc_assoc015), sizeof(enc_nonce015) }, ++ { enc_input016, enc_output016, enc_assoc016, enc_nonce016, enc_key016, ++ sizeof(enc_input016), sizeof(enc_assoc016), sizeof(enc_nonce016) }, ++ { enc_input017, enc_output017, enc_assoc017, enc_nonce017, enc_key017, ++ sizeof(enc_input017), sizeof(enc_assoc017), sizeof(enc_nonce017) }, ++ { enc_input018, enc_output018, enc_assoc018, enc_nonce018, enc_key018, ++ sizeof(enc_input018), sizeof(enc_assoc018), sizeof(enc_nonce018) }, ++ { enc_input019, enc_output019, enc_assoc019, enc_nonce019, enc_key019, ++ sizeof(enc_input019), sizeof(enc_assoc019), sizeof(enc_nonce019) }, ++ { enc_input020, enc_output020, enc_assoc020, enc_nonce020, enc_key020, ++ sizeof(enc_input020), sizeof(enc_assoc020), sizeof(enc_nonce020) }, ++ { enc_input021, enc_output021, enc_assoc021, enc_nonce021, enc_key021, ++ sizeof(enc_input021), sizeof(enc_assoc021), sizeof(enc_nonce021) }, ++ { enc_input022, enc_output022, enc_assoc022, enc_nonce022, enc_key022, ++ sizeof(enc_input022), sizeof(enc_assoc022), sizeof(enc_nonce022) }, ++ { enc_input023, enc_output023, enc_assoc023, enc_nonce023, enc_key023, ++ sizeof(enc_input023), sizeof(enc_assoc023), sizeof(enc_nonce023) }, ++ { enc_input024, enc_output024, enc_assoc024, enc_nonce024, enc_key024, ++ sizeof(enc_input024), sizeof(enc_assoc024), sizeof(enc_nonce024) }, ++ { enc_input025, enc_output025, enc_assoc025, enc_nonce025, enc_key025, ++ sizeof(enc_input025), sizeof(enc_assoc025), sizeof(enc_nonce025) }, ++ { enc_input026, enc_output026, enc_assoc026, enc_nonce026, enc_key026, ++ sizeof(enc_input026), sizeof(enc_assoc026), sizeof(enc_nonce026) }, ++ { enc_input027, enc_output027, enc_assoc027, enc_nonce027, enc_key027, ++ sizeof(enc_input027), sizeof(enc_assoc027), sizeof(enc_nonce027) }, ++ { enc_input028, enc_output028, enc_assoc028, enc_nonce028, enc_key028, ++ sizeof(enc_input028), sizeof(enc_assoc028), sizeof(enc_nonce028) }, ++ { enc_input029, enc_output029, enc_assoc029, enc_nonce029, enc_key029, ++ sizeof(enc_input029), sizeof(enc_assoc029), sizeof(enc_nonce029) }, ++ { enc_input030, enc_output030, enc_assoc030, enc_nonce030, enc_key030, ++ sizeof(enc_input030), sizeof(enc_assoc030), sizeof(enc_nonce030) }, ++ { enc_input031, enc_output031, enc_assoc031, enc_nonce031, enc_key031, ++ sizeof(enc_input031), sizeof(enc_assoc031), sizeof(enc_nonce031) }, ++ { enc_input032, enc_output032, enc_assoc032, enc_nonce032, enc_key032, ++ sizeof(enc_input032), sizeof(enc_assoc032), sizeof(enc_nonce032) }, ++ { enc_input033, enc_output033, enc_assoc033, enc_nonce033, enc_key033, ++ sizeof(enc_input033), sizeof(enc_assoc033), sizeof(enc_nonce033) }, ++ { enc_input034, enc_output034, enc_assoc034, enc_nonce034, enc_key034, ++ sizeof(enc_input034), sizeof(enc_assoc034), sizeof(enc_nonce034) }, ++ { enc_input035, enc_output035, enc_assoc035, enc_nonce035, enc_key035, ++ sizeof(enc_input035), sizeof(enc_assoc035), sizeof(enc_nonce035) }, ++ { enc_input036, enc_output036, enc_assoc036, enc_nonce036, enc_key036, ++ sizeof(enc_input036), sizeof(enc_assoc036), sizeof(enc_nonce036) }, ++ { enc_input037, enc_output037, enc_assoc037, enc_nonce037, enc_key037, ++ sizeof(enc_input037), sizeof(enc_assoc037), sizeof(enc_nonce037) }, ++ { enc_input038, enc_output038, enc_assoc038, enc_nonce038, enc_key038, ++ sizeof(enc_input038), sizeof(enc_assoc038), sizeof(enc_nonce038) }, ++ { enc_input039, enc_output039, enc_assoc039, enc_nonce039, enc_key039, ++ sizeof(enc_input039), sizeof(enc_assoc039), sizeof(enc_nonce039) }, ++ { enc_input040, enc_output040, enc_assoc040, enc_nonce040, enc_key040, ++ sizeof(enc_input040), sizeof(enc_assoc040), sizeof(enc_nonce040) }, ++ { enc_input041, enc_output041, enc_assoc041, enc_nonce041, enc_key041, ++ sizeof(enc_input041), sizeof(enc_assoc041), sizeof(enc_nonce041) }, ++ { enc_input042, enc_output042, enc_assoc042, enc_nonce042, enc_key042, ++ sizeof(enc_input042), sizeof(enc_assoc042), sizeof(enc_nonce042) }, ++ { enc_input043, enc_output043, enc_assoc043, enc_nonce043, enc_key043, ++ sizeof(enc_input043), sizeof(enc_assoc043), sizeof(enc_nonce043) }, ++ { enc_input044, enc_output044, enc_assoc044, enc_nonce044, enc_key044, ++ sizeof(enc_input044), sizeof(enc_assoc044), sizeof(enc_nonce044) }, ++ { enc_input045, enc_output045, enc_assoc045, enc_nonce045, enc_key045, ++ sizeof(enc_input045), sizeof(enc_assoc045), sizeof(enc_nonce045) }, ++ { enc_input046, enc_output046, enc_assoc046, enc_nonce046, enc_key046, ++ sizeof(enc_input046), sizeof(enc_assoc046), sizeof(enc_nonce046) }, ++ { enc_input047, enc_output047, enc_assoc047, enc_nonce047, enc_key047, ++ sizeof(enc_input047), sizeof(enc_assoc047), sizeof(enc_nonce047) }, ++ { enc_input048, enc_output048, enc_assoc048, enc_nonce048, enc_key048, ++ sizeof(enc_input048), sizeof(enc_assoc048), sizeof(enc_nonce048) }, ++ { enc_input049, enc_output049, enc_assoc049, enc_nonce049, enc_key049, ++ sizeof(enc_input049), sizeof(enc_assoc049), sizeof(enc_nonce049) }, ++ { enc_input050, enc_output050, enc_assoc050, enc_nonce050, enc_key050, ++ sizeof(enc_input050), sizeof(enc_assoc050), sizeof(enc_nonce050) }, ++ { enc_input051, enc_output051, enc_assoc051, enc_nonce051, enc_key051, ++ sizeof(enc_input051), sizeof(enc_assoc051), sizeof(enc_nonce051) }, ++ { enc_input052, enc_output052, enc_assoc052, enc_nonce052, enc_key052, ++ sizeof(enc_input052), sizeof(enc_assoc052), sizeof(enc_nonce052) }, + { enc_input053, enc_output053, enc_assoc053, enc_nonce053, enc_key053, + sizeof(enc_input053), sizeof(enc_assoc053), sizeof(enc_nonce053) }, + { enc_input054, enc_output054, enc_assoc054, enc_nonce054, enc_key054, +@@ -4497,6 +6076,10 @@ chacha20poly1305_enc_vectors[] __initcon + sizeof(enc_input072), sizeof(enc_assoc072), sizeof(enc_nonce072) }, + { enc_input073, enc_output073, enc_assoc073, enc_nonce073, enc_key073, + sizeof(enc_input073), sizeof(enc_assoc073), sizeof(enc_nonce073) }, ++ { enc_input074, enc_output074, enc_assoc074, enc_nonce074, enc_key074, ++ sizeof(enc_input074), sizeof(enc_assoc074), sizeof(enc_nonce074) }, ++ { enc_input075, enc_output075, enc_assoc075, enc_nonce075, enc_key075, ++ sizeof(enc_input075), sizeof(enc_assoc075), sizeof(enc_nonce075) }, + { enc_input076, enc_output076, enc_assoc076, enc_nonce076, enc_key076, + sizeof(enc_input076), sizeof(enc_assoc076), sizeof(enc_nonce076) }, + { enc_input077, enc_output077, enc_assoc077, enc_nonce077, enc_key077, +@@ -4517,6 +6100,20 @@ chacha20poly1305_enc_vectors[] __initcon + sizeof(enc_input084), sizeof(enc_assoc084), sizeof(enc_nonce084) }, + { enc_input085, enc_output085, enc_assoc085, enc_nonce085, enc_key085, + sizeof(enc_input085), sizeof(enc_assoc085), sizeof(enc_nonce085) }, ++ { enc_input086, enc_output086, enc_assoc086, enc_nonce086, enc_key086, ++ sizeof(enc_input086), sizeof(enc_assoc086), sizeof(enc_nonce086) }, ++ { enc_input087, enc_output087, enc_assoc087, enc_nonce087, enc_key087, ++ sizeof(enc_input087), sizeof(enc_assoc087), sizeof(enc_nonce087) }, ++ { enc_input088, enc_output088, enc_assoc088, enc_nonce088, enc_key088, ++ sizeof(enc_input088), sizeof(enc_assoc088), sizeof(enc_nonce088) }, ++ { enc_input089, enc_output089, enc_assoc089, enc_nonce089, enc_key089, ++ sizeof(enc_input089), sizeof(enc_assoc089), sizeof(enc_nonce089) }, ++ { enc_input090, enc_output090, enc_assoc090, enc_nonce090, enc_key090, ++ sizeof(enc_input090), sizeof(enc_assoc090), sizeof(enc_nonce090) }, ++ { enc_input091, enc_output091, enc_assoc091, enc_nonce091, enc_key091, ++ sizeof(enc_input091), sizeof(enc_assoc091), sizeof(enc_nonce091) }, ++ { enc_input092, enc_output092, enc_assoc092, enc_nonce092, enc_key092, ++ sizeof(enc_input092), sizeof(enc_assoc092), sizeof(enc_nonce092) }, + { enc_input093, enc_output093, enc_assoc093, enc_nonce093, enc_key093, + sizeof(enc_input093), sizeof(enc_assoc093), sizeof(enc_nonce093) }, + { enc_input094, enc_output094, enc_assoc094, enc_nonce094, enc_key094, +@@ -7224,6 +8821,43 @@ xchacha20poly1305_dec_vectors[] __initco + sizeof(xdec_input001), sizeof(xdec_assoc001), sizeof(xdec_nonce001) } + }; + ++/* This is for the selftests-only, since it is only useful for the purpose of ++ * testing the underlying primitives and interactions. ++ */ ++static void __init ++chacha20poly1305_encrypt_bignonce(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[12], ++ const u8 key[CHACHA20POLY1305_KEY_SIZE]) ++{ ++ const u8 *pad0 = page_address(ZERO_PAGE(0)); ++ struct poly1305_desc_ctx poly1305_state; ++ u32 chacha20_state[CHACHA_STATE_WORDS]; ++ union { ++ u8 block0[POLY1305_KEY_SIZE]; ++ __le64 lens[2]; ++ } b = {{ 0 }}; ++ u8 bottom_row[16] = { 0 }; ++ u32 le_key[8]; ++ int i; ++ ++ memcpy(&bottom_row[4], nonce, 12); ++ for (i = 0; i < 8; ++i) ++ le_key[i] = get_unaligned_le32(key + sizeof(le_key[i]) * i); ++ chacha_init(chacha20_state, le_key, bottom_row); ++ chacha20_crypt(chacha20_state, b.block0, b.block0, sizeof(b.block0)); ++ poly1305_init(&poly1305_state, b.block0); ++ poly1305_update(&poly1305_state, ad, ad_len); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf); ++ chacha20_crypt(chacha20_state, dst, src, src_len); ++ poly1305_update(&poly1305_state, dst, src_len); ++ poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf); ++ b.lens[0] = cpu_to_le64(ad_len); ++ b.lens[1] = cpu_to_le64(src_len); ++ poly1305_update(&poly1305_state, (u8 *)b.lens, sizeof(b.lens)); ++ poly1305_final(&poly1305_state, dst + src_len); ++} ++ + static void __init + chacha20poly1305_selftest_encrypt(u8 *dst, const u8 *src, const size_t src_len, + const u8 *ad, const size_t ad_len, +@@ -7233,6 +8867,9 @@ chacha20poly1305_selftest_encrypt(u8 *ds + if (nonce_len == 8) + chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, + get_unaligned_le64(nonce), key); ++ else if (nonce_len == 12) ++ chacha20poly1305_encrypt_bignonce(dst, src, src_len, ad, ++ ad_len, nonce, key); + else + BUG(); + } +@@ -7248,14 +8885,14 @@ decryption_success(bool func_ret, bool e + bool __init chacha20poly1305_selftest(void) + { + enum { MAXIMUM_TEST_BUFFER_LEN = 1UL << 12 }; +- size_t i; +- u8 *computed_output = NULL, *heap_src = NULL; +- struct scatterlist sg_src; ++ size_t i, j, k, total_len; ++ u8 *computed_output = NULL, *input = NULL; + bool success = true, ret; ++ struct scatterlist sg_src[3]; + +- heap_src = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL); + computed_output = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL); +- if (!heap_src || !computed_output) { ++ input = kmalloc(MAXIMUM_TEST_BUFFER_LEN, GFP_KERNEL); ++ if (!computed_output || !input) { + pr_err("chacha20poly1305 self-test malloc: FAIL\n"); + success = false; + goto out; +@@ -7284,17 +8921,17 @@ bool __init chacha20poly1305_selftest(vo + for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) { + if (chacha20poly1305_enc_vectors[i].nlen != 8) + continue; +- memcpy(heap_src, chacha20poly1305_enc_vectors[i].input, ++ memcpy(computed_output, chacha20poly1305_enc_vectors[i].input, + chacha20poly1305_enc_vectors[i].ilen); +- sg_init_one(&sg_src, heap_src, ++ sg_init_one(sg_src, computed_output, + chacha20poly1305_enc_vectors[i].ilen + POLY1305_DIGEST_SIZE); +- chacha20poly1305_encrypt_sg_inplace(&sg_src, ++ ret = chacha20poly1305_encrypt_sg_inplace(sg_src, + chacha20poly1305_enc_vectors[i].ilen, + chacha20poly1305_enc_vectors[i].assoc, + chacha20poly1305_enc_vectors[i].alen, + get_unaligned_le64(chacha20poly1305_enc_vectors[i].nonce), + chacha20poly1305_enc_vectors[i].key); +- if (memcmp(heap_src, ++ if (!ret || memcmp(computed_output, + chacha20poly1305_enc_vectors[i].output, + chacha20poly1305_enc_vectors[i].ilen + + POLY1305_DIGEST_SIZE)) { +@@ -7326,11 +8963,11 @@ bool __init chacha20poly1305_selftest(vo + } + + for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) { +- memcpy(heap_src, chacha20poly1305_dec_vectors[i].input, ++ memcpy(computed_output, chacha20poly1305_dec_vectors[i].input, + chacha20poly1305_dec_vectors[i].ilen); +- sg_init_one(&sg_src, heap_src, ++ sg_init_one(sg_src, computed_output, + chacha20poly1305_dec_vectors[i].ilen); +- ret = chacha20poly1305_decrypt_sg_inplace(&sg_src, ++ ret = chacha20poly1305_decrypt_sg_inplace(sg_src, + chacha20poly1305_dec_vectors[i].ilen, + chacha20poly1305_dec_vectors[i].assoc, + chacha20poly1305_dec_vectors[i].alen, +@@ -7338,7 +8975,7 @@ bool __init chacha20poly1305_selftest(vo + chacha20poly1305_dec_vectors[i].key); + if (!decryption_success(ret, + chacha20poly1305_dec_vectors[i].failure, +- memcmp(heap_src, chacha20poly1305_dec_vectors[i].output, ++ memcmp(computed_output, chacha20poly1305_dec_vectors[i].output, + chacha20poly1305_dec_vectors[i].ilen - + POLY1305_DIGEST_SIZE))) { + pr_err("chacha20poly1305 sg decryption self-test %zu: FAIL\n", +@@ -7365,6 +9002,7 @@ bool __init chacha20poly1305_selftest(vo + success = false; + } + } ++ + for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_dec_vectors); ++i) { + memset(computed_output, 0, MAXIMUM_TEST_BUFFER_LEN); + ret = xchacha20poly1305_decrypt(computed_output, +@@ -7386,8 +9024,54 @@ bool __init chacha20poly1305_selftest(vo + } + } + ++ for (total_len = POLY1305_DIGEST_SIZE; IS_ENABLED(DEBUG_CHACHA20POLY1305_SLOW_CHUNK_TEST) ++ && total_len <= 1 << 10; ++total_len) { ++ for (i = 0; i <= total_len; ++i) { ++ for (j = i; j <= total_len; ++j) { ++ sg_init_table(sg_src, 3); ++ sg_set_buf(&sg_src[0], input, i); ++ sg_set_buf(&sg_src[1], input + i, j - i); ++ sg_set_buf(&sg_src[2], input + j, total_len - j); ++ memset(computed_output, 0, total_len); ++ memset(input, 0, total_len); ++ ++ if (!chacha20poly1305_encrypt_sg_inplace(sg_src, ++ total_len - POLY1305_DIGEST_SIZE, NULL, 0, ++ 0, enc_key001)) ++ goto chunkfail; ++ chacha20poly1305_encrypt(computed_output, ++ computed_output, ++ total_len - POLY1305_DIGEST_SIZE, NULL, 0, 0, ++ enc_key001); ++ if (memcmp(computed_output, input, total_len)) ++ goto chunkfail; ++ if (!chacha20poly1305_decrypt(computed_output, ++ input, total_len, NULL, 0, 0, enc_key001)) ++ goto chunkfail; ++ for (k = 0; k < total_len - POLY1305_DIGEST_SIZE; ++k) { ++ if (computed_output[k]) ++ goto chunkfail; ++ } ++ if (!chacha20poly1305_decrypt_sg_inplace(sg_src, ++ total_len, NULL, 0, 0, enc_key001)) ++ goto chunkfail; ++ for (k = 0; k < total_len - POLY1305_DIGEST_SIZE; ++k) { ++ if (input[k]) ++ goto chunkfail; ++ } ++ continue; ++ ++ chunkfail: ++ pr_err("chacha20poly1305 chunked self-test %zu/%zu/%zu: FAIL\n", ++ total_len, i, j); ++ success = false; ++ } ++ ++ } ++ } ++ + out: +- kfree(heap_src); + kfree(computed_output); ++ kfree(input); + return success; + } diff --git a/ipq806x/backport-5.4/080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch b/ipq806x/backport-5.4/080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch new file mode 100644 index 0000000..8209ca2 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0048-crypto-x86-poly1305-emit-does-base-conversion-itself.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 17 Jan 2020 11:42:22 +0100 +Subject: [PATCH] crypto: x86/poly1305 - emit does base conversion itself + +commit f9e7fe32a792726186301423ff63a465d63386e1 upstream. + +The emit code does optional base conversion itself in assembly, so we +don't need to do that here. Also, neither one of these functions uses +simd instructions, so checking for that doesn't make sense either. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305_glue.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -123,13 +123,9 @@ static void poly1305_simd_blocks(void *c + static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], + const u32 nonce[4]) + { +- struct poly1305_arch_internal *state = ctx; +- +- if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) || +- !state->is_base2_26 || !crypto_simd_usable()) { +- convert_to_base2_64(ctx); ++ if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx)) + poly1305_emit_x86_64(ctx, mac, nonce); +- } else ++ else + poly1305_emit_avx(ctx, mac, nonce); + } + diff --git a/ipq806x/backport-5.4/080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch b/ipq806x/backport-5.4/080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch new file mode 100644 index 0000000..354f584 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0049-crypto-arm-chacha-fix-build-failured-when-kernel-mod.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 17 Jan 2020 17:43:18 +0100 +Subject: [PATCH] crypto: arm/chacha - fix build failured when kernel mode NEON + is disabled + +commit 0bc81767c5bd9d005fae1099fb39eb3688370cb1 upstream. + +When the ARM accelerated ChaCha driver is built as part of a configuration +that has kernel mode NEON disabled, we expect the compiler to propagate +the build time constant expression IS_ENABLED(CONFIG_KERNEL_MODE_NEON) in +a way that eliminates all the cross-object references to the actual NEON +routines, which allows the chacha-neon-core.o object to be omitted from +the build entirely. + +Unfortunately, this fails to work as expected in some cases, and we may +end up with a build error such as + + chacha-glue.c:(.text+0xc0): undefined reference to `chacha_4block_xor_neon' + +caused by the fact that chacha_doneon() has not been eliminated from the +object code, even though it will never be called in practice. + +Let's fix this by adding some IS_ENABLED(CONFIG_KERNEL_MODE_NEON) tests +that are not strictly needed from a logical point of view, but should +help the compiler infer that the NEON code paths are unreachable in +those cases. + +Fixes: b36d8c09e710c71f ("crypto: arm/chacha - remove dependency on generic ...") +Reported-by: Russell King +Cc: Arnd Bergmann +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/chacha-glue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/arch/arm/crypto/chacha-glue.c ++++ b/arch/arm/crypto/chacha-glue.c +@@ -115,7 +115,7 @@ static int chacha_stream_xor(struct skci + if (nbytes < walk.total) + nbytes = round_down(nbytes, walk.stride); + +- if (!neon) { ++ if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon) { + chacha_doarm(walk.dst.virt.addr, walk.src.virt.addr, + nbytes, state, ctx->nrounds); + state[12] += DIV_ROUND_UP(nbytes, CHACHA_BLOCK_SIZE); +@@ -159,7 +159,7 @@ static int do_xchacha(struct skcipher_re + + chacha_init_generic(state, ctx->key, req->iv); + +- if (!neon) { ++ if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon) { + hchacha_block_arm(state, subctx.key, ctx->nrounds); + } else { + kernel_neon_begin(); diff --git a/ipq806x/backport-5.4/080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch b/ipq806x/backport-5.4/080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch new file mode 100644 index 0000000..c52bf0a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0050-crypto-Kconfig-allow-tests-to-be-disabled-when-manag.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 17 Jan 2020 12:01:36 +0100 +Subject: [PATCH] crypto: Kconfig - allow tests to be disabled when manager is + disabled + +commit 2343d1529aff8b552589f622c23932035ed7a05d upstream. + +The library code uses CRYPTO_MANAGER_DISABLE_TESTS to conditionalize its +tests, but the library code can also exist without CRYPTO_MANAGER. That +means on minimal configs, the test code winds up being built with no way +to disable it. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/Kconfig | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -136,8 +136,6 @@ config CRYPTO_USER + Userspace configuration for cryptographic instantiations such as + cbc(aes). + +-if CRYPTO_MANAGER2 +- + config CRYPTO_MANAGER_DISABLE_TESTS + bool "Disable run-time self tests" + default y +@@ -155,8 +153,6 @@ config CRYPTO_MANAGER_EXTRA_TESTS + This is intended for developer use only, as these tests take much + longer to run than the normal self tests. + +-endif # if CRYPTO_MANAGER2 +- + config CRYPTO_GF128MUL + tristate + diff --git a/ipq806x/backport-5.4/080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch b/ipq806x/backport-5.4/080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch new file mode 100644 index 0000000..1ed49e5 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0051-crypto-chacha20poly1305-prevent-integer-overflow-on-.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 6 Feb 2020 12:42:01 +0100 +Subject: [PATCH] crypto: chacha20poly1305 - prevent integer overflow on large + input + +commit c9cc0517bba9f0213f1e55172feceb99e5512daf upstream. + +This code assigns src_len (size_t) to sl (int), which causes problems +when src_len is very large. Probably nobody in the kernel should be +passing this much data to chacha20poly1305 all in one go anyway, so I +don't think we need to change the algorithm or introduce larger types +or anything. But we should at least error out early in this case and +print a warning so that we get reports if this does happen and can look +into why anybody is possibly passing it that much data or if they're +accidently passing -1 or similar. + +Fixes: d95312a3ccc0 ("crypto: lib/chacha20poly1305 - reimplement crypt_from_sg() routine") +Cc: Ard Biesheuvel +Cc: stable@vger.kernel.org # 5.5+ +Signed-off-by: Jason A. Donenfeld +Acked-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + lib/crypto/chacha20poly1305.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/lib/crypto/chacha20poly1305.c ++++ b/lib/crypto/chacha20poly1305.c +@@ -235,6 +235,9 @@ bool chacha20poly1305_crypt_sg_inplace(s + __le64 lens[2]; + } b __aligned(16); + ++ if (WARN_ON(src_len > INT_MAX)) ++ return false; ++ + chacha_load_key(b.k, key); + + b.iv[0] = 0; diff --git a/ipq806x/backport-5.4/080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch b/ipq806x/backport-5.4/080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch new file mode 100644 index 0000000..cd507b1 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0052-crypto-x86-curve25519-support-assemblers-with-no-adx.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 1 Mar 2020 22:52:35 +0800 +Subject: [PATCH] crypto: x86/curve25519 - support assemblers with no adx + support + +commit 1579f1bc3b753d17a44de3457d5c6f4a5b14c752 upstream. + +Some older version of GAS do not support the ADX instructions, similarly +to how they also don't support AVX and such. This commit adds the same +build-time detection mechanisms we use for AVX and others for ADX, and +then makes sure that the curve25519 library dispatcher calls the right +functions. + +Reported-by: Willy Tarreau +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/Makefile | 5 +++-- + arch/x86/crypto/Makefile | 7 ++++++- + include/crypto/curve25519.h | 6 ++++-- + 3 files changed, 13 insertions(+), 5 deletions(-) + +--- a/arch/x86/Makefile ++++ b/arch/x86/Makefile +@@ -198,9 +198,10 @@ avx2_instr :=$(call as-instr,vpbroadcast + avx512_instr :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,-DCONFIG_AS_AVX512=1) + sha1_ni_instr :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA1_NI=1) + sha256_ni_instr :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA256_NI=1) ++adx_instr := $(call as-instr,adox %r10$(comma)%r10,-DCONFIG_AS_ADX=1) + +-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) +-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) ++KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr) ++KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr) + + KBUILD_LDFLAGS := -m elf_$(UTS_MACHINE) + +--- a/arch/x86/crypto/Makefile ++++ b/arch/x86/crypto/Makefile +@@ -11,6 +11,7 @@ avx2_supported := $(call as-instr,vpgath + avx512_supported :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,yes,no) + sha1_ni_supported :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,yes,no) + sha256_ni_supported :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,yes,no) ++adx_supported := $(call as-instr,adox %r10$(comma)%r10,yes,no) + + obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o + +@@ -39,7 +40,11 @@ obj-$(CONFIG_CRYPTO_AEGIS128_AESNI_SSE2) + + obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o + obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o +-obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o ++ ++# These modules require the assembler to support ADX. ++ifeq ($(adx_supported),yes) ++ obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o ++endif + + # These modules require assembler to support AVX. + ifeq ($(avx_supported),yes) +--- a/include/crypto/curve25519.h ++++ b/include/crypto/curve25519.h +@@ -33,7 +33,8 @@ bool __must_check curve25519(u8 mypublic + const u8 secret[CURVE25519_KEY_SIZE], + const u8 basepoint[CURVE25519_KEY_SIZE]) + { +- if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519)) ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) && ++ (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX))) + curve25519_arch(mypublic, secret, basepoint); + else + curve25519_generic(mypublic, secret, basepoint); +@@ -49,7 +50,8 @@ __must_check curve25519_generate_public( + CURVE25519_KEY_SIZE))) + return false; + +- if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519)) ++ if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) && ++ (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX))) + curve25519_base_arch(pub, secret); + else + curve25519_generic(pub, secret, curve25519_base_point); diff --git a/ipq806x/backport-5.4/080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch b/ipq806x/backport-5.4/080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch new file mode 100644 index 0000000..823a908 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0053-crypto-arm64-chacha-correctly-walk-through-blocks.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 18 Mar 2020 20:27:32 -0600 +Subject: [PATCH] crypto: arm64/chacha - correctly walk through blocks + +commit c8cfcb78c65877313cda7bcbace624d3dbd1f3b3 upstream. + +Prior, passing in chunks of 2, 3, or 4, followed by any additional +chunks would result in the chacha state counter getting out of sync, +resulting in incorrect encryption/decryption, which is a pretty nasty +crypto vuln: "why do images look weird on webpages?" WireGuard users +never experienced this prior, because we have always, out of tree, used +a different crypto library, until the recent Frankenzinc addition. This +commit fixes the issue by advancing the pointers and state counter by +the actual size processed. It also fixes up a bug in the (optional, +costly) stride test that prevented it from running on arm64. + +Fixes: b3aad5bad26a ("crypto: arm64/chacha - expose arm64 ChaCha routine as library function") +Reported-and-tested-by: Emil Renner Berthing +Cc: Ard Biesheuvel +Cc: stable@vger.kernel.org # v5.5+ +Signed-off-by: Jason A. Donenfeld +Reviewed-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm64/crypto/chacha-neon-glue.c | 8 ++++---- + lib/crypto/chacha20poly1305-selftest.c | 11 ++++++++--- + 2 files changed, 12 insertions(+), 7 deletions(-) + +--- a/arch/arm64/crypto/chacha-neon-glue.c ++++ b/arch/arm64/crypto/chacha-neon-glue.c +@@ -55,10 +55,10 @@ static void chacha_doneon(u32 *state, u8 + break; + } + chacha_4block_xor_neon(state, dst, src, nrounds, l); +- bytes -= CHACHA_BLOCK_SIZE * 5; +- src += CHACHA_BLOCK_SIZE * 5; +- dst += CHACHA_BLOCK_SIZE * 5; +- state[12] += 5; ++ bytes -= l; ++ src += l; ++ dst += l; ++ state[12] += DIV_ROUND_UP(l, CHACHA_BLOCK_SIZE); + } + } + +--- a/lib/crypto/chacha20poly1305-selftest.c ++++ b/lib/crypto/chacha20poly1305-selftest.c +@@ -9028,10 +9028,15 @@ bool __init chacha20poly1305_selftest(vo + && total_len <= 1 << 10; ++total_len) { + for (i = 0; i <= total_len; ++i) { + for (j = i; j <= total_len; ++j) { ++ k = 0; + sg_init_table(sg_src, 3); +- sg_set_buf(&sg_src[0], input, i); +- sg_set_buf(&sg_src[1], input + i, j - i); +- sg_set_buf(&sg_src[2], input + j, total_len - j); ++ if (i) ++ sg_set_buf(&sg_src[k++], input, i); ++ if (j - i) ++ sg_set_buf(&sg_src[k++], input + i, j - i); ++ if (total_len - j) ++ sg_set_buf(&sg_src[k++], input + j, total_len - j); ++ sg_init_marker(sg_src, k); + memset(computed_output, 0, total_len); + memset(input, 0, total_len); + diff --git a/ipq806x/backport-5.4/080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch b/ipq806x/backport-5.4/080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch new file mode 100644 index 0000000..938d700 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0054-crypto-x86-curve25519-replace-with-formally-verified.patch @@ -0,0 +1,3765 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 20 Jan 2020 18:18:15 +0100 +Subject: [PATCH] crypto: x86/curve25519 - replace with formally verified + implementation + +commit 07b586fe06625b0b610dc3d3a969c51913d143d4 upstream. + +This comes from INRIA's HACL*/Vale. It implements the same algorithm and +implementation strategy as the code it replaces, only this code has been +formally verified, sans the base point multiplication, which uses code +similar to prior, only it uses the formally verified field arithmetic +alongside reproducable ladder generation steps. This doesn't have a +pure-bmi2 version, which means haswell no longer benefits, but the +increased (doubled) code complexity is not worth it for a single +generation of chips that's already old. + +Performance-wise, this is around 1% slower on older microarchitectures, +and slightly faster on newer microarchitectures, mainly 10nm ones or +backports of 10nm to 14nm. This implementation is "everest" below: + +Xeon E5-2680 v4 (Broadwell) + + armfazh: 133340 cycles per call + everest: 133436 cycles per call + +Xeon Gold 5120 (Sky Lake Server) + + armfazh: 112636 cycles per call + everest: 113906 cycles per call + +Core i5-6300U (Sky Lake Client) + + armfazh: 116810 cycles per call + everest: 117916 cycles per call + +Core i7-7600U (Kaby Lake) + + armfazh: 119523 cycles per call + everest: 119040 cycles per call + +Core i7-8750H (Coffee Lake) + + armfazh: 113914 cycles per call + everest: 113650 cycles per call + +Core i9-9880H (Coffee Lake Refresh) + + armfazh: 112616 cycles per call + everest: 114082 cycles per call + +Core i3-8121U (Cannon Lake) + + armfazh: 113202 cycles per call + everest: 111382 cycles per call + +Core i7-8265U (Whiskey Lake) + + armfazh: 127307 cycles per call + everest: 127697 cycles per call + +Core i7-8550U (Kaby Lake Refresh) + + armfazh: 127522 cycles per call + everest: 127083 cycles per call + +Xeon Platinum 8275CL (Cascade Lake) + + armfazh: 114380 cycles per call + everest: 114656 cycles per call + +Achieving these kind of results with formally verified code is quite +remarkable, especialy considering that performance is favorable for +newer chips. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/curve25519-x86_64.c | 3546 ++++++++++----------------- + 1 file changed, 1292 insertions(+), 2254 deletions(-) + +--- a/arch/x86/crypto/curve25519-x86_64.c ++++ b/arch/x86/crypto/curve25519-x86_64.c +@@ -1,8 +1,7 @@ +-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++// SPDX-License-Identifier: GPL-2.0 OR MIT + /* +- * Copyright (c) 2017 Armando Faz . All Rights Reserved. +- * Copyright (C) 2018-2019 Jason A. Donenfeld . All Rights Reserved. +- * Copyright (C) 2018 Samuel Neves . All Rights Reserved. ++ * Copyright (C) 2020 Jason A. Donenfeld . All Rights Reserved. ++ * Copyright (c) 2016-2020 INRIA, CMU and Microsoft Corporation + */ + + #include +@@ -16,2337 +15,1378 @@ + #include + #include + +-static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_bmi2); +-static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_adx); +- +-enum { NUM_WORDS_ELTFP25519 = 4 }; +-typedef __aligned(32) u64 eltfp25519_1w[NUM_WORDS_ELTFP25519]; +-typedef __aligned(32) u64 eltfp25519_1w_buffer[2 * NUM_WORDS_ELTFP25519]; +- +-#define mul_eltfp25519_1w_adx(c, a, b) do { \ +- mul_256x256_integer_adx(m.buffer, a, b); \ +- red_eltfp25519_1w_adx(c, m.buffer); \ +-} while (0) +- +-#define mul_eltfp25519_1w_bmi2(c, a, b) do { \ +- mul_256x256_integer_bmi2(m.buffer, a, b); \ +- red_eltfp25519_1w_bmi2(c, m.buffer); \ +-} while (0) +- +-#define sqr_eltfp25519_1w_adx(a) do { \ +- sqr_256x256_integer_adx(m.buffer, a); \ +- red_eltfp25519_1w_adx(a, m.buffer); \ +-} while (0) +- +-#define sqr_eltfp25519_1w_bmi2(a) do { \ +- sqr_256x256_integer_bmi2(m.buffer, a); \ +- red_eltfp25519_1w_bmi2(a, m.buffer); \ +-} while (0) +- +-#define mul_eltfp25519_2w_adx(c, a, b) do { \ +- mul2_256x256_integer_adx(m.buffer, a, b); \ +- red_eltfp25519_2w_adx(c, m.buffer); \ +-} while (0) +- +-#define mul_eltfp25519_2w_bmi2(c, a, b) do { \ +- mul2_256x256_integer_bmi2(m.buffer, a, b); \ +- red_eltfp25519_2w_bmi2(c, m.buffer); \ +-} while (0) +- +-#define sqr_eltfp25519_2w_adx(a) do { \ +- sqr2_256x256_integer_adx(m.buffer, a); \ +- red_eltfp25519_2w_adx(a, m.buffer); \ +-} while (0) +- +-#define sqr_eltfp25519_2w_bmi2(a) do { \ +- sqr2_256x256_integer_bmi2(m.buffer, a); \ +- red_eltfp25519_2w_bmi2(a, m.buffer); \ +-} while (0) +- +-#define sqrn_eltfp25519_1w_adx(a, times) do { \ +- int ____counter = (times); \ +- while (____counter-- > 0) \ +- sqr_eltfp25519_1w_adx(a); \ +-} while (0) +- +-#define sqrn_eltfp25519_1w_bmi2(a, times) do { \ +- int ____counter = (times); \ +- while (____counter-- > 0) \ +- sqr_eltfp25519_1w_bmi2(a); \ +-} while (0) +- +-#define copy_eltfp25519_1w(C, A) do { \ +- (C)[0] = (A)[0]; \ +- (C)[1] = (A)[1]; \ +- (C)[2] = (A)[2]; \ +- (C)[3] = (A)[3]; \ +-} while (0) +- +-#define setzero_eltfp25519_1w(C) do { \ +- (C)[0] = 0; \ +- (C)[1] = 0; \ +- (C)[2] = 0; \ +- (C)[3] = 0; \ +-} while (0) +- +-__aligned(32) static const u64 table_ladder_8k[252 * NUM_WORDS_ELTFP25519] = { +- /* 1 */ 0xfffffffffffffff3UL, 0xffffffffffffffffUL, +- 0xffffffffffffffffUL, 0x5fffffffffffffffUL, +- /* 2 */ 0x6b8220f416aafe96UL, 0x82ebeb2b4f566a34UL, +- 0xd5a9a5b075a5950fUL, 0x5142b2cf4b2488f4UL, +- /* 3 */ 0x6aaebc750069680cUL, 0x89cf7820a0f99c41UL, +- 0x2a58d9183b56d0f4UL, 0x4b5aca80e36011a4UL, +- /* 4 */ 0x329132348c29745dUL, 0xf4a2e616e1642fd7UL, +- 0x1e45bb03ff67bc34UL, 0x306912d0f42a9b4aUL, +- /* 5 */ 0xff886507e6af7154UL, 0x04f50e13dfeec82fUL, +- 0xaa512fe82abab5ceUL, 0x174e251a68d5f222UL, +- /* 6 */ 0xcf96700d82028898UL, 0x1743e3370a2c02c5UL, +- 0x379eec98b4e86eaaUL, 0x0c59888a51e0482eUL, +- /* 7 */ 0xfbcbf1d699b5d189UL, 0xacaef0d58e9fdc84UL, +- 0xc1c20d06231f7614UL, 0x2938218da274f972UL, +- /* 8 */ 0xf6af49beff1d7f18UL, 0xcc541c22387ac9c2UL, +- 0x96fcc9ef4015c56bUL, 0x69c1627c690913a9UL, +- /* 9 */ 0x7a86fd2f4733db0eUL, 0xfdb8c4f29e087de9UL, +- 0x095e4b1a8ea2a229UL, 0x1ad7a7c829b37a79UL, +- /* 10 */ 0x342d89cad17ea0c0UL, 0x67bedda6cced2051UL, +- 0x19ca31bf2bb42f74UL, 0x3df7b4c84980acbbUL, +- /* 11 */ 0xa8c6444dc80ad883UL, 0xb91e440366e3ab85UL, +- 0xc215cda00164f6d8UL, 0x3d867c6ef247e668UL, +- /* 12 */ 0xc7dd582bcc3e658cUL, 0xfd2c4748ee0e5528UL, +- 0xa0fd9b95cc9f4f71UL, 0x7529d871b0675ddfUL, +- /* 13 */ 0xb8f568b42d3cbd78UL, 0x1233011b91f3da82UL, +- 0x2dce6ccd4a7c3b62UL, 0x75e7fc8e9e498603UL, +- /* 14 */ 0x2f4f13f1fcd0b6ecUL, 0xf1a8ca1f29ff7a45UL, +- 0xc249c1a72981e29bUL, 0x6ebe0dbb8c83b56aUL, +- /* 15 */ 0x7114fa8d170bb222UL, 0x65a2dcd5bf93935fUL, +- 0xbdc41f68b59c979aUL, 0x2f0eef79a2ce9289UL, +- /* 16 */ 0x42ecbf0c083c37ceUL, 0x2930bc09ec496322UL, +- 0xf294b0c19cfeac0dUL, 0x3780aa4bedfabb80UL, +- /* 17 */ 0x56c17d3e7cead929UL, 0xe7cb4beb2e5722c5UL, +- 0x0ce931732dbfe15aUL, 0x41b883c7621052f8UL, +- /* 18 */ 0xdbf75ca0c3d25350UL, 0x2936be086eb1e351UL, +- 0xc936e03cb4a9b212UL, 0x1d45bf82322225aaUL, +- /* 19 */ 0xe81ab1036a024cc5UL, 0xe212201c304c9a72UL, +- 0xc5d73fba6832b1fcUL, 0x20ffdb5a4d839581UL, +- /* 20 */ 0xa283d367be5d0fadUL, 0x6c2b25ca8b164475UL, +- 0x9d4935467caaf22eUL, 0x5166408eee85ff49UL, +- /* 21 */ 0x3c67baa2fab4e361UL, 0xb3e433c67ef35cefUL, +- 0x5259729241159b1cUL, 0x6a621892d5b0ab33UL, +- /* 22 */ 0x20b74a387555cdcbUL, 0x532aa10e1208923fUL, +- 0xeaa17b7762281dd1UL, 0x61ab3443f05c44bfUL, +- /* 23 */ 0x257a6c422324def8UL, 0x131c6c1017e3cf7fUL, +- 0x23758739f630a257UL, 0x295a407a01a78580UL, +- /* 24 */ 0xf8c443246d5da8d9UL, 0x19d775450c52fa5dUL, +- 0x2afcfc92731bf83dUL, 0x7d10c8e81b2b4700UL, +- /* 25 */ 0xc8e0271f70baa20bUL, 0x993748867ca63957UL, +- 0x5412efb3cb7ed4bbUL, 0x3196d36173e62975UL, +- /* 26 */ 0xde5bcad141c7dffcUL, 0x47cc8cd2b395c848UL, +- 0xa34cd942e11af3cbUL, 0x0256dbf2d04ecec2UL, +- /* 27 */ 0x875ab7e94b0e667fUL, 0xcad4dd83c0850d10UL, +- 0x47f12e8f4e72c79fUL, 0x5f1a87bb8c85b19bUL, +- /* 28 */ 0x7ae9d0b6437f51b8UL, 0x12c7ce5518879065UL, +- 0x2ade09fe5cf77aeeUL, 0x23a05a2f7d2c5627UL, +- /* 29 */ 0x5908e128f17c169aUL, 0xf77498dd8ad0852dUL, +- 0x74b4c4ceab102f64UL, 0x183abadd10139845UL, +- /* 30 */ 0xb165ba8daa92aaacUL, 0xd5c5ef9599386705UL, +- 0xbe2f8f0cf8fc40d1UL, 0x2701e635ee204514UL, +- /* 31 */ 0x629fa80020156514UL, 0xf223868764a8c1ceUL, +- 0x5b894fff0b3f060eUL, 0x60d9944cf708a3faUL, +- /* 32 */ 0xaeea001a1c7a201fUL, 0xebf16a633ee2ce63UL, +- 0x6f7709594c7a07e1UL, 0x79b958150d0208cbUL, +- /* 33 */ 0x24b55e5301d410e7UL, 0xe3a34edff3fdc84dUL, +- 0xd88768e4904032d8UL, 0x131384427b3aaeecUL, +- /* 34 */ 0x8405e51286234f14UL, 0x14dc4739adb4c529UL, +- 0xb8a2b5b250634ffdUL, 0x2fe2a94ad8a7ff93UL, +- /* 35 */ 0xec5c57efe843faddUL, 0x2843ce40f0bb9918UL, +- 0xa4b561d6cf3d6305UL, 0x743629bde8fb777eUL, +- /* 36 */ 0x343edd46bbaf738fUL, 0xed981828b101a651UL, +- 0xa401760b882c797aUL, 0x1fc223e28dc88730UL, +- /* 37 */ 0x48604e91fc0fba0eUL, 0xb637f78f052c6fa4UL, +- 0x91ccac3d09e9239cUL, 0x23f7eed4437a687cUL, +- /* 38 */ 0x5173b1118d9bd800UL, 0x29d641b63189d4a7UL, +- 0xfdbf177988bbc586UL, 0x2959894fcad81df5UL, +- /* 39 */ 0xaebc8ef3b4bbc899UL, 0x4148995ab26992b9UL, +- 0x24e20b0134f92cfbUL, 0x40d158894a05dee8UL, +- /* 40 */ 0x46b00b1185af76f6UL, 0x26bac77873187a79UL, +- 0x3dc0bf95ab8fff5fUL, 0x2a608bd8945524d7UL, +- /* 41 */ 0x26449588bd446302UL, 0x7c4bc21c0388439cUL, +- 0x8e98a4f383bd11b2UL, 0x26218d7bc9d876b9UL, +- /* 42 */ 0xe3081542997c178aUL, 0x3c2d29a86fb6606fUL, +- 0x5c217736fa279374UL, 0x7dde05734afeb1faUL, +- /* 43 */ 0x3bf10e3906d42babUL, 0xe4f7803e1980649cUL, +- 0xe6053bf89595bf7aUL, 0x394faf38da245530UL, +- /* 44 */ 0x7a8efb58896928f4UL, 0xfbc778e9cc6a113cUL, +- 0x72670ce330af596fUL, 0x48f222a81d3d6cf7UL, +- /* 45 */ 0xf01fce410d72caa7UL, 0x5a20ecc7213b5595UL, +- 0x7bc21165c1fa1483UL, 0x07f89ae31da8a741UL, +- /* 46 */ 0x05d2c2b4c6830ff9UL, 0xd43e330fc6316293UL, +- 0xa5a5590a96d3a904UL, 0x705edb91a65333b6UL, +- /* 47 */ 0x048ee15e0bb9a5f7UL, 0x3240cfca9e0aaf5dUL, +- 0x8f4b71ceedc4a40bUL, 0x621c0da3de544a6dUL, +- /* 48 */ 0x92872836a08c4091UL, 0xce8375b010c91445UL, +- 0x8a72eb524f276394UL, 0x2667fcfa7ec83635UL, +- /* 49 */ 0x7f4c173345e8752aUL, 0x061b47feee7079a5UL, +- 0x25dd9afa9f86ff34UL, 0x3780cef5425dc89cUL, +- /* 50 */ 0x1a46035a513bb4e9UL, 0x3e1ef379ac575adaUL, +- 0xc78c5f1c5fa24b50UL, 0x321a967634fd9f22UL, +- /* 51 */ 0x946707b8826e27faUL, 0x3dca84d64c506fd0UL, +- 0xc189218075e91436UL, 0x6d9284169b3b8484UL, +- /* 52 */ 0x3a67e840383f2ddfUL, 0x33eec9a30c4f9b75UL, +- 0x3ec7c86fa783ef47UL, 0x26ec449fbac9fbc4UL, +- /* 53 */ 0x5c0f38cba09b9e7dUL, 0x81168cc762a3478cUL, +- 0x3e23b0d306fc121cUL, 0x5a238aa0a5efdcddUL, +- /* 54 */ 0x1ba26121c4ea43ffUL, 0x36f8c77f7c8832b5UL, +- 0x88fbea0b0adcf99aUL, 0x5ca9938ec25bebf9UL, +- /* 55 */ 0xd5436a5e51fccda0UL, 0x1dbc4797c2cd893bUL, +- 0x19346a65d3224a08UL, 0x0f5034e49b9af466UL, +- /* 56 */ 0xf23c3967a1e0b96eUL, 0xe58b08fa867a4d88UL, +- 0xfb2fabc6a7341679UL, 0x2a75381eb6026946UL, +- /* 57 */ 0xc80a3be4c19420acUL, 0x66b1f6c681f2b6dcUL, +- 0x7cf7036761e93388UL, 0x25abbbd8a660a4c4UL, +- /* 58 */ 0x91ea12ba14fd5198UL, 0x684950fc4a3cffa9UL, +- 0xf826842130f5ad28UL, 0x3ea988f75301a441UL, +- /* 59 */ 0xc978109a695f8c6fUL, 0x1746eb4a0530c3f3UL, +- 0x444d6d77b4459995UL, 0x75952b8c054e5cc7UL, +- /* 60 */ 0xa3703f7915f4d6aaUL, 0x66c346202f2647d8UL, +- 0xd01469df811d644bUL, 0x77fea47d81a5d71fUL, +- /* 61 */ 0xc5e9529ef57ca381UL, 0x6eeeb4b9ce2f881aUL, +- 0xb6e91a28e8009bd6UL, 0x4b80be3e9afc3fecUL, +- /* 62 */ 0x7e3773c526aed2c5UL, 0x1b4afcb453c9a49dUL, +- 0xa920bdd7baffb24dUL, 0x7c54699f122d400eUL, +- /* 63 */ 0xef46c8e14fa94bc8UL, 0xe0b074ce2952ed5eUL, +- 0xbea450e1dbd885d5UL, 0x61b68649320f712cUL, +- /* 64 */ 0x8a485f7309ccbdd1UL, 0xbd06320d7d4d1a2dUL, +- 0x25232973322dbef4UL, 0x445dc4758c17f770UL, +- /* 65 */ 0xdb0434177cc8933cUL, 0xed6fe82175ea059fUL, +- 0x1efebefdc053db34UL, 0x4adbe867c65daf99UL, +- /* 66 */ 0x3acd71a2a90609dfUL, 0xe5e991856dd04050UL, +- 0x1ec69b688157c23cUL, 0x697427f6885cfe4dUL, +- /* 67 */ 0xd7be7b9b65e1a851UL, 0xa03d28d522c536ddUL, +- 0x28399d658fd2b645UL, 0x49e5b7e17c2641e1UL, +- /* 68 */ 0x6f8c3a98700457a4UL, 0x5078f0a25ebb6778UL, +- 0xd13c3ccbc382960fUL, 0x2e003258a7df84b1UL, +- /* 69 */ 0x8ad1f39be6296a1cUL, 0xc1eeaa652a5fbfb2UL, +- 0x33ee0673fd26f3cbUL, 0x59256173a69d2cccUL, +- /* 70 */ 0x41ea07aa4e18fc41UL, 0xd9fc19527c87a51eUL, +- 0xbdaacb805831ca6fUL, 0x445b652dc916694fUL, +- /* 71 */ 0xce92a3a7f2172315UL, 0x1edc282de11b9964UL, +- 0xa1823aafe04c314aUL, 0x790a2d94437cf586UL, +- /* 72 */ 0x71c447fb93f6e009UL, 0x8922a56722845276UL, +- 0xbf70903b204f5169UL, 0x2f7a89891ba319feUL, +- /* 73 */ 0x02a08eb577e2140cUL, 0xed9a4ed4427bdcf4UL, +- 0x5253ec44e4323cd1UL, 0x3e88363c14e9355bUL, +- /* 74 */ 0xaa66c14277110b8cUL, 0x1ae0391610a23390UL, +- 0x2030bd12c93fc2a2UL, 0x3ee141579555c7abUL, +- /* 75 */ 0x9214de3a6d6e7d41UL, 0x3ccdd88607f17efeUL, +- 0x674f1288f8e11217UL, 0x5682250f329f93d0UL, +- /* 76 */ 0x6cf00b136d2e396eUL, 0x6e4cf86f1014debfUL, +- 0x5930b1b5bfcc4e83UL, 0x047069b48aba16b6UL, +- /* 77 */ 0x0d4ce4ab69b20793UL, 0xb24db91a97d0fb9eUL, +- 0xcdfa50f54e00d01dUL, 0x221b1085368bddb5UL, +- /* 78 */ 0xe7e59468b1e3d8d2UL, 0x53c56563bd122f93UL, +- 0xeee8a903e0663f09UL, 0x61efa662cbbe3d42UL, +- /* 79 */ 0x2cf8ddddde6eab2aUL, 0x9bf80ad51435f231UL, +- 0x5deadacec9f04973UL, 0x29275b5d41d29b27UL, +- /* 80 */ 0xcfde0f0895ebf14fUL, 0xb9aab96b054905a7UL, +- 0xcae80dd9a1c420fdUL, 0x0a63bf2f1673bbc7UL, +- /* 81 */ 0x092f6e11958fbc8cUL, 0x672a81e804822fadUL, +- 0xcac8351560d52517UL, 0x6f3f7722c8f192f8UL, +- /* 82 */ 0xf8ba90ccc2e894b7UL, 0x2c7557a438ff9f0dUL, +- 0x894d1d855ae52359UL, 0x68e122157b743d69UL, +- /* 83 */ 0xd87e5570cfb919f3UL, 0x3f2cdecd95798db9UL, +- 0x2121154710c0a2ceUL, 0x3c66a115246dc5b2UL, +- /* 84 */ 0xcbedc562294ecb72UL, 0xba7143c36a280b16UL, +- 0x9610c2efd4078b67UL, 0x6144735d946a4b1eUL, +- /* 85 */ 0x536f111ed75b3350UL, 0x0211db8c2041d81bUL, +- 0xf93cb1000e10413cUL, 0x149dfd3c039e8876UL, +- /* 86 */ 0xd479dde46b63155bUL, 0xb66e15e93c837976UL, +- 0xdafde43b1f13e038UL, 0x5fafda1a2e4b0b35UL, +- /* 87 */ 0x3600bbdf17197581UL, 0x3972050bbe3cd2c2UL, +- 0x5938906dbdd5be86UL, 0x34fce5e43f9b860fUL, +- /* 88 */ 0x75a8a4cd42d14d02UL, 0x828dabc53441df65UL, +- 0x33dcabedd2e131d3UL, 0x3ebad76fb814d25fUL, +- /* 89 */ 0xd4906f566f70e10fUL, 0x5d12f7aa51690f5aUL, +- 0x45adb16e76cefcf2UL, 0x01f768aead232999UL, +- /* 90 */ 0x2b6cc77b6248febdUL, 0x3cd30628ec3aaffdUL, +- 0xce1c0b80d4ef486aUL, 0x4c3bff2ea6f66c23UL, +- /* 91 */ 0x3f2ec4094aeaeb5fUL, 0x61b19b286e372ca7UL, +- 0x5eefa966de2a701dUL, 0x23b20565de55e3efUL, +- /* 92 */ 0xe301ca5279d58557UL, 0x07b2d4ce27c2874fUL, +- 0xa532cd8a9dcf1d67UL, 0x2a52fee23f2bff56UL, +- /* 93 */ 0x8624efb37cd8663dUL, 0xbbc7ac20ffbd7594UL, +- 0x57b85e9c82d37445UL, 0x7b3052cb86a6ec66UL, +- /* 94 */ 0x3482f0ad2525e91eUL, 0x2cb68043d28edca0UL, +- 0xaf4f6d052e1b003aUL, 0x185f8c2529781b0aUL, +- /* 95 */ 0xaa41de5bd80ce0d6UL, 0x9407b2416853e9d6UL, +- 0x563ec36e357f4c3aUL, 0x4cc4b8dd0e297bceUL, +- /* 96 */ 0xa2fc1a52ffb8730eUL, 0x1811f16e67058e37UL, +- 0x10f9a366cddf4ee1UL, 0x72f4a0c4a0b9f099UL, +- /* 97 */ 0x8c16c06f663f4ea7UL, 0x693b3af74e970fbaUL, +- 0x2102e7f1d69ec345UL, 0x0ba53cbc968a8089UL, +- /* 98 */ 0xca3d9dc7fea15537UL, 0x4c6824bb51536493UL, +- 0xb9886314844006b1UL, 0x40d2a72ab454cc60UL, +- /* 99 */ 0x5936a1b712570975UL, 0x91b9d648debda657UL, +- 0x3344094bb64330eaUL, 0x006ba10d12ee51d0UL, +- /* 100 */ 0x19228468f5de5d58UL, 0x0eb12f4c38cc05b0UL, +- 0xa1039f9dd5601990UL, 0x4502d4ce4fff0e0bUL, +- /* 101 */ 0xeb2054106837c189UL, 0xd0f6544c6dd3b93cUL, +- 0x40727064c416d74fUL, 0x6e15c6114b502ef0UL, +- /* 102 */ 0x4df2a398cfb1a76bUL, 0x11256c7419f2f6b1UL, +- 0x4a497962066e6043UL, 0x705b3aab41355b44UL, +- /* 103 */ 0x365ef536d797b1d8UL, 0x00076bd622ddf0dbUL, +- 0x3bbf33b0e0575a88UL, 0x3777aa05c8e4ca4dUL, +- /* 104 */ 0x392745c85578db5fUL, 0x6fda4149dbae5ae2UL, +- 0xb1f0b00b8adc9867UL, 0x09963437d36f1da3UL, +- /* 105 */ 0x7e824e90a5dc3853UL, 0xccb5f6641f135cbdUL, +- 0x6736d86c87ce8fccUL, 0x625f3ce26604249fUL, +- /* 106 */ 0xaf8ac8059502f63fUL, 0x0c05e70a2e351469UL, +- 0x35292e9c764b6305UL, 0x1a394360c7e23ac3UL, +- /* 107 */ 0xd5c6d53251183264UL, 0x62065abd43c2b74fUL, +- 0xb5fbf5d03b973f9bUL, 0x13a3da3661206e5eUL, +- /* 108 */ 0xc6bd5837725d94e5UL, 0x18e30912205016c5UL, +- 0x2088ce1570033c68UL, 0x7fba1f495c837987UL, +- /* 109 */ 0x5a8c7423f2f9079dUL, 0x1735157b34023fc5UL, +- 0xe4f9b49ad2fab351UL, 0x6691ff72c878e33cUL, +- /* 110 */ 0x122c2adedc5eff3eUL, 0xf8dd4bf1d8956cf4UL, +- 0xeb86205d9e9e5bdaUL, 0x049b92b9d975c743UL, +- /* 111 */ 0xa5379730b0f6c05aUL, 0x72a0ffacc6f3a553UL, +- 0xb0032c34b20dcd6dUL, 0x470e9dbc88d5164aUL, +- /* 112 */ 0xb19cf10ca237c047UL, 0xb65466711f6c81a2UL, +- 0xb3321bd16dd80b43UL, 0x48c14f600c5fbe8eUL, +- /* 113 */ 0x66451c264aa6c803UL, 0xb66e3904a4fa7da6UL, +- 0xd45f19b0b3128395UL, 0x31602627c3c9bc10UL, +- /* 114 */ 0x3120dc4832e4e10dUL, 0xeb20c46756c717f7UL, +- 0x00f52e3f67280294UL, 0x566d4fc14730c509UL, +- /* 115 */ 0x7e3a5d40fd837206UL, 0xc1e926dc7159547aUL, +- 0x216730fba68d6095UL, 0x22e8c3843f69cea7UL, +- /* 116 */ 0x33d074e8930e4b2bUL, 0xb6e4350e84d15816UL, +- 0x5534c26ad6ba2365UL, 0x7773c12f89f1f3f3UL, +- /* 117 */ 0x8cba404da57962aaUL, 0x5b9897a81999ce56UL, +- 0x508e862f121692fcUL, 0x3a81907fa093c291UL, +- /* 118 */ 0x0dded0ff4725a510UL, 0x10d8cc10673fc503UL, +- 0x5b9d151c9f1f4e89UL, 0x32a5c1d5cb09a44cUL, +- /* 119 */ 0x1e0aa442b90541fbUL, 0x5f85eb7cc1b485dbUL, +- 0xbee595ce8a9df2e5UL, 0x25e496c722422236UL, +- /* 120 */ 0x5edf3c46cd0fe5b9UL, 0x34e75a7ed2a43388UL, +- 0xe488de11d761e352UL, 0x0e878a01a085545cUL, +- /* 121 */ 0xba493c77e021bb04UL, 0x2b4d1843c7df899aUL, +- 0x9ea37a487ae80d67UL, 0x67a9958011e41794UL, +- /* 122 */ 0x4b58051a6697b065UL, 0x47e33f7d8d6ba6d4UL, +- 0xbb4da8d483ca46c1UL, 0x68becaa181c2db0dUL, +- /* 123 */ 0x8d8980e90b989aa5UL, 0xf95eb14a2c93c99bUL, +- 0x51c6c7c4796e73a2UL, 0x6e228363b5efb569UL, +- /* 124 */ 0xc6bbc0b02dd624c8UL, 0x777eb47dec8170eeUL, +- 0x3cde15a004cfafa9UL, 0x1dc6bc087160bf9bUL, +- /* 125 */ 0x2e07e043eec34002UL, 0x18e9fc677a68dc7fUL, +- 0xd8da03188bd15b9aUL, 0x48fbc3bb00568253UL, +- /* 126 */ 0x57547d4cfb654ce1UL, 0xd3565b82a058e2adUL, +- 0xf63eaf0bbf154478UL, 0x47531ef114dfbb18UL, +- /* 127 */ 0xe1ec630a4278c587UL, 0x5507d546ca8e83f3UL, +- 0x85e135c63adc0c2bUL, 0x0aa7efa85682844eUL, +- /* 128 */ 0x72691ba8b3e1f615UL, 0x32b4e9701fbe3ffaUL, +- 0x97b6d92e39bb7868UL, 0x2cfe53dea02e39e8UL, +- /* 129 */ 0x687392cd85cd52b0UL, 0x27ff66c910e29831UL, +- 0x97134556a9832d06UL, 0x269bb0360a84f8a0UL, +- /* 130 */ 0x706e55457643f85cUL, 0x3734a48c9b597d1bUL, +- 0x7aee91e8c6efa472UL, 0x5cd6abc198a9d9e0UL, +- /* 131 */ 0x0e04de06cb3ce41aUL, 0xd8c6eb893402e138UL, +- 0x904659bb686e3772UL, 0x7215c371746ba8c8UL, +- /* 132 */ 0xfd12a97eeae4a2d9UL, 0x9514b7516394f2c5UL, +- 0x266fd5809208f294UL, 0x5c847085619a26b9UL, +- /* 133 */ 0x52985410fed694eaUL, 0x3c905b934a2ed254UL, +- 0x10bb47692d3be467UL, 0x063b3d2d69e5e9e1UL, +- /* 134 */ 0x472726eedda57debUL, 0xefb6c4ae10f41891UL, +- 0x2b1641917b307614UL, 0x117c554fc4f45b7cUL, +- /* 135 */ 0xc07cf3118f9d8812UL, 0x01dbd82050017939UL, +- 0xd7e803f4171b2827UL, 0x1015e87487d225eaUL, +- /* 136 */ 0xc58de3fed23acc4dUL, 0x50db91c294a7be2dUL, +- 0x0b94d43d1c9cf457UL, 0x6b1640fa6e37524aUL, +- /* 137 */ 0x692f346c5fda0d09UL, 0x200b1c59fa4d3151UL, +- 0xb8c46f760777a296UL, 0x4b38395f3ffdfbcfUL, +- /* 138 */ 0x18d25e00be54d671UL, 0x60d50582bec8aba6UL, +- 0x87ad8f263b78b982UL, 0x50fdf64e9cda0432UL, +- /* 139 */ 0x90f567aac578dcf0UL, 0xef1e9b0ef2a3133bUL, +- 0x0eebba9242d9de71UL, 0x15473c9bf03101c7UL, +- /* 140 */ 0x7c77e8ae56b78095UL, 0xb678e7666e6f078eUL, +- 0x2da0b9615348ba1fUL, 0x7cf931c1ff733f0bUL, +- /* 141 */ 0x26b357f50a0a366cUL, 0xe9708cf42b87d732UL, +- 0xc13aeea5f91cb2c0UL, 0x35d90c991143bb4cUL, +- /* 142 */ 0x47c1c404a9a0d9dcUL, 0x659e58451972d251UL, +- 0x3875a8c473b38c31UL, 0x1fbd9ed379561f24UL, +- /* 143 */ 0x11fabc6fd41ec28dUL, 0x7ef8dfe3cd2a2dcaUL, +- 0x72e73b5d8c404595UL, 0x6135fa4954b72f27UL, +- /* 144 */ 0xccfc32a2de24b69cUL, 0x3f55698c1f095d88UL, +- 0xbe3350ed5ac3f929UL, 0x5e9bf806ca477eebUL, +- /* 145 */ 0xe9ce8fb63c309f68UL, 0x5376f63565e1f9f4UL, +- 0xd1afcfb35a6393f1UL, 0x6632a1ede5623506UL, +- /* 146 */ 0x0b7d6c390c2ded4cUL, 0x56cb3281df04cb1fUL, +- 0x66305a1249ecc3c7UL, 0x5d588b60a38ca72aUL, +- /* 147 */ 0xa6ecbf78e8e5f42dUL, 0x86eeb44b3c8a3eecUL, +- 0xec219c48fbd21604UL, 0x1aaf1af517c36731UL, +- /* 148 */ 0xc306a2836769bde7UL, 0x208280622b1e2adbUL, +- 0x8027f51ffbff94a6UL, 0x76cfa1ce1124f26bUL, +- /* 149 */ 0x18eb00562422abb6UL, 0xf377c4d58f8c29c3UL, +- 0x4dbbc207f531561aUL, 0x0253b7f082128a27UL, +- /* 150 */ 0x3d1f091cb62c17e0UL, 0x4860e1abd64628a9UL, +- 0x52d17436309d4253UL, 0x356f97e13efae576UL, +- /* 151 */ 0xd351e11aa150535bUL, 0x3e6b45bb1dd878ccUL, +- 0x0c776128bed92c98UL, 0x1d34ae93032885b8UL, +- /* 152 */ 0x4ba0488ca85ba4c3UL, 0x985348c33c9ce6ceUL, +- 0x66124c6f97bda770UL, 0x0f81a0290654124aUL, +- /* 153 */ 0x9ed09ca6569b86fdUL, 0x811009fd18af9a2dUL, +- 0xff08d03f93d8c20aUL, 0x52a148199faef26bUL, +- /* 154 */ 0x3e03f9dc2d8d1b73UL, 0x4205801873961a70UL, +- 0xc0d987f041a35970UL, 0x07aa1f15a1c0d549UL, +- /* 155 */ 0xdfd46ce08cd27224UL, 0x6d0a024f934e4239UL, +- 0x808a7a6399897b59UL, 0x0a4556e9e13d95a2UL, +- /* 156 */ 0xd21a991fe9c13045UL, 0x9b0e8548fe7751b8UL, +- 0x5da643cb4bf30035UL, 0x77db28d63940f721UL, +- /* 157 */ 0xfc5eeb614adc9011UL, 0x5229419ae8c411ebUL, +- 0x9ec3e7787d1dcf74UL, 0x340d053e216e4cb5UL, +- /* 158 */ 0xcac7af39b48df2b4UL, 0xc0faec2871a10a94UL, +- 0x140a69245ca575edUL, 0x0cf1c37134273a4cUL, +- /* 159 */ 0xc8ee306ac224b8a5UL, 0x57eaee7ccb4930b0UL, +- 0xa1e806bdaacbe74fUL, 0x7d9a62742eeb657dUL, +- /* 160 */ 0x9eb6b6ef546c4830UL, 0x885cca1fddb36e2eUL, +- 0xe6b9f383ef0d7105UL, 0x58654fef9d2e0412UL, +- /* 161 */ 0xa905c4ffbe0e8e26UL, 0x942de5df9b31816eUL, +- 0x497d723f802e88e1UL, 0x30684dea602f408dUL, +- /* 162 */ 0x21e5a278a3e6cb34UL, 0xaefb6e6f5b151dc4UL, +- 0xb30b8e049d77ca15UL, 0x28c3c9cf53b98981UL, +- /* 163 */ 0x287fb721556cdd2aUL, 0x0d317ca897022274UL, +- 0x7468c7423a543258UL, 0x4a7f11464eb5642fUL, +- /* 164 */ 0xa237a4774d193aa6UL, 0xd865986ea92129a1UL, +- 0x24c515ecf87c1a88UL, 0x604003575f39f5ebUL, +- /* 165 */ 0x47b9f189570a9b27UL, 0x2b98cede465e4b78UL, +- 0x026df551dbb85c20UL, 0x74fcd91047e21901UL, +- /* 166 */ 0x13e2a90a23c1bfa3UL, 0x0cb0074e478519f6UL, +- 0x5ff1cbbe3af6cf44UL, 0x67fe5438be812dbeUL, +- /* 167 */ 0xd13cf64fa40f05b0UL, 0x054dfb2f32283787UL, +- 0x4173915b7f0d2aeaUL, 0x482f144f1f610d4eUL, +- /* 168 */ 0xf6210201b47f8234UL, 0x5d0ae1929e70b990UL, +- 0xdcd7f455b049567cUL, 0x7e93d0f1f0916f01UL, +- /* 169 */ 0xdd79cbf18a7db4faUL, 0xbe8391bf6f74c62fUL, +- 0x027145d14b8291bdUL, 0x585a73ea2cbf1705UL, +- /* 170 */ 0x485ca03e928a0db2UL, 0x10fc01a5742857e7UL, +- 0x2f482edbd6d551a7UL, 0x0f0433b5048fdb8aUL, +- /* 171 */ 0x60da2e8dd7dc6247UL, 0x88b4c9d38cd4819aUL, +- 0x13033ac001f66697UL, 0x273b24fe3b367d75UL, +- /* 172 */ 0xc6e8f66a31b3b9d4UL, 0x281514a494df49d5UL, +- 0xd1726fdfc8b23da7UL, 0x4b3ae7d103dee548UL, +- /* 173 */ 0xc6256e19ce4b9d7eUL, 0xff5c5cf186e3c61cUL, +- 0xacc63ca34b8ec145UL, 0x74621888fee66574UL, +- /* 174 */ 0x956f409645290a1eUL, 0xef0bf8e3263a962eUL, +- 0xed6a50eb5ec2647bUL, 0x0694283a9dca7502UL, +- /* 175 */ 0x769b963643a2dcd1UL, 0x42b7c8ea09fc5353UL, +- 0x4f002aee13397eabUL, 0x63005e2c19b7d63aUL, +- /* 176 */ 0xca6736da63023beaUL, 0x966c7f6db12a99b7UL, +- 0xace09390c537c5e1UL, 0x0b696063a1aa89eeUL, +- /* 177 */ 0xebb03e97288c56e5UL, 0x432a9f9f938c8be8UL, +- 0xa6a5a93d5b717f71UL, 0x1a5fb4c3e18f9d97UL, +- /* 178 */ 0x1c94e7ad1c60cdceUL, 0xee202a43fc02c4a0UL, +- 0x8dafe4d867c46a20UL, 0x0a10263c8ac27b58UL, +- /* 179 */ 0xd0dea9dfe4432a4aUL, 0x856af87bbe9277c5UL, +- 0xce8472acc212c71aUL, 0x6f151b6d9bbb1e91UL, +- /* 180 */ 0x26776c527ceed56aUL, 0x7d211cb7fbf8faecUL, +- 0x37ae66a6fd4609ccUL, 0x1f81b702d2770c42UL, +- /* 181 */ 0x2fb0b057eac58392UL, 0xe1dd89fe29744e9dUL, +- 0xc964f8eb17beb4f8UL, 0x29571073c9a2d41eUL, +- /* 182 */ 0xa948a18981c0e254UL, 0x2df6369b65b22830UL, +- 0xa33eb2d75fcfd3c6UL, 0x078cd6ec4199a01fUL, +- /* 183 */ 0x4a584a41ad900d2fUL, 0x32142b78e2c74c52UL, +- 0x68c4e8338431c978UL, 0x7f69ea9008689fc2UL, +- /* 184 */ 0x52f2c81e46a38265UL, 0xfd78072d04a832fdUL, +- 0x8cd7d5fa25359e94UL, 0x4de71b7454cc29d2UL, +- /* 185 */ 0x42eb60ad1eda6ac9UL, 0x0aad37dfdbc09c3aUL, +- 0x81004b71e33cc191UL, 0x44e6be345122803cUL, +- /* 186 */ 0x03fe8388ba1920dbUL, 0xf5d57c32150db008UL, +- 0x49c8c4281af60c29UL, 0x21edb518de701aeeUL, +- /* 187 */ 0x7fb63e418f06dc99UL, 0xa4460d99c166d7b8UL, +- 0x24dd5248ce520a83UL, 0x5ec3ad712b928358UL, +- /* 188 */ 0x15022a5fbd17930fUL, 0xa4f64a77d82570e3UL, +- 0x12bc8d6915783712UL, 0x498194c0fc620abbUL, +- /* 189 */ 0x38a2d9d255686c82UL, 0x785c6bd9193e21f0UL, +- 0xe4d5c81ab24a5484UL, 0x56307860b2e20989UL, +- /* 190 */ 0x429d55f78b4d74c4UL, 0x22f1834643350131UL, +- 0x1e60c24598c71fffUL, 0x59f2f014979983efUL, +- /* 191 */ 0x46a47d56eb494a44UL, 0x3e22a854d636a18eUL, +- 0xb346e15274491c3bUL, 0x2ceafd4e5390cde7UL, +- /* 192 */ 0xba8a8538be0d6675UL, 0x4b9074bb50818e23UL, +- 0xcbdab89085d304c3UL, 0x61a24fe0e56192c4UL, +- /* 193 */ 0xcb7615e6db525bcbUL, 0xdd7d8c35a567e4caUL, +- 0xe6b4153acafcdd69UL, 0x2d668e097f3c9766UL, +- /* 194 */ 0xa57e7e265ce55ef0UL, 0x5d9f4e527cd4b967UL, +- 0xfbc83606492fd1e5UL, 0x090d52beb7c3f7aeUL, +- /* 195 */ 0x09b9515a1e7b4d7cUL, 0x1f266a2599da44c0UL, +- 0xa1c49548e2c55504UL, 0x7ef04287126f15ccUL, +- /* 196 */ 0xfed1659dbd30ef15UL, 0x8b4ab9eec4e0277bUL, +- 0x884d6236a5df3291UL, 0x1fd96ea6bf5cf788UL, +- /* 197 */ 0x42a161981f190d9aUL, 0x61d849507e6052c1UL, +- 0x9fe113bf285a2cd5UL, 0x7c22d676dbad85d8UL, +- /* 198 */ 0x82e770ed2bfbd27dUL, 0x4c05b2ece996f5a5UL, +- 0xcd40a9c2b0900150UL, 0x5895319213d9bf64UL, +- /* 199 */ 0xe7cc5d703fea2e08UL, 0xb50c491258e2188cUL, +- 0xcce30baa48205bf0UL, 0x537c659ccfa32d62UL, +- /* 200 */ 0x37b6623a98cfc088UL, 0xfe9bed1fa4d6aca4UL, +- 0x04d29b8e56a8d1b0UL, 0x725f71c40b519575UL, +- /* 201 */ 0x28c7f89cd0339ce6UL, 0x8367b14469ddc18bUL, +- 0x883ada83a6a1652cUL, 0x585f1974034d6c17UL, +- /* 202 */ 0x89cfb266f1b19188UL, 0xe63b4863e7c35217UL, +- 0xd88c9da6b4c0526aUL, 0x3e035c9df0954635UL, +- /* 203 */ 0xdd9d5412fb45de9dUL, 0xdd684532e4cff40dUL, +- 0x4b5c999b151d671cUL, 0x2d8c2cc811e7f690UL, +- /* 204 */ 0x7f54be1d90055d40UL, 0xa464c5df464aaf40UL, +- 0x33979624f0e917beUL, 0x2c018dc527356b30UL, +- /* 205 */ 0xa5415024e330b3d4UL, 0x73ff3d96691652d3UL, +- 0x94ec42c4ef9b59f1UL, 0x0747201618d08e5aUL, +- /* 206 */ 0x4d6ca48aca411c53UL, 0x66415f2fcfa66119UL, +- 0x9c4dd40051e227ffUL, 0x59810bc09a02f7ebUL, +- /* 207 */ 0x2a7eb171b3dc101dUL, 0x441c5ab99ffef68eUL, +- 0x32025c9b93b359eaUL, 0x5e8ce0a71e9d112fUL, +- /* 208 */ 0xbfcccb92429503fdUL, 0xd271ba752f095d55UL, +- 0x345ead5e972d091eUL, 0x18c8df11a83103baUL, +- /* 209 */ 0x90cd949a9aed0f4cUL, 0xc5d1f4cb6660e37eUL, +- 0xb8cac52d56c52e0bUL, 0x6e42e400c5808e0dUL, +- /* 210 */ 0xa3b46966eeaefd23UL, 0x0c4f1f0be39ecdcaUL, +- 0x189dc8c9d683a51dUL, 0x51f27f054c09351bUL, +- /* 211 */ 0x4c487ccd2a320682UL, 0x587ea95bb3df1c96UL, +- 0xc8ccf79e555cb8e8UL, 0x547dc829a206d73dUL, +- /* 212 */ 0xb822a6cd80c39b06UL, 0xe96d54732000d4c6UL, +- 0x28535b6f91463b4dUL, 0x228f4660e2486e1dUL, +- /* 213 */ 0x98799538de8d3abfUL, 0x8cd8330045ebca6eUL, +- 0x79952a008221e738UL, 0x4322e1a7535cd2bbUL, +- /* 214 */ 0xb114c11819d1801cUL, 0x2016e4d84f3f5ec7UL, +- 0xdd0e2df409260f4cUL, 0x5ec362c0ae5f7266UL, +- /* 215 */ 0xc0462b18b8b2b4eeUL, 0x7cc8d950274d1afbUL, +- 0xf25f7105436b02d2UL, 0x43bbf8dcbff9ccd3UL, +- /* 216 */ 0xb6ad1767a039e9dfUL, 0xb0714da8f69d3583UL, +- 0x5e55fa18b42931f5UL, 0x4ed5558f33c60961UL, +- /* 217 */ 0x1fe37901c647a5ddUL, 0x593ddf1f8081d357UL, +- 0x0249a4fd813fd7a6UL, 0x69acca274e9caf61UL, +- /* 218 */ 0x047ba3ea330721c9UL, 0x83423fc20e7e1ea0UL, +- 0x1df4c0af01314a60UL, 0x09a62dab89289527UL, +- /* 219 */ 0xa5b325a49cc6cb00UL, 0xe94b5dc654b56cb6UL, +- 0x3be28779adc994a0UL, 0x4296e8f8ba3a4aadUL, +- /* 220 */ 0x328689761e451eabUL, 0x2e4d598bff59594aUL, +- 0x49b96853d7a7084aUL, 0x4980a319601420a8UL, +- /* 221 */ 0x9565b9e12f552c42UL, 0x8a5318db7100fe96UL, +- 0x05c90b4d43add0d7UL, 0x538b4cd66a5d4edaUL, +- /* 222 */ 0xf4e94fc3e89f039fUL, 0x592c9af26f618045UL, +- 0x08a36eb5fd4b9550UL, 0x25fffaf6c2ed1419UL, +- /* 223 */ 0x34434459cc79d354UL, 0xeeecbfb4b1d5476bUL, +- 0xddeb34a061615d99UL, 0x5129cecceb64b773UL, +- /* 224 */ 0xee43215894993520UL, 0x772f9c7cf14c0b3bUL, +- 0xd2e2fce306bedad5UL, 0x715f42b546f06a97UL, +- /* 225 */ 0x434ecdceda5b5f1aUL, 0x0da17115a49741a9UL, +- 0x680bd77c73edad2eUL, 0x487c02354edd9041UL, +- /* 226 */ 0xb8efeff3a70ed9c4UL, 0x56a32aa3e857e302UL, +- 0xdf3a68bd48a2a5a0UL, 0x07f650b73176c444UL, +- /* 227 */ 0xe38b9b1626e0ccb1UL, 0x79e053c18b09fb36UL, +- 0x56d90319c9f94964UL, 0x1ca941e7ac9ff5c4UL, +- /* 228 */ 0x49c4df29162fa0bbUL, 0x8488cf3282b33305UL, +- 0x95dfda14cabb437dUL, 0x3391f78264d5ad86UL, +- /* 229 */ 0x729ae06ae2b5095dUL, 0xd58a58d73259a946UL, +- 0xe9834262d13921edUL, 0x27fedafaa54bb592UL, +- /* 230 */ 0xa99dc5b829ad48bbUL, 0x5f025742499ee260UL, +- 0x802c8ecd5d7513fdUL, 0x78ceb3ef3f6dd938UL, +- /* 231 */ 0xc342f44f8a135d94UL, 0x7b9edb44828cdda3UL, +- 0x9436d11a0537cfe7UL, 0x5064b164ec1ab4c8UL, +- /* 232 */ 0x7020eccfd37eb2fcUL, 0x1f31ea3ed90d25fcUL, +- 0x1b930d7bdfa1bb34UL, 0x5344467a48113044UL, +- /* 233 */ 0x70073170f25e6dfbUL, 0xe385dc1a50114cc8UL, +- 0x2348698ac8fc4f00UL, 0x2a77a55284dd40d8UL, +- /* 234 */ 0xfe06afe0c98c6ce4UL, 0xc235df96dddfd6e4UL, +- 0x1428d01e33bf1ed3UL, 0x785768ec9300bdafUL, +- /* 235 */ 0x9702e57a91deb63bUL, 0x61bdb8bfe5ce8b80UL, +- 0x645b426f3d1d58acUL, 0x4804a82227a557bcUL, +- /* 236 */ 0x8e57048ab44d2601UL, 0x68d6501a4b3a6935UL, +- 0xc39c9ec3f9e1c293UL, 0x4172f257d4de63e2UL, +- /* 237 */ 0xd368b450330c6401UL, 0x040d3017418f2391UL, +- 0x2c34bb6090b7d90dUL, 0x16f649228fdfd51fUL, +- /* 238 */ 0xbea6818e2b928ef5UL, 0xe28ccf91cdc11e72UL, +- 0x594aaa68e77a36cdUL, 0x313034806c7ffd0fUL, +- /* 239 */ 0x8a9d27ac2249bd65UL, 0x19a3b464018e9512UL, +- 0xc26ccff352b37ec7UL, 0x056f68341d797b21UL, +- /* 240 */ 0x5e79d6757efd2327UL, 0xfabdbcb6553afe15UL, +- 0xd3e7222c6eaf5a60UL, 0x7046c76d4dae743bUL, +- /* 241 */ 0x660be872b18d4a55UL, 0x19992518574e1496UL, +- 0xc103053a302bdcbbUL, 0x3ed8e9800b218e8eUL, +- /* 242 */ 0x7b0b9239fa75e03eUL, 0xefe9fb684633c083UL, +- 0x98a35fbe391a7793UL, 0x6065510fe2d0fe34UL, +- /* 243 */ 0x55cb668548abad0cUL, 0xb4584548da87e527UL, +- 0x2c43ecea0107c1ddUL, 0x526028809372de35UL, +- /* 244 */ 0x3415c56af9213b1fUL, 0x5bee1a4d017e98dbUL, +- 0x13f6b105b5cf709bUL, 0x5ff20e3482b29ab6UL, +- /* 245 */ 0x0aa29c75cc2e6c90UL, 0xfc7d73ca3a70e206UL, +- 0x899fc38fc4b5c515UL, 0x250386b124ffc207UL, +- /* 246 */ 0x54ea28d5ae3d2b56UL, 0x9913149dd6de60ceUL, +- 0x16694fc58f06d6c1UL, 0x46b23975eb018fc7UL, +- /* 247 */ 0x470a6a0fb4b7b4e2UL, 0x5d92475a8f7253deUL, +- 0xabeee5b52fbd3adbUL, 0x7fa20801a0806968UL, +- /* 248 */ 0x76f3faf19f7714d2UL, 0xb3e840c12f4660c3UL, +- 0x0fb4cd8df212744eUL, 0x4b065a251d3a2dd2UL, +- /* 249 */ 0x5cebde383d77cd4aUL, 0x6adf39df882c9cb1UL, +- 0xa2dd242eb09af759UL, 0x3147c0e50e5f6422UL, +- /* 250 */ 0x164ca5101d1350dbUL, 0xf8d13479c33fc962UL, +- 0xe640ce4d13e5da08UL, 0x4bdee0c45061f8baUL, +- /* 251 */ 0xd7c46dc1a4edb1c9UL, 0x5514d7b6437fd98aUL, +- 0x58942f6bb2a1c00bUL, 0x2dffb2ab1d70710eUL, +- /* 252 */ 0xccdfcf2fc18b6d68UL, 0xa8ebcba8b7806167UL, +- 0x980697f95e2937e3UL, 0x02fbba1cd0126e8cUL +-}; +- +-/* c is two 512-bit products: c0[0:7]=a0[0:3]*b0[0:3] and c1[8:15]=a1[4:7]*b1[4:7] +- * a is two 256-bit integers: a0[0:3] and a1[4:7] +- * b is two 256-bit integers: b0[0:3] and b1[4:7] +- */ +-static void mul2_256x256_integer_adx(u64 *const c, const u64 *const a, +- const u64 *const b) +-{ +- asm volatile( +- "xorl %%r14d, %%r14d ;" +- "movq (%1), %%rdx; " /* A[0] */ +- "mulx (%2), %%r8, %%r15; " /* A[0]*B[0] */ +- "xorl %%r10d, %%r10d ;" +- "movq %%r8, (%0) ;" +- "mulx 8(%2), %%r10, %%rax; " /* A[0]*B[1] */ +- "adox %%r10, %%r15 ;" +- "mulx 16(%2), %%r8, %%rbx; " /* A[0]*B[2] */ +- "adox %%r8, %%rax ;" +- "mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */ +- "adox %%r10, %%rbx ;" +- /******************************************/ +- "adox %%r14, %%rcx ;" +- +- "movq 8(%1), %%rdx; " /* A[1] */ +- "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ +- "adox %%r15, %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ +- "adox %%r10, %%r9 ;" +- "adcx %%r9, %%rax ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[1]*B[2] */ +- "adox %%r8, %%r11 ;" +- "adcx %%r11, %%rbx ;" +- "mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */ +- "adox %%r10, %%r13 ;" +- "adcx %%r13, %%rcx ;" +- /******************************************/ +- "adox %%r14, %%r15 ;" +- "adcx %%r14, %%r15 ;" +- +- "movq 16(%1), %%rdx; " /* A[2] */ +- "xorl %%r10d, %%r10d ;" +- "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ +- "adox %%rax, %%r8 ;" +- "movq %%r8, 16(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ +- "adox %%r10, %%r9 ;" +- "adcx %%r9, %%rbx ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[2]*B[2] */ +- "adox %%r8, %%r11 ;" +- "adcx %%r11, %%rcx ;" +- "mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */ +- "adox %%r10, %%r13 ;" +- "adcx %%r13, %%r15 ;" +- /******************************************/ +- "adox %%r14, %%rax ;" +- "adcx %%r14, %%rax ;" +- +- "movq 24(%1), %%rdx; " /* A[3] */ +- "xorl %%r10d, %%r10d ;" +- "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ +- "adox %%rbx, %%r8 ;" +- "movq %%r8, 24(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ +- "adox %%r10, %%r9 ;" +- "adcx %%r9, %%rcx ;" +- "movq %%rcx, 32(%0) ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[3]*B[2] */ +- "adox %%r8, %%r11 ;" +- "adcx %%r11, %%r15 ;" +- "movq %%r15, 40(%0) ;" +- "mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */ +- "adox %%r10, %%r13 ;" +- "adcx %%r13, %%rax ;" +- "movq %%rax, 48(%0) ;" +- /******************************************/ +- "adox %%r14, %%rbx ;" +- "adcx %%r14, %%rbx ;" +- "movq %%rbx, 56(%0) ;" +- +- "movq 32(%1), %%rdx; " /* C[0] */ +- "mulx 32(%2), %%r8, %%r15; " /* C[0]*D[0] */ +- "xorl %%r10d, %%r10d ;" +- "movq %%r8, 64(%0);" +- "mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */ +- "adox %%r10, %%r15 ;" +- "mulx 48(%2), %%r8, %%rbx; " /* C[0]*D[2] */ +- "adox %%r8, %%rax ;" +- "mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */ +- "adox %%r10, %%rbx ;" +- /******************************************/ +- "adox %%r14, %%rcx ;" +- +- "movq 40(%1), %%rdx; " /* C[1] */ +- "xorl %%r10d, %%r10d ;" +- "mulx 32(%2), %%r8, %%r9; " /* C[1]*D[0] */ +- "adox %%r15, %%r8 ;" +- "movq %%r8, 72(%0);" +- "mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */ +- "adox %%r10, %%r9 ;" +- "adcx %%r9, %%rax ;" +- "mulx 48(%2), %%r8, %%r13; " /* C[1]*D[2] */ +- "adox %%r8, %%r11 ;" +- "adcx %%r11, %%rbx ;" +- "mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */ +- "adox %%r10, %%r13 ;" +- "adcx %%r13, %%rcx ;" +- /******************************************/ +- "adox %%r14, %%r15 ;" +- "adcx %%r14, %%r15 ;" +- +- "movq 48(%1), %%rdx; " /* C[2] */ +- "xorl %%r10d, %%r10d ;" +- "mulx 32(%2), %%r8, %%r9; " /* C[2]*D[0] */ +- "adox %%rax, %%r8 ;" +- "movq %%r8, 80(%0);" +- "mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */ +- "adox %%r10, %%r9 ;" +- "adcx %%r9, %%rbx ;" +- "mulx 48(%2), %%r8, %%r13; " /* C[2]*D[2] */ +- "adox %%r8, %%r11 ;" +- "adcx %%r11, %%rcx ;" +- "mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */ +- "adox %%r10, %%r13 ;" +- "adcx %%r13, %%r15 ;" +- /******************************************/ +- "adox %%r14, %%rax ;" +- "adcx %%r14, %%rax ;" +- +- "movq 56(%1), %%rdx; " /* C[3] */ +- "xorl %%r10d, %%r10d ;" +- "mulx 32(%2), %%r8, %%r9; " /* C[3]*D[0] */ +- "adox %%rbx, %%r8 ;" +- "movq %%r8, 88(%0);" +- "mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */ +- "adox %%r10, %%r9 ;" +- "adcx %%r9, %%rcx ;" +- "movq %%rcx, 96(%0) ;" +- "mulx 48(%2), %%r8, %%r13; " /* C[3]*D[2] */ +- "adox %%r8, %%r11 ;" +- "adcx %%r11, %%r15 ;" +- "movq %%r15, 104(%0) ;" +- "mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */ +- "adox %%r10, %%r13 ;" +- "adcx %%r13, %%rax ;" +- "movq %%rax, 112(%0) ;" +- /******************************************/ +- "adox %%r14, %%rbx ;" +- "adcx %%r14, %%rbx ;" +- "movq %%rbx, 120(%0) ;" +- : +- : "r"(c), "r"(a), "r"(b) +- : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", +- "%r10", "%r11", "%r13", "%r14", "%r15"); +-} +- +-static void mul2_256x256_integer_bmi2(u64 *const c, const u64 *const a, +- const u64 *const b) ++static __always_inline u64 eq_mask(u64 a, u64 b) + { +- asm volatile( +- "movq (%1), %%rdx; " /* A[0] */ +- "mulx (%2), %%r8, %%r15; " /* A[0]*B[0] */ +- "movq %%r8, (%0) ;" +- "mulx 8(%2), %%r10, %%rax; " /* A[0]*B[1] */ +- "addq %%r10, %%r15 ;" +- "mulx 16(%2), %%r8, %%rbx; " /* A[0]*B[2] */ +- "adcq %%r8, %%rax ;" +- "mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */ +- "adcq %%r10, %%rbx ;" +- /******************************************/ +- "adcq $0, %%rcx ;" +- +- "movq 8(%1), %%rdx; " /* A[1] */ +- "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ +- "addq %%r15, %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[1]*B[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%r15 ;" +- +- "addq %%r9, %%rax ;" +- "adcq %%r11, %%rbx ;" +- "adcq %%r13, %%rcx ;" +- "adcq $0, %%r15 ;" +- +- "movq 16(%1), %%rdx; " /* A[2] */ +- "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ +- "addq %%rax, %%r8 ;" +- "movq %%r8, 16(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[2]*B[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%rax ;" +- +- "addq %%r9, %%rbx ;" +- "adcq %%r11, %%rcx ;" +- "adcq %%r13, %%r15 ;" +- "adcq $0, %%rax ;" +- +- "movq 24(%1), %%rdx; " /* A[3] */ +- "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ +- "addq %%rbx, %%r8 ;" +- "movq %%r8, 24(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[3]*B[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%rbx ;" +- +- "addq %%r9, %%rcx ;" +- "movq %%rcx, 32(%0) ;" +- "adcq %%r11, %%r15 ;" +- "movq %%r15, 40(%0) ;" +- "adcq %%r13, %%rax ;" +- "movq %%rax, 48(%0) ;" +- "adcq $0, %%rbx ;" +- "movq %%rbx, 56(%0) ;" +- +- "movq 32(%1), %%rdx; " /* C[0] */ +- "mulx 32(%2), %%r8, %%r15; " /* C[0]*D[0] */ +- "movq %%r8, 64(%0) ;" +- "mulx 40(%2), %%r10, %%rax; " /* C[0]*D[1] */ +- "addq %%r10, %%r15 ;" +- "mulx 48(%2), %%r8, %%rbx; " /* C[0]*D[2] */ +- "adcq %%r8, %%rax ;" +- "mulx 56(%2), %%r10, %%rcx; " /* C[0]*D[3] */ +- "adcq %%r10, %%rbx ;" +- /******************************************/ +- "adcq $0, %%rcx ;" +- +- "movq 40(%1), %%rdx; " /* C[1] */ +- "mulx 32(%2), %%r8, %%r9; " /* C[1]*D[0] */ +- "addq %%r15, %%r8 ;" +- "movq %%r8, 72(%0) ;" +- "mulx 40(%2), %%r10, %%r11; " /* C[1]*D[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 48(%2), %%r8, %%r13; " /* C[1]*D[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 56(%2), %%r10, %%r15; " /* C[1]*D[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%r15 ;" +- +- "addq %%r9, %%rax ;" +- "adcq %%r11, %%rbx ;" +- "adcq %%r13, %%rcx ;" +- "adcq $0, %%r15 ;" +- +- "movq 48(%1), %%rdx; " /* C[2] */ +- "mulx 32(%2), %%r8, %%r9; " /* C[2]*D[0] */ +- "addq %%rax, %%r8 ;" +- "movq %%r8, 80(%0) ;" +- "mulx 40(%2), %%r10, %%r11; " /* C[2]*D[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 48(%2), %%r8, %%r13; " /* C[2]*D[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 56(%2), %%r10, %%rax; " /* C[2]*D[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%rax ;" +- +- "addq %%r9, %%rbx ;" +- "adcq %%r11, %%rcx ;" +- "adcq %%r13, %%r15 ;" +- "adcq $0, %%rax ;" +- +- "movq 56(%1), %%rdx; " /* C[3] */ +- "mulx 32(%2), %%r8, %%r9; " /* C[3]*D[0] */ +- "addq %%rbx, %%r8 ;" +- "movq %%r8, 88(%0) ;" +- "mulx 40(%2), %%r10, %%r11; " /* C[3]*D[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 48(%2), %%r8, %%r13; " /* C[3]*D[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 56(%2), %%r10, %%rbx; " /* C[3]*D[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%rbx ;" +- +- "addq %%r9, %%rcx ;" +- "movq %%rcx, 96(%0) ;" +- "adcq %%r11, %%r15 ;" +- "movq %%r15, 104(%0) ;" +- "adcq %%r13, %%rax ;" +- "movq %%rax, 112(%0) ;" +- "adcq $0, %%rbx ;" +- "movq %%rbx, 120(%0) ;" +- : +- : "r"(c), "r"(a), "r"(b) +- : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", +- "%r10", "%r11", "%r13", "%r15"); ++ u64 x = a ^ b; ++ u64 minus_x = ~x + (u64)1U; ++ u64 x_or_minus_x = x | minus_x; ++ u64 xnx = x_or_minus_x >> (u32)63U; ++ return xnx - (u64)1U; + } + +-static void sqr2_256x256_integer_adx(u64 *const c, const u64 *const a) ++static __always_inline u64 gte_mask(u64 a, u64 b) + { +- asm volatile( +- "movq (%1), %%rdx ;" /* A[0] */ +- "mulx 8(%1), %%r8, %%r14 ;" /* A[1]*A[0] */ +- "xorl %%r15d, %%r15d;" +- "mulx 16(%1), %%r9, %%r10 ;" /* A[2]*A[0] */ +- "adcx %%r14, %%r9 ;" +- "mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */ +- "adcx %%rax, %%r10 ;" +- "movq 24(%1), %%rdx ;" /* A[3] */ +- "mulx 8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */ +- "adcx %%rcx, %%r11 ;" +- "mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */ +- "adcx %%rax, %%rbx ;" +- "movq 8(%1), %%rdx ;" /* A[1] */ +- "adcx %%r15, %%r13 ;" +- "mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */ +- "movq $0, %%r14 ;" +- /******************************************/ +- "adcx %%r15, %%r14 ;" +- +- "xorl %%r15d, %%r15d;" +- "adox %%rax, %%r10 ;" +- "adcx %%r8, %%r8 ;" +- "adox %%rcx, %%r11 ;" +- "adcx %%r9, %%r9 ;" +- "adox %%r15, %%rbx ;" +- "adcx %%r10, %%r10 ;" +- "adox %%r15, %%r13 ;" +- "adcx %%r11, %%r11 ;" +- "adox %%r15, %%r14 ;" +- "adcx %%rbx, %%rbx ;" +- "adcx %%r13, %%r13 ;" +- "adcx %%r14, %%r14 ;" +- +- "movq (%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */ +- /*******************/ +- "movq %%rax, 0(%0) ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "movq 8(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */ +- "adcq %%rax, %%r9 ;" +- "movq %%r9, 16(%0) ;" +- "adcq %%rcx, %%r10 ;" +- "movq %%r10, 24(%0) ;" +- "movq 16(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */ +- "adcq %%rax, %%r11 ;" +- "movq %%r11, 32(%0) ;" +- "adcq %%rcx, %%rbx ;" +- "movq %%rbx, 40(%0) ;" +- "movq 24(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */ +- "adcq %%rax, %%r13 ;" +- "movq %%r13, 48(%0) ;" +- "adcq %%rcx, %%r14 ;" +- "movq %%r14, 56(%0) ;" +- +- +- "movq 32(%1), %%rdx ;" /* B[0] */ +- "mulx 40(%1), %%r8, %%r14 ;" /* B[1]*B[0] */ +- "xorl %%r15d, %%r15d;" +- "mulx 48(%1), %%r9, %%r10 ;" /* B[2]*B[0] */ +- "adcx %%r14, %%r9 ;" +- "mulx 56(%1), %%rax, %%rcx ;" /* B[3]*B[0] */ +- "adcx %%rax, %%r10 ;" +- "movq 56(%1), %%rdx ;" /* B[3] */ +- "mulx 40(%1), %%r11, %%rbx ;" /* B[1]*B[3] */ +- "adcx %%rcx, %%r11 ;" +- "mulx 48(%1), %%rax, %%r13 ;" /* B[2]*B[3] */ +- "adcx %%rax, %%rbx ;" +- "movq 40(%1), %%rdx ;" /* B[1] */ +- "adcx %%r15, %%r13 ;" +- "mulx 48(%1), %%rax, %%rcx ;" /* B[2]*B[1] */ +- "movq $0, %%r14 ;" +- /******************************************/ +- "adcx %%r15, %%r14 ;" +- +- "xorl %%r15d, %%r15d;" +- "adox %%rax, %%r10 ;" +- "adcx %%r8, %%r8 ;" +- "adox %%rcx, %%r11 ;" +- "adcx %%r9, %%r9 ;" +- "adox %%r15, %%rbx ;" +- "adcx %%r10, %%r10 ;" +- "adox %%r15, %%r13 ;" +- "adcx %%r11, %%r11 ;" +- "adox %%r15, %%r14 ;" +- "adcx %%rbx, %%rbx ;" +- "adcx %%r13, %%r13 ;" +- "adcx %%r14, %%r14 ;" +- +- "movq 32(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* B[0]^2 */ +- /*******************/ +- "movq %%rax, 64(%0) ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 72(%0) ;" +- "movq 40(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* B[1]^2 */ +- "adcq %%rax, %%r9 ;" +- "movq %%r9, 80(%0) ;" +- "adcq %%rcx, %%r10 ;" +- "movq %%r10, 88(%0) ;" +- "movq 48(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* B[2]^2 */ +- "adcq %%rax, %%r11 ;" +- "movq %%r11, 96(%0) ;" +- "adcq %%rcx, %%rbx ;" +- "movq %%rbx, 104(%0) ;" +- "movq 56(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* B[3]^2 */ +- "adcq %%rax, %%r13 ;" +- "movq %%r13, 112(%0) ;" +- "adcq %%rcx, %%r14 ;" +- "movq %%r14, 120(%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", +- "%r10", "%r11", "%r13", "%r14", "%r15"); ++ u64 x = a; ++ u64 y = b; ++ u64 x_xor_y = x ^ y; ++ u64 x_sub_y = x - y; ++ u64 x_sub_y_xor_y = x_sub_y ^ y; ++ u64 q = x_xor_y | x_sub_y_xor_y; ++ u64 x_xor_q = x ^ q; ++ u64 x_xor_q_ = x_xor_q >> (u32)63U; ++ return x_xor_q_ - (u64)1U; + } + +-static void sqr2_256x256_integer_bmi2(u64 *const c, const u64 *const a) ++/* Computes the addition of four-element f1 with value in f2 ++ * and returns the carry (if any) */ ++static inline u64 add_scalar(u64 *out, const u64 *f1, u64 f2) + { +- asm volatile( +- "movq 8(%1), %%rdx ;" /* A[1] */ +- "mulx (%1), %%r8, %%r9 ;" /* A[0]*A[1] */ +- "mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */ +- "mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */ +- +- "movq 16(%1), %%rdx ;" /* A[2] */ +- "mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */ +- "mulx (%1), %%rax, %%rdx ;" /* A[0]*A[2] */ +- +- "addq %%rax, %%r9 ;" +- "adcq %%rdx, %%r10 ;" +- "adcq %%rcx, %%r11 ;" +- "adcq %%r14, %%r15 ;" +- "adcq $0, %%r13 ;" +- "movq $0, %%r14 ;" +- "adcq $0, %%r14 ;" +- +- "movq (%1), %%rdx ;" /* A[0] */ +- "mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */ +- +- "addq %%rax, %%r10 ;" +- "adcq %%rcx, %%r11 ;" +- "adcq $0, %%r15 ;" +- "adcq $0, %%r13 ;" +- "adcq $0, %%r14 ;" +- +- "shldq $1, %%r13, %%r14 ;" +- "shldq $1, %%r15, %%r13 ;" +- "shldq $1, %%r11, %%r15 ;" +- "shldq $1, %%r10, %%r11 ;" +- "shldq $1, %%r9, %%r10 ;" +- "shldq $1, %%r8, %%r9 ;" +- "shlq $1, %%r8 ;" +- +- /*******************/ +- "mulx %%rdx, %%rax, %%rcx ; " /* A[0]^2 */ +- /*******************/ +- "movq %%rax, 0(%0) ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "movq 8(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ; " /* A[1]^2 */ +- "adcq %%rax, %%r9 ;" +- "movq %%r9, 16(%0) ;" +- "adcq %%rcx, %%r10 ;" +- "movq %%r10, 24(%0) ;" +- "movq 16(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ; " /* A[2]^2 */ +- "adcq %%rax, %%r11 ;" +- "movq %%r11, 32(%0) ;" +- "adcq %%rcx, %%r15 ;" +- "movq %%r15, 40(%0) ;" +- "movq 24(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ; " /* A[3]^2 */ +- "adcq %%rax, %%r13 ;" +- "movq %%r13, 48(%0) ;" +- "adcq %%rcx, %%r14 ;" +- "movq %%r14, 56(%0) ;" +- +- "movq 40(%1), %%rdx ;" /* B[1] */ +- "mulx 32(%1), %%r8, %%r9 ;" /* B[0]*B[1] */ +- "mulx 48(%1), %%r10, %%r11 ;" /* B[2]*B[1] */ +- "mulx 56(%1), %%rcx, %%r14 ;" /* B[3]*B[1] */ +- +- "movq 48(%1), %%rdx ;" /* B[2] */ +- "mulx 56(%1), %%r15, %%r13 ;" /* B[3]*B[2] */ +- "mulx 32(%1), %%rax, %%rdx ;" /* B[0]*B[2] */ +- +- "addq %%rax, %%r9 ;" +- "adcq %%rdx, %%r10 ;" +- "adcq %%rcx, %%r11 ;" +- "adcq %%r14, %%r15 ;" +- "adcq $0, %%r13 ;" +- "movq $0, %%r14 ;" +- "adcq $0, %%r14 ;" +- +- "movq 32(%1), %%rdx ;" /* B[0] */ +- "mulx 56(%1), %%rax, %%rcx ;" /* B[0]*B[3] */ +- +- "addq %%rax, %%r10 ;" +- "adcq %%rcx, %%r11 ;" +- "adcq $0, %%r15 ;" +- "adcq $0, %%r13 ;" +- "adcq $0, %%r14 ;" +- +- "shldq $1, %%r13, %%r14 ;" +- "shldq $1, %%r15, %%r13 ;" +- "shldq $1, %%r11, %%r15 ;" +- "shldq $1, %%r10, %%r11 ;" +- "shldq $1, %%r9, %%r10 ;" +- "shldq $1, %%r8, %%r9 ;" +- "shlq $1, %%r8 ;" +- +- /*******************/ +- "mulx %%rdx, %%rax, %%rcx ; " /* B[0]^2 */ +- /*******************/ +- "movq %%rax, 64(%0) ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 72(%0) ;" +- "movq 40(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ; " /* B[1]^2 */ +- "adcq %%rax, %%r9 ;" +- "movq %%r9, 80(%0) ;" +- "adcq %%rcx, %%r10 ;" +- "movq %%r10, 88(%0) ;" +- "movq 48(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ; " /* B[2]^2 */ +- "adcq %%rax, %%r11 ;" +- "movq %%r11, 96(%0) ;" +- "adcq %%rcx, %%r15 ;" +- "movq %%r15, 104(%0) ;" +- "movq 56(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ; " /* B[3]^2 */ +- "adcq %%rax, %%r13 ;" +- "movq %%r13, 112(%0) ;" +- "adcq %%rcx, %%r14 ;" +- "movq %%r14, 120(%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", +- "%r11", "%r13", "%r14", "%r15"); +-} ++ u64 carry_r; + +-static void red_eltfp25519_2w_adx(u64 *const c, const u64 *const a) +-{ + asm volatile( +- "movl $38, %%edx; " /* 2*c = 38 = 2^256 */ +- "mulx 32(%1), %%r8, %%r10; " /* c*C[4] */ +- "xorl %%ebx, %%ebx ;" +- "adox (%1), %%r8 ;" +- "mulx 40(%1), %%r9, %%r11; " /* c*C[5] */ +- "adcx %%r10, %%r9 ;" +- "adox 8(%1), %%r9 ;" +- "mulx 48(%1), %%r10, %%rax; " /* c*C[6] */ +- "adcx %%r11, %%r10 ;" +- "adox 16(%1), %%r10 ;" +- "mulx 56(%1), %%r11, %%rcx; " /* c*C[7] */ +- "adcx %%rax, %%r11 ;" +- "adox 24(%1), %%r11 ;" +- /***************************************/ +- "adcx %%rbx, %%rcx ;" +- "adox %%rbx, %%rcx ;" +- "imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */ +- "adcx %%rcx, %%r8 ;" +- "adcx %%rbx, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "adcx %%rbx, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "adcx %%rbx, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%edx, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, (%0) ;" +- +- "mulx 96(%1), %%r8, %%r10; " /* c*C[4] */ +- "xorl %%ebx, %%ebx ;" +- "adox 64(%1), %%r8 ;" +- "mulx 104(%1), %%r9, %%r11; " /* c*C[5] */ +- "adcx %%r10, %%r9 ;" +- "adox 72(%1), %%r9 ;" +- "mulx 112(%1), %%r10, %%rax; " /* c*C[6] */ +- "adcx %%r11, %%r10 ;" +- "adox 80(%1), %%r10 ;" +- "mulx 120(%1), %%r11, %%rcx; " /* c*C[7] */ +- "adcx %%rax, %%r11 ;" +- "adox 88(%1), %%r11 ;" +- /****************************************/ +- "adcx %%rbx, %%rcx ;" +- "adox %%rbx, %%rcx ;" +- "imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */ +- "adcx %%rcx, %%r8 ;" +- "adcx %%rbx, %%r9 ;" +- "movq %%r9, 40(%0) ;" +- "adcx %%rbx, %%r10 ;" +- "movq %%r10, 48(%0) ;" +- "adcx %%rbx, %%r11 ;" +- "movq %%r11, 56(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%edx, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 32(%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", +- "%r10", "%r11"); +-} ++ /* Clear registers to propagate the carry bit */ ++ " xor %%r8, %%r8;" ++ " xor %%r9, %%r9;" ++ " xor %%r10, %%r10;" ++ " xor %%r11, %%r11;" ++ " xor %1, %1;" ++ ++ /* Begin addition chain */ ++ " addq 0(%3), %0;" ++ " movq %0, 0(%2);" ++ " adcxq 8(%3), %%r8;" ++ " movq %%r8, 8(%2);" ++ " adcxq 16(%3), %%r9;" ++ " movq %%r9, 16(%2);" ++ " adcxq 24(%3), %%r10;" ++ " movq %%r10, 24(%2);" ++ ++ /* Return the carry bit in a register */ ++ " adcx %%r11, %1;" ++ : "+&r" (f2), "=&r" (carry_r) ++ : "r" (out), "r" (f1) ++ : "%r8", "%r9", "%r10", "%r11", "memory", "cc" ++ ); + +-static void red_eltfp25519_2w_bmi2(u64 *const c, const u64 *const a) +-{ +- asm volatile( +- "movl $38, %%edx ; " /* 2*c = 38 = 2^256 */ +- "mulx 32(%1), %%r8, %%r10 ;" /* c*C[4] */ +- "mulx 40(%1), %%r9, %%r11 ;" /* c*C[5] */ +- "addq %%r10, %%r9 ;" +- "mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */ +- "adcq %%r11, %%r10 ;" +- "mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */ +- "adcq %%rax, %%r11 ;" +- /***************************************/ +- "adcq $0, %%rcx ;" +- "addq (%1), %%r8 ;" +- "adcq 8(%1), %%r9 ;" +- "adcq 16(%1), %%r10 ;" +- "adcq 24(%1), %%r11 ;" +- "adcq $0, %%rcx ;" +- "imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */ +- "addq %%rcx, %%r8 ;" +- "adcq $0, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "adcq $0, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "adcq $0, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%edx, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, (%0) ;" +- +- "mulx 96(%1), %%r8, %%r10 ;" /* c*C[4] */ +- "mulx 104(%1), %%r9, %%r11 ;" /* c*C[5] */ +- "addq %%r10, %%r9 ;" +- "mulx 112(%1), %%r10, %%rax ;" /* c*C[6] */ +- "adcq %%r11, %%r10 ;" +- "mulx 120(%1), %%r11, %%rcx ;" /* c*C[7] */ +- "adcq %%rax, %%r11 ;" +- /****************************************/ +- "adcq $0, %%rcx ;" +- "addq 64(%1), %%r8 ;" +- "adcq 72(%1), %%r9 ;" +- "adcq 80(%1), %%r10 ;" +- "adcq 88(%1), %%r11 ;" +- "adcq $0, %%rcx ;" +- "imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */ +- "addq %%rcx, %%r8 ;" +- "adcq $0, %%r9 ;" +- "movq %%r9, 40(%0) ;" +- "adcq $0, %%r10 ;" +- "movq %%r10, 48(%0) ;" +- "adcq $0, %%r11 ;" +- "movq %%r11, 56(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%edx, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 32(%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", +- "%r11"); ++ return carry_r; + } + +-static void mul_256x256_integer_adx(u64 *const c, const u64 *const a, +- const u64 *const b) ++/* Computes the field addition of two field elements */ ++static inline void fadd(u64 *out, const u64 *f1, const u64 *f2) + { + asm volatile( +- "movq (%1), %%rdx; " /* A[0] */ +- "mulx (%2), %%r8, %%r9; " /* A[0]*B[0] */ +- "xorl %%r10d, %%r10d ;" +- "movq %%r8, (%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[0]*B[1] */ +- "adox %%r9, %%r10 ;" +- "movq %%r10, 8(%0) ;" +- "mulx 16(%2), %%r15, %%r13; " /* A[0]*B[2] */ +- "adox %%r11, %%r15 ;" +- "mulx 24(%2), %%r14, %%rdx; " /* A[0]*B[3] */ +- "adox %%r13, %%r14 ;" +- "movq $0, %%rax ;" +- /******************************************/ +- "adox %%rdx, %%rax ;" +- +- "movq 8(%1), %%rdx; " /* A[1] */ +- "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ +- "xorl %%r10d, %%r10d ;" +- "adcx 8(%0), %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ +- "adox %%r9, %%r10 ;" +- "adcx %%r15, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "mulx 16(%2), %%r15, %%r13; " /* A[1]*B[2] */ +- "adox %%r11, %%r15 ;" +- "adcx %%r14, %%r15 ;" +- "movq $0, %%r8 ;" +- "mulx 24(%2), %%r14, %%rdx; " /* A[1]*B[3] */ +- "adox %%r13, %%r14 ;" +- "adcx %%rax, %%r14 ;" +- "movq $0, %%rax ;" +- /******************************************/ +- "adox %%rdx, %%rax ;" +- "adcx %%r8, %%rax ;" +- +- "movq 16(%1), %%rdx; " /* A[2] */ +- "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ +- "xorl %%r10d, %%r10d ;" +- "adcx 16(%0), %%r8 ;" +- "movq %%r8, 16(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ +- "adox %%r9, %%r10 ;" +- "adcx %%r15, %%r10 ;" +- "movq %%r10, 24(%0) ;" +- "mulx 16(%2), %%r15, %%r13; " /* A[2]*B[2] */ +- "adox %%r11, %%r15 ;" +- "adcx %%r14, %%r15 ;" +- "movq $0, %%r8 ;" +- "mulx 24(%2), %%r14, %%rdx; " /* A[2]*B[3] */ +- "adox %%r13, %%r14 ;" +- "adcx %%rax, %%r14 ;" +- "movq $0, %%rax ;" +- /******************************************/ +- "adox %%rdx, %%rax ;" +- "adcx %%r8, %%rax ;" +- +- "movq 24(%1), %%rdx; " /* A[3] */ +- "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ +- "xorl %%r10d, %%r10d ;" +- "adcx 24(%0), %%r8 ;" +- "movq %%r8, 24(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ +- "adox %%r9, %%r10 ;" +- "adcx %%r15, %%r10 ;" +- "movq %%r10, 32(%0) ;" +- "mulx 16(%2), %%r15, %%r13; " /* A[3]*B[2] */ +- "adox %%r11, %%r15 ;" +- "adcx %%r14, %%r15 ;" +- "movq %%r15, 40(%0) ;" +- "movq $0, %%r8 ;" +- "mulx 24(%2), %%r14, %%rdx; " /* A[3]*B[3] */ +- "adox %%r13, %%r14 ;" +- "adcx %%rax, %%r14 ;" +- "movq %%r14, 48(%0) ;" +- "movq $0, %%rax ;" +- /******************************************/ +- "adox %%rdx, %%rax ;" +- "adcx %%r8, %%rax ;" +- "movq %%rax, 56(%0) ;" +- : +- : "r"(c), "r"(a), "r"(b) +- : "memory", "cc", "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", +- "%r13", "%r14", "%r15"); ++ /* Compute the raw addition of f1 + f2 */ ++ " movq 0(%0), %%r8;" ++ " addq 0(%2), %%r8;" ++ " movq 8(%0), %%r9;" ++ " adcxq 8(%2), %%r9;" ++ " movq 16(%0), %%r10;" ++ " adcxq 16(%2), %%r10;" ++ " movq 24(%0), %%r11;" ++ " adcxq 24(%2), %%r11;" ++ ++ /* Wrap the result back into the field */ ++ ++ /* Step 1: Compute carry*38 */ ++ " mov $0, %%rax;" ++ " mov $38, %0;" ++ " cmovc %0, %%rax;" ++ ++ /* Step 2: Add carry*38 to the original sum */ ++ " xor %%rcx, %%rcx;" ++ " add %%rax, %%r8;" ++ " adcx %%rcx, %%r9;" ++ " movq %%r9, 8(%1);" ++ " adcx %%rcx, %%r10;" ++ " movq %%r10, 16(%1);" ++ " adcx %%rcx, %%r11;" ++ " movq %%r11, 24(%1);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %0, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 0(%1);" ++ : "+&r" (f2) ++ : "r" (out), "r" (f1) ++ : "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "memory", "cc" ++ ); + } + +-static void mul_256x256_integer_bmi2(u64 *const c, const u64 *const a, +- const u64 *const b) ++/* Computes the field substraction of two field elements */ ++static inline void fsub(u64 *out, const u64 *f1, const u64 *f2) + { + asm volatile( +- "movq (%1), %%rdx; " /* A[0] */ +- "mulx (%2), %%r8, %%r15; " /* A[0]*B[0] */ +- "movq %%r8, (%0) ;" +- "mulx 8(%2), %%r10, %%rax; " /* A[0]*B[1] */ +- "addq %%r10, %%r15 ;" +- "mulx 16(%2), %%r8, %%rbx; " /* A[0]*B[2] */ +- "adcq %%r8, %%rax ;" +- "mulx 24(%2), %%r10, %%rcx; " /* A[0]*B[3] */ +- "adcq %%r10, %%rbx ;" +- /******************************************/ +- "adcq $0, %%rcx ;" +- +- "movq 8(%1), %%rdx; " /* A[1] */ +- "mulx (%2), %%r8, %%r9; " /* A[1]*B[0] */ +- "addq %%r15, %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[1]*B[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[1]*B[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 24(%2), %%r10, %%r15; " /* A[1]*B[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%r15 ;" +- +- "addq %%r9, %%rax ;" +- "adcq %%r11, %%rbx ;" +- "adcq %%r13, %%rcx ;" +- "adcq $0, %%r15 ;" +- +- "movq 16(%1), %%rdx; " /* A[2] */ +- "mulx (%2), %%r8, %%r9; " /* A[2]*B[0] */ +- "addq %%rax, %%r8 ;" +- "movq %%r8, 16(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[2]*B[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[2]*B[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 24(%2), %%r10, %%rax; " /* A[2]*B[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%rax ;" +- +- "addq %%r9, %%rbx ;" +- "adcq %%r11, %%rcx ;" +- "adcq %%r13, %%r15 ;" +- "adcq $0, %%rax ;" +- +- "movq 24(%1), %%rdx; " /* A[3] */ +- "mulx (%2), %%r8, %%r9; " /* A[3]*B[0] */ +- "addq %%rbx, %%r8 ;" +- "movq %%r8, 24(%0) ;" +- "mulx 8(%2), %%r10, %%r11; " /* A[3]*B[1] */ +- "adcq %%r10, %%r9 ;" +- "mulx 16(%2), %%r8, %%r13; " /* A[3]*B[2] */ +- "adcq %%r8, %%r11 ;" +- "mulx 24(%2), %%r10, %%rbx; " /* A[3]*B[3] */ +- "adcq %%r10, %%r13 ;" +- /******************************************/ +- "adcq $0, %%rbx ;" +- +- "addq %%r9, %%rcx ;" +- "movq %%rcx, 32(%0) ;" +- "adcq %%r11, %%r15 ;" +- "movq %%r15, 40(%0) ;" +- "adcq %%r13, %%rax ;" +- "movq %%rax, 48(%0) ;" +- "adcq $0, %%rbx ;" +- "movq %%rbx, 56(%0) ;" +- : +- : "r"(c), "r"(a), "r"(b) +- : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", +- "%r10", "%r11", "%r13", "%r15"); ++ /* Compute the raw substraction of f1-f2 */ ++ " movq 0(%1), %%r8;" ++ " subq 0(%2), %%r8;" ++ " movq 8(%1), %%r9;" ++ " sbbq 8(%2), %%r9;" ++ " movq 16(%1), %%r10;" ++ " sbbq 16(%2), %%r10;" ++ " movq 24(%1), %%r11;" ++ " sbbq 24(%2), %%r11;" ++ ++ /* Wrap the result back into the field */ ++ ++ /* Step 1: Compute carry*38 */ ++ " mov $0, %%rax;" ++ " mov $38, %%rcx;" ++ " cmovc %%rcx, %%rax;" ++ ++ /* Step 2: Substract carry*38 from the original difference */ ++ " sub %%rax, %%r8;" ++ " sbb $0, %%r9;" ++ " sbb $0, %%r10;" ++ " sbb $0, %%r11;" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rcx, %%rax;" ++ " sub %%rax, %%r8;" ++ ++ /* Store the result */ ++ " movq %%r8, 0(%0);" ++ " movq %%r9, 8(%0);" ++ " movq %%r10, 16(%0);" ++ " movq %%r11, 24(%0);" ++ : ++ : "r" (out), "r" (f1), "r" (f2) ++ : "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "memory", "cc" ++ ); + } + +-static void sqr_256x256_integer_adx(u64 *const c, const u64 *const a) ++/* Computes a field multiplication: out <- f1 * f2 ++ * Uses the 8-element buffer tmp for intermediate results */ ++static inline void fmul(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp) + { + asm volatile( +- "movq (%1), %%rdx ;" /* A[0] */ +- "mulx 8(%1), %%r8, %%r14 ;" /* A[1]*A[0] */ +- "xorl %%r15d, %%r15d;" +- "mulx 16(%1), %%r9, %%r10 ;" /* A[2]*A[0] */ +- "adcx %%r14, %%r9 ;" +- "mulx 24(%1), %%rax, %%rcx ;" /* A[3]*A[0] */ +- "adcx %%rax, %%r10 ;" +- "movq 24(%1), %%rdx ;" /* A[3] */ +- "mulx 8(%1), %%r11, %%rbx ;" /* A[1]*A[3] */ +- "adcx %%rcx, %%r11 ;" +- "mulx 16(%1), %%rax, %%r13 ;" /* A[2]*A[3] */ +- "adcx %%rax, %%rbx ;" +- "movq 8(%1), %%rdx ;" /* A[1] */ +- "adcx %%r15, %%r13 ;" +- "mulx 16(%1), %%rax, %%rcx ;" /* A[2]*A[1] */ +- "movq $0, %%r14 ;" +- /******************************************/ +- "adcx %%r15, %%r14 ;" +- +- "xorl %%r15d, %%r15d;" +- "adox %%rax, %%r10 ;" +- "adcx %%r8, %%r8 ;" +- "adox %%rcx, %%r11 ;" +- "adcx %%r9, %%r9 ;" +- "adox %%r15, %%rbx ;" +- "adcx %%r10, %%r10 ;" +- "adox %%r15, %%r13 ;" +- "adcx %%r11, %%r11 ;" +- "adox %%r15, %%r14 ;" +- "adcx %%rbx, %%rbx ;" +- "adcx %%r13, %%r13 ;" +- "adcx %%r14, %%r14 ;" +- +- "movq (%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */ +- /*******************/ +- "movq %%rax, 0(%0) ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "movq 8(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */ +- "adcq %%rax, %%r9 ;" +- "movq %%r9, 16(%0) ;" +- "adcq %%rcx, %%r10 ;" +- "movq %%r10, 24(%0) ;" +- "movq 16(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */ +- "adcq %%rax, %%r11 ;" +- "movq %%r11, 32(%0) ;" +- "adcq %%rcx, %%rbx ;" +- "movq %%rbx, 40(%0) ;" +- "movq 24(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */ +- "adcq %%rax, %%r13 ;" +- "movq %%r13, 48(%0) ;" +- "adcq %%rcx, %%r14 ;" +- "movq %%r14, 56(%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", +- "%r10", "%r11", "%r13", "%r14", "%r15"); +-} ++ /* Compute the raw multiplication: tmp <- src1 * src2 */ + +-static void sqr_256x256_integer_bmi2(u64 *const c, const u64 *const a) +-{ +- asm volatile( +- "movq 8(%1), %%rdx ;" /* A[1] */ +- "mulx (%1), %%r8, %%r9 ;" /* A[0]*A[1] */ +- "mulx 16(%1), %%r10, %%r11 ;" /* A[2]*A[1] */ +- "mulx 24(%1), %%rcx, %%r14 ;" /* A[3]*A[1] */ +- +- "movq 16(%1), %%rdx ;" /* A[2] */ +- "mulx 24(%1), %%r15, %%r13 ;" /* A[3]*A[2] */ +- "mulx (%1), %%rax, %%rdx ;" /* A[0]*A[2] */ +- +- "addq %%rax, %%r9 ;" +- "adcq %%rdx, %%r10 ;" +- "adcq %%rcx, %%r11 ;" +- "adcq %%r14, %%r15 ;" +- "adcq $0, %%r13 ;" +- "movq $0, %%r14 ;" +- "adcq $0, %%r14 ;" +- +- "movq (%1), %%rdx ;" /* A[0] */ +- "mulx 24(%1), %%rax, %%rcx ;" /* A[0]*A[3] */ +- +- "addq %%rax, %%r10 ;" +- "adcq %%rcx, %%r11 ;" +- "adcq $0, %%r15 ;" +- "adcq $0, %%r13 ;" +- "adcq $0, %%r14 ;" +- +- "shldq $1, %%r13, %%r14 ;" +- "shldq $1, %%r15, %%r13 ;" +- "shldq $1, %%r11, %%r15 ;" +- "shldq $1, %%r10, %%r11 ;" +- "shldq $1, %%r9, %%r10 ;" +- "shldq $1, %%r8, %%r9 ;" +- "shlq $1, %%r8 ;" +- +- /*******************/ +- "mulx %%rdx, %%rax, %%rcx ;" /* A[0]^2 */ +- /*******************/ +- "movq %%rax, 0(%0) ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, 8(%0) ;" +- "movq 8(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[1]^2 */ +- "adcq %%rax, %%r9 ;" +- "movq %%r9, 16(%0) ;" +- "adcq %%rcx, %%r10 ;" +- "movq %%r10, 24(%0) ;" +- "movq 16(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[2]^2 */ +- "adcq %%rax, %%r11 ;" +- "movq %%r11, 32(%0) ;" +- "adcq %%rcx, %%r15 ;" +- "movq %%r15, 40(%0) ;" +- "movq 24(%1), %%rdx ;" +- "mulx %%rdx, %%rax, %%rcx ;" /* A[3]^2 */ +- "adcq %%rax, %%r13 ;" +- "movq %%r13, 48(%0) ;" +- "adcq %%rcx, %%r14 ;" +- "movq %%r14, 56(%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", +- "%r11", "%r13", "%r14", "%r15"); ++ /* Compute src1[0] * src2 */ ++ " movq 0(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 0(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 8(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" ++ /* Compute src1[1] * src2 */ ++ " movq 8(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 16(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" ++ /* Compute src1[2] * src2 */ ++ " movq 16(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 24(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" ++ /* Compute src1[3] * src2 */ ++ " movq 24(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 32(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " movq %%r12, 40(%0);" " mov $0, %%r8;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 48(%0);" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" " movq %%rax, 56(%0);" ++ /* Line up pointers */ ++ " mov %0, %1;" ++ " mov %2, %0;" ++ ++ /* Wrap the result back into the field */ ++ ++ /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ ++ " mov $38, %%rdx;" ++ " mulxq 32(%1), %%r8, %%r13;" ++ " xor %3, %3;" ++ " adoxq 0(%1), %%r8;" ++ " mulxq 40(%1), %%r9, %%r12;" ++ " adcx %%r13, %%r9;" ++ " adoxq 8(%1), %%r9;" ++ " mulxq 48(%1), %%r10, %%r13;" ++ " adcx %%r12, %%r10;" ++ " adoxq 16(%1), %%r10;" ++ " mulxq 56(%1), %%r11, %%rax;" ++ " adcx %%r13, %%r11;" ++ " adoxq 24(%1), %%r11;" ++ " adcx %3, %%rax;" ++ " adox %3, %%rax;" ++ " imul %%rdx, %%rax;" ++ ++ /* Step 2: Fold the carry back into dst */ ++ " add %%rax, %%r8;" ++ " adcx %3, %%r9;" ++ " movq %%r9, 8(%0);" ++ " adcx %3, %%r10;" ++ " movq %%r10, 16(%0);" ++ " adcx %3, %%r11;" ++ " movq %%r11, 24(%0);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rdx, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 0(%0);" ++ : "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2) ++ : ++ : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc" ++ ); + } + +-static void red_eltfp25519_1w_adx(u64 *const c, const u64 *const a) ++/* Computes two field multiplications: ++ * out[0] <- f1[0] * f2[0] ++ * out[1] <- f1[1] * f2[1] ++ * Uses the 16-element buffer tmp for intermediate results. */ ++static inline void fmul2(u64 *out, const u64 *f1, const u64 *f2, u64 *tmp) + { + asm volatile( +- "movl $38, %%edx ;" /* 2*c = 38 = 2^256 */ +- "mulx 32(%1), %%r8, %%r10 ;" /* c*C[4] */ +- "xorl %%ebx, %%ebx ;" +- "adox (%1), %%r8 ;" +- "mulx 40(%1), %%r9, %%r11 ;" /* c*C[5] */ +- "adcx %%r10, %%r9 ;" +- "adox 8(%1), %%r9 ;" +- "mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */ +- "adcx %%r11, %%r10 ;" +- "adox 16(%1), %%r10 ;" +- "mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */ +- "adcx %%rax, %%r11 ;" +- "adox 24(%1), %%r11 ;" +- /***************************************/ +- "adcx %%rbx, %%rcx ;" +- "adox %%rbx, %%rcx ;" +- "imul %%rdx, %%rcx ;" /* c*C[4], cf=0, of=0 */ +- "adcx %%rcx, %%r8 ;" +- "adcx %%rbx, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "adcx %%rbx, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "adcx %%rbx, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%edx, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, (%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", +- "%r10", "%r11"); +-} ++ /* Compute the raw multiplication tmp[0] <- f1[0] * f2[0] */ + +-static void red_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a) +-{ +- asm volatile( +- "movl $38, %%edx ;" /* 2*c = 38 = 2^256 */ +- "mulx 32(%1), %%r8, %%r10 ;" /* c*C[4] */ +- "mulx 40(%1), %%r9, %%r11 ;" /* c*C[5] */ +- "addq %%r10, %%r9 ;" +- "mulx 48(%1), %%r10, %%rax ;" /* c*C[6] */ +- "adcq %%r11, %%r10 ;" +- "mulx 56(%1), %%r11, %%rcx ;" /* c*C[7] */ +- "adcq %%rax, %%r11 ;" +- /***************************************/ +- "adcq $0, %%rcx ;" +- "addq (%1), %%r8 ;" +- "adcq 8(%1), %%r9 ;" +- "adcq 16(%1), %%r10 ;" +- "adcq 24(%1), %%r11 ;" +- "adcq $0, %%rcx ;" +- "imul %%rdx, %%rcx ;" /* c*C[4], cf=0 */ +- "addq %%rcx, %%r8 ;" +- "adcq $0, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "adcq $0, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "adcq $0, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%edx, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, (%0) ;" +- : +- : "r"(c), "r"(a) +- : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", +- "%r11"); ++ /* Compute src1[0] * src2 */ ++ " movq 0(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 0(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 8(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" ++ /* Compute src1[1] * src2 */ ++ " movq 8(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 16(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" ++ /* Compute src1[2] * src2 */ ++ " movq 16(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 24(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" ++ /* Compute src1[3] * src2 */ ++ " movq 24(%1), %%rdx;" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 32(%0);" ++ " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " movq %%r12, 40(%0);" " mov $0, %%r8;" ++ " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 48(%0);" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" " movq %%rax, 56(%0);" ++ ++ /* Compute the raw multiplication tmp[1] <- f1[1] * f2[1] */ ++ ++ /* Compute src1[0] * src2 */ ++ " movq 32(%1), %%rdx;" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 64(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 72(%0);" ++ " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" ++ " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" ++ /* Compute src1[1] * src2 */ ++ " movq 40(%1), %%rdx;" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 72(%0), %%r8;" " movq %%r8, 72(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 80(%0);" ++ " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" ++ /* Compute src1[2] * src2 */ ++ " movq 48(%1), %%rdx;" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 80(%0), %%r8;" " movq %%r8, 80(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 88(%0);" ++ " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" ++ /* Compute src1[3] * src2 */ ++ " movq 56(%1), %%rdx;" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 88(%0), %%r8;" " movq %%r8, 88(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 96(%0);" ++ " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " movq %%r12, 104(%0);" " mov $0, %%r8;" ++ " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 112(%0);" " mov $0, %%rax;" ++ " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" " movq %%rax, 120(%0);" ++ /* Line up pointers */ ++ " mov %0, %1;" ++ " mov %2, %0;" ++ ++ /* Wrap the results back into the field */ ++ ++ /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ ++ " mov $38, %%rdx;" ++ " mulxq 32(%1), %%r8, %%r13;" ++ " xor %3, %3;" ++ " adoxq 0(%1), %%r8;" ++ " mulxq 40(%1), %%r9, %%r12;" ++ " adcx %%r13, %%r9;" ++ " adoxq 8(%1), %%r9;" ++ " mulxq 48(%1), %%r10, %%r13;" ++ " adcx %%r12, %%r10;" ++ " adoxq 16(%1), %%r10;" ++ " mulxq 56(%1), %%r11, %%rax;" ++ " adcx %%r13, %%r11;" ++ " adoxq 24(%1), %%r11;" ++ " adcx %3, %%rax;" ++ " adox %3, %%rax;" ++ " imul %%rdx, %%rax;" ++ ++ /* Step 2: Fold the carry back into dst */ ++ " add %%rax, %%r8;" ++ " adcx %3, %%r9;" ++ " movq %%r9, 8(%0);" ++ " adcx %3, %%r10;" ++ " movq %%r10, 16(%0);" ++ " adcx %3, %%r11;" ++ " movq %%r11, 24(%0);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rdx, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 0(%0);" ++ ++ /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ ++ " mov $38, %%rdx;" ++ " mulxq 96(%1), %%r8, %%r13;" ++ " xor %3, %3;" ++ " adoxq 64(%1), %%r8;" ++ " mulxq 104(%1), %%r9, %%r12;" ++ " adcx %%r13, %%r9;" ++ " adoxq 72(%1), %%r9;" ++ " mulxq 112(%1), %%r10, %%r13;" ++ " adcx %%r12, %%r10;" ++ " adoxq 80(%1), %%r10;" ++ " mulxq 120(%1), %%r11, %%rax;" ++ " adcx %%r13, %%r11;" ++ " adoxq 88(%1), %%r11;" ++ " adcx %3, %%rax;" ++ " adox %3, %%rax;" ++ " imul %%rdx, %%rax;" ++ ++ /* Step 2: Fold the carry back into dst */ ++ " add %%rax, %%r8;" ++ " adcx %3, %%r9;" ++ " movq %%r9, 40(%0);" ++ " adcx %3, %%r10;" ++ " movq %%r10, 48(%0);" ++ " adcx %3, %%r11;" ++ " movq %%r11, 56(%0);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rdx, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 32(%0);" ++ : "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2) ++ : ++ : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc" ++ ); + } + +-static __always_inline void +-add_eltfp25519_1w_adx(u64 *const c, const u64 *const a, const u64 *const b) ++/* Computes the field multiplication of four-element f1 with value in f2 */ ++static inline void fmul_scalar(u64 *out, const u64 *f1, u64 f2) + { +- asm volatile( +- "mov $38, %%eax ;" +- "xorl %%ecx, %%ecx ;" +- "movq (%2), %%r8 ;" +- "adcx (%1), %%r8 ;" +- "movq 8(%2), %%r9 ;" +- "adcx 8(%1), %%r9 ;" +- "movq 16(%2), %%r10 ;" +- "adcx 16(%1), %%r10 ;" +- "movq 24(%2), %%r11 ;" +- "adcx 24(%1), %%r11 ;" +- "cmovc %%eax, %%ecx ;" +- "xorl %%eax, %%eax ;" +- "adcx %%rcx, %%r8 ;" +- "adcx %%rax, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "adcx %%rax, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "adcx %%rax, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $38, %%ecx ;" +- "cmovc %%ecx, %%eax ;" +- "addq %%rax, %%r8 ;" +- "movq %%r8, (%0) ;" +- : +- : "r"(c), "r"(a), "r"(b) +- : "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11"); +-} ++ register u64 f2_r asm("rdx") = f2; + +-static __always_inline void +-add_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a, const u64 *const b) +-{ + asm volatile( +- "mov $38, %%eax ;" +- "movq (%2), %%r8 ;" +- "addq (%1), %%r8 ;" +- "movq 8(%2), %%r9 ;" +- "adcq 8(%1), %%r9 ;" +- "movq 16(%2), %%r10 ;" +- "adcq 16(%1), %%r10 ;" +- "movq 24(%2), %%r11 ;" +- "adcq 24(%1), %%r11 ;" +- "mov $0, %%ecx ;" +- "cmovc %%eax, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "adcq $0, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "adcq $0, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "adcq $0, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%eax, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, (%0) ;" +- : +- : "r"(c), "r"(a), "r"(b) +- : "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11"); ++ /* Compute the raw multiplication of f1*f2 */ ++ " mulxq 0(%2), %%r8, %%rcx;" /* f1[0]*f2 */ ++ " mulxq 8(%2), %%r9, %%r12;" /* f1[1]*f2 */ ++ " add %%rcx, %%r9;" ++ " mov $0, %%rcx;" ++ " mulxq 16(%2), %%r10, %%r13;" /* f1[2]*f2 */ ++ " adcx %%r12, %%r10;" ++ " mulxq 24(%2), %%r11, %%rax;" /* f1[3]*f2 */ ++ " adcx %%r13, %%r11;" ++ " adcx %%rcx, %%rax;" ++ ++ /* Wrap the result back into the field */ ++ ++ /* Step 1: Compute carry*38 */ ++ " mov $38, %%rdx;" ++ " imul %%rdx, %%rax;" ++ ++ /* Step 2: Fold the carry back into dst */ ++ " add %%rax, %%r8;" ++ " adcx %%rcx, %%r9;" ++ " movq %%r9, 8(%1);" ++ " adcx %%rcx, %%r10;" ++ " movq %%r10, 16(%1);" ++ " adcx %%rcx, %%r11;" ++ " movq %%r11, 24(%1);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rdx, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 0(%1);" ++ : "+&r" (f2_r) ++ : "r" (out), "r" (f1) ++ : "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "memory", "cc" ++ ); + } + +-static __always_inline void +-sub_eltfp25519_1w(u64 *const c, const u64 *const a, const u64 *const b) +-{ +- asm volatile( +- "mov $38, %%eax ;" +- "movq (%1), %%r8 ;" +- "subq (%2), %%r8 ;" +- "movq 8(%1), %%r9 ;" +- "sbbq 8(%2), %%r9 ;" +- "movq 16(%1), %%r10 ;" +- "sbbq 16(%2), %%r10 ;" +- "movq 24(%1), %%r11 ;" +- "sbbq 24(%2), %%r11 ;" +- "mov $0, %%ecx ;" +- "cmovc %%eax, %%ecx ;" +- "subq %%rcx, %%r8 ;" +- "sbbq $0, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "sbbq $0, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "sbbq $0, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%eax, %%ecx ;" +- "subq %%rcx, %%r8 ;" +- "movq %%r8, (%0) ;" +- : +- : "r"(c), "r"(a), "r"(b) +- : "memory", "cc", "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11"); +-} +- +-/* Multiplication by a24 = (A+2)/4 = (486662+2)/4 = 121666 */ +-static __always_inline void +-mul_a24_eltfp25519_1w(u64 *const c, const u64 *const a) ++/* Computes p1 <- bit ? p2 : p1 in constant time */ ++static inline void cswap2(u64 bit, const u64 *p1, const u64 *p2) + { +- const u64 a24 = 121666; + asm volatile( +- "movq %2, %%rdx ;" +- "mulx (%1), %%r8, %%r10 ;" +- "mulx 8(%1), %%r9, %%r11 ;" +- "addq %%r10, %%r9 ;" +- "mulx 16(%1), %%r10, %%rax ;" +- "adcq %%r11, %%r10 ;" +- "mulx 24(%1), %%r11, %%rcx ;" +- "adcq %%rax, %%r11 ;" +- /**************************/ +- "adcq $0, %%rcx ;" +- "movl $38, %%edx ;" /* 2*c = 38 = 2^256 mod 2^255-19*/ +- "imul %%rdx, %%rcx ;" +- "addq %%rcx, %%r8 ;" +- "adcq $0, %%r9 ;" +- "movq %%r9, 8(%0) ;" +- "adcq $0, %%r10 ;" +- "movq %%r10, 16(%0) ;" +- "adcq $0, %%r11 ;" +- "movq %%r11, 24(%0) ;" +- "mov $0, %%ecx ;" +- "cmovc %%edx, %%ecx ;" +- "addq %%rcx, %%r8 ;" +- "movq %%r8, (%0) ;" +- : +- : "r"(c), "r"(a), "r"(a24) +- : "memory", "cc", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", +- "%r11"); +-} +- +-static void inv_eltfp25519_1w_adx(u64 *const c, const u64 *const a) +-{ +- struct { +- eltfp25519_1w_buffer buffer; +- eltfp25519_1w x0, x1, x2; +- } __aligned(32) m; +- u64 *T[4]; +- +- T[0] = m.x0; +- T[1] = c; /* x^(-1) */ +- T[2] = m.x1; +- T[3] = m.x2; +- +- copy_eltfp25519_1w(T[1], a); +- sqrn_eltfp25519_1w_adx(T[1], 1); +- copy_eltfp25519_1w(T[2], T[1]); +- sqrn_eltfp25519_1w_adx(T[2], 2); +- mul_eltfp25519_1w_adx(T[0], a, T[2]); +- mul_eltfp25519_1w_adx(T[1], T[1], T[0]); +- copy_eltfp25519_1w(T[2], T[1]); +- sqrn_eltfp25519_1w_adx(T[2], 1); +- mul_eltfp25519_1w_adx(T[0], T[0], T[2]); +- copy_eltfp25519_1w(T[2], T[0]); +- sqrn_eltfp25519_1w_adx(T[2], 5); +- mul_eltfp25519_1w_adx(T[0], T[0], T[2]); +- copy_eltfp25519_1w(T[2], T[0]); +- sqrn_eltfp25519_1w_adx(T[2], 10); +- mul_eltfp25519_1w_adx(T[2], T[2], T[0]); +- copy_eltfp25519_1w(T[3], T[2]); +- sqrn_eltfp25519_1w_adx(T[3], 20); +- mul_eltfp25519_1w_adx(T[3], T[3], T[2]); +- sqrn_eltfp25519_1w_adx(T[3], 10); +- mul_eltfp25519_1w_adx(T[3], T[3], T[0]); +- copy_eltfp25519_1w(T[0], T[3]); +- sqrn_eltfp25519_1w_adx(T[0], 50); +- mul_eltfp25519_1w_adx(T[0], T[0], T[3]); +- copy_eltfp25519_1w(T[2], T[0]); +- sqrn_eltfp25519_1w_adx(T[2], 100); +- mul_eltfp25519_1w_adx(T[2], T[2], T[0]); +- sqrn_eltfp25519_1w_adx(T[2], 50); +- mul_eltfp25519_1w_adx(T[2], T[2], T[3]); +- sqrn_eltfp25519_1w_adx(T[2], 5); +- mul_eltfp25519_1w_adx(T[1], T[1], T[2]); +- +- memzero_explicit(&m, sizeof(m)); +-} +- +-static void inv_eltfp25519_1w_bmi2(u64 *const c, const u64 *const a) +-{ +- struct { +- eltfp25519_1w_buffer buffer; +- eltfp25519_1w x0, x1, x2; +- } __aligned(32) m; +- u64 *T[5]; +- +- T[0] = m.x0; +- T[1] = c; /* x^(-1) */ +- T[2] = m.x1; +- T[3] = m.x2; +- +- copy_eltfp25519_1w(T[1], a); +- sqrn_eltfp25519_1w_bmi2(T[1], 1); +- copy_eltfp25519_1w(T[2], T[1]); +- sqrn_eltfp25519_1w_bmi2(T[2], 2); +- mul_eltfp25519_1w_bmi2(T[0], a, T[2]); +- mul_eltfp25519_1w_bmi2(T[1], T[1], T[0]); +- copy_eltfp25519_1w(T[2], T[1]); +- sqrn_eltfp25519_1w_bmi2(T[2], 1); +- mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]); +- copy_eltfp25519_1w(T[2], T[0]); +- sqrn_eltfp25519_1w_bmi2(T[2], 5); +- mul_eltfp25519_1w_bmi2(T[0], T[0], T[2]); +- copy_eltfp25519_1w(T[2], T[0]); +- sqrn_eltfp25519_1w_bmi2(T[2], 10); +- mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]); +- copy_eltfp25519_1w(T[3], T[2]); +- sqrn_eltfp25519_1w_bmi2(T[3], 20); +- mul_eltfp25519_1w_bmi2(T[3], T[3], T[2]); +- sqrn_eltfp25519_1w_bmi2(T[3], 10); +- mul_eltfp25519_1w_bmi2(T[3], T[3], T[0]); +- copy_eltfp25519_1w(T[0], T[3]); +- sqrn_eltfp25519_1w_bmi2(T[0], 50); +- mul_eltfp25519_1w_bmi2(T[0], T[0], T[3]); +- copy_eltfp25519_1w(T[2], T[0]); +- sqrn_eltfp25519_1w_bmi2(T[2], 100); +- mul_eltfp25519_1w_bmi2(T[2], T[2], T[0]); +- sqrn_eltfp25519_1w_bmi2(T[2], 50); +- mul_eltfp25519_1w_bmi2(T[2], T[2], T[3]); +- sqrn_eltfp25519_1w_bmi2(T[2], 5); +- mul_eltfp25519_1w_bmi2(T[1], T[1], T[2]); ++ /* Invert the polarity of bit to match cmov expectations */ ++ " add $18446744073709551615, %0;" + +- memzero_explicit(&m, sizeof(m)); ++ /* cswap p1[0], p2[0] */ ++ " movq 0(%1), %%r8;" ++ " movq 0(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 0(%1);" ++ " movq %%r9, 0(%2);" ++ ++ /* cswap p1[1], p2[1] */ ++ " movq 8(%1), %%r8;" ++ " movq 8(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 8(%1);" ++ " movq %%r9, 8(%2);" ++ ++ /* cswap p1[2], p2[2] */ ++ " movq 16(%1), %%r8;" ++ " movq 16(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 16(%1);" ++ " movq %%r9, 16(%2);" ++ ++ /* cswap p1[3], p2[3] */ ++ " movq 24(%1), %%r8;" ++ " movq 24(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 24(%1);" ++ " movq %%r9, 24(%2);" ++ ++ /* cswap p1[4], p2[4] */ ++ " movq 32(%1), %%r8;" ++ " movq 32(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 32(%1);" ++ " movq %%r9, 32(%2);" ++ ++ /* cswap p1[5], p2[5] */ ++ " movq 40(%1), %%r8;" ++ " movq 40(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 40(%1);" ++ " movq %%r9, 40(%2);" ++ ++ /* cswap p1[6], p2[6] */ ++ " movq 48(%1), %%r8;" ++ " movq 48(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 48(%1);" ++ " movq %%r9, 48(%2);" ++ ++ /* cswap p1[7], p2[7] */ ++ " movq 56(%1), %%r8;" ++ " movq 56(%2), %%r9;" ++ " mov %%r8, %%r10;" ++ " cmovc %%r9, %%r8;" ++ " cmovc %%r10, %%r9;" ++ " movq %%r8, 56(%1);" ++ " movq %%r9, 56(%2);" ++ : "+&r" (bit) ++ : "r" (p1), "r" (p2) ++ : "%r8", "%r9", "%r10", "memory", "cc" ++ ); + } + +-/* Given c, a 256-bit number, fred_eltfp25519_1w updates c +- * with a number such that 0 <= C < 2**255-19. +- */ +-static __always_inline void fred_eltfp25519_1w(u64 *const c) ++/* Computes the square of a field element: out <- f * f ++ * Uses the 8-element buffer tmp for intermediate results */ ++static inline void fsqr(u64 *out, const u64 *f, u64 *tmp) + { +- u64 tmp0 = 38, tmp1 = 19; + asm volatile( +- "btrq $63, %3 ;" /* Put bit 255 in carry flag and clear */ +- "cmovncl %k5, %k4 ;" /* c[255] ? 38 : 19 */ +- +- /* Add either 19 or 38 to c */ +- "addq %4, %0 ;" +- "adcq $0, %1 ;" +- "adcq $0, %2 ;" +- "adcq $0, %3 ;" +- +- /* Test for bit 255 again; only triggered on overflow modulo 2^255-19 */ +- "movl $0, %k4 ;" +- "cmovnsl %k5, %k4 ;" /* c[255] ? 0 : 19 */ +- "btrq $63, %3 ;" /* Clear bit 255 */ +- +- /* Subtract 19 if necessary */ +- "subq %4, %0 ;" +- "sbbq $0, %1 ;" +- "sbbq $0, %2 ;" +- "sbbq $0, %3 ;" +- +- : "+r"(c[0]), "+r"(c[1]), "+r"(c[2]), "+r"(c[3]), "+r"(tmp0), +- "+r"(tmp1) +- : +- : "memory", "cc"); +-} ++ /* Compute the raw multiplication: tmp <- f * f */ + +-static __always_inline void cswap(u8 bit, u64 *const px, u64 *const py) +-{ +- u64 temp; +- asm volatile( +- "test %9, %9 ;" +- "movq %0, %8 ;" +- "cmovnzq %4, %0 ;" +- "cmovnzq %8, %4 ;" +- "movq %1, %8 ;" +- "cmovnzq %5, %1 ;" +- "cmovnzq %8, %5 ;" +- "movq %2, %8 ;" +- "cmovnzq %6, %2 ;" +- "cmovnzq %8, %6 ;" +- "movq %3, %8 ;" +- "cmovnzq %7, %3 ;" +- "cmovnzq %8, %7 ;" +- : "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3]), +- "+r"(py[0]), "+r"(py[1]), "+r"(py[2]), "+r"(py[3]), +- "=r"(temp) +- : "r"(bit) +- : "cc" ++ /* Step 1: Compute all partial products */ ++ " movq 0(%1), %%rdx;" /* f[0] */ ++ " mulxq 8(%1), %%r8, %%r14;" " xor %%r15, %%r15;" /* f[1]*f[0] */ ++ " mulxq 16(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ ++ " mulxq 24(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ ++ " movq 24(%1), %%rdx;" /* f[3] */ ++ " mulxq 8(%1), %%r11, %%r12;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ ++ " mulxq 16(%1), %%rax, %%r13;" " adcx %%rax, %%r12;" /* f[2]*f[3] */ ++ " movq 8(%1), %%rdx;" " adcx %%r15, %%r13;" /* f1 */ ++ " mulxq 16(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ ++ ++ /* Step 2: Compute two parallel carry chains */ ++ " xor %%r15, %%r15;" ++ " adox %%rax, %%r10;" ++ " adcx %%r8, %%r8;" ++ " adox %%rcx, %%r11;" ++ " adcx %%r9, %%r9;" ++ " adox %%r15, %%r12;" ++ " adcx %%r10, %%r10;" ++ " adox %%r15, %%r13;" ++ " adcx %%r11, %%r11;" ++ " adox %%r15, %%r14;" ++ " adcx %%r12, %%r12;" ++ " adcx %%r13, %%r13;" ++ " adcx %%r14, %%r14;" ++ ++ /* Step 3: Compute intermediate squares */ ++ " movq 0(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[0]^2 */ ++ " movq %%rax, 0(%0);" ++ " add %%rcx, %%r8;" " movq %%r8, 8(%0);" ++ " movq 8(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[1]^2 */ ++ " adcx %%rax, %%r9;" " movq %%r9, 16(%0);" ++ " adcx %%rcx, %%r10;" " movq %%r10, 24(%0);" ++ " movq 16(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[2]^2 */ ++ " adcx %%rax, %%r11;" " movq %%r11, 32(%0);" ++ " adcx %%rcx, %%r12;" " movq %%r12, 40(%0);" ++ " movq 24(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[3]^2 */ ++ " adcx %%rax, %%r13;" " movq %%r13, 48(%0);" ++ " adcx %%rcx, %%r14;" " movq %%r14, 56(%0);" ++ ++ /* Line up pointers */ ++ " mov %0, %1;" ++ " mov %2, %0;" ++ ++ /* Wrap the result back into the field */ ++ ++ /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ ++ " mov $38, %%rdx;" ++ " mulxq 32(%1), %%r8, %%r13;" ++ " xor %%rcx, %%rcx;" ++ " adoxq 0(%1), %%r8;" ++ " mulxq 40(%1), %%r9, %%r12;" ++ " adcx %%r13, %%r9;" ++ " adoxq 8(%1), %%r9;" ++ " mulxq 48(%1), %%r10, %%r13;" ++ " adcx %%r12, %%r10;" ++ " adoxq 16(%1), %%r10;" ++ " mulxq 56(%1), %%r11, %%rax;" ++ " adcx %%r13, %%r11;" ++ " adoxq 24(%1), %%r11;" ++ " adcx %%rcx, %%rax;" ++ " adox %%rcx, %%rax;" ++ " imul %%rdx, %%rax;" ++ ++ /* Step 2: Fold the carry back into dst */ ++ " add %%rax, %%r8;" ++ " adcx %%rcx, %%r9;" ++ " movq %%r9, 8(%0);" ++ " adcx %%rcx, %%r10;" ++ " movq %%r10, 16(%0);" ++ " adcx %%rcx, %%r11;" ++ " movq %%r11, 24(%0);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rdx, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 0(%0);" ++ : "+&r" (tmp), "+&r" (f), "+&r" (out) ++ : ++ : "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc" + ); + } + +-static __always_inline void cselect(u8 bit, u64 *const px, const u64 *const py) ++/* Computes two field squarings: ++ * out[0] <- f[0] * f[0] ++ * out[1] <- f[1] * f[1] ++ * Uses the 16-element buffer tmp for intermediate results */ ++static inline void fsqr2(u64 *out, const u64 *f, u64 *tmp) + { + asm volatile( +- "test %4, %4 ;" +- "cmovnzq %5, %0 ;" +- "cmovnzq %6, %1 ;" +- "cmovnzq %7, %2 ;" +- "cmovnzq %8, %3 ;" +- : "+r"(px[0]), "+r"(px[1]), "+r"(px[2]), "+r"(px[3]) +- : "r"(bit), "rm"(py[0]), "rm"(py[1]), "rm"(py[2]), "rm"(py[3]) +- : "cc" ++ /* Step 1: Compute all partial products */ ++ " movq 0(%1), %%rdx;" /* f[0] */ ++ " mulxq 8(%1), %%r8, %%r14;" " xor %%r15, %%r15;" /* f[1]*f[0] */ ++ " mulxq 16(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ ++ " mulxq 24(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ ++ " movq 24(%1), %%rdx;" /* f[3] */ ++ " mulxq 8(%1), %%r11, %%r12;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ ++ " mulxq 16(%1), %%rax, %%r13;" " adcx %%rax, %%r12;" /* f[2]*f[3] */ ++ " movq 8(%1), %%rdx;" " adcx %%r15, %%r13;" /* f1 */ ++ " mulxq 16(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ ++ ++ /* Step 2: Compute two parallel carry chains */ ++ " xor %%r15, %%r15;" ++ " adox %%rax, %%r10;" ++ " adcx %%r8, %%r8;" ++ " adox %%rcx, %%r11;" ++ " adcx %%r9, %%r9;" ++ " adox %%r15, %%r12;" ++ " adcx %%r10, %%r10;" ++ " adox %%r15, %%r13;" ++ " adcx %%r11, %%r11;" ++ " adox %%r15, %%r14;" ++ " adcx %%r12, %%r12;" ++ " adcx %%r13, %%r13;" ++ " adcx %%r14, %%r14;" ++ ++ /* Step 3: Compute intermediate squares */ ++ " movq 0(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[0]^2 */ ++ " movq %%rax, 0(%0);" ++ " add %%rcx, %%r8;" " movq %%r8, 8(%0);" ++ " movq 8(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[1]^2 */ ++ " adcx %%rax, %%r9;" " movq %%r9, 16(%0);" ++ " adcx %%rcx, %%r10;" " movq %%r10, 24(%0);" ++ " movq 16(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[2]^2 */ ++ " adcx %%rax, %%r11;" " movq %%r11, 32(%0);" ++ " adcx %%rcx, %%r12;" " movq %%r12, 40(%0);" ++ " movq 24(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[3]^2 */ ++ " adcx %%rax, %%r13;" " movq %%r13, 48(%0);" ++ " adcx %%rcx, %%r14;" " movq %%r14, 56(%0);" ++ ++ /* Step 1: Compute all partial products */ ++ " movq 32(%1), %%rdx;" /* f[0] */ ++ " mulxq 40(%1), %%r8, %%r14;" " xor %%r15, %%r15;" /* f[1]*f[0] */ ++ " mulxq 48(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ ++ " mulxq 56(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ ++ " movq 56(%1), %%rdx;" /* f[3] */ ++ " mulxq 40(%1), %%r11, %%r12;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ ++ " mulxq 48(%1), %%rax, %%r13;" " adcx %%rax, %%r12;" /* f[2]*f[3] */ ++ " movq 40(%1), %%rdx;" " adcx %%r15, %%r13;" /* f1 */ ++ " mulxq 48(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ ++ ++ /* Step 2: Compute two parallel carry chains */ ++ " xor %%r15, %%r15;" ++ " adox %%rax, %%r10;" ++ " adcx %%r8, %%r8;" ++ " adox %%rcx, %%r11;" ++ " adcx %%r9, %%r9;" ++ " adox %%r15, %%r12;" ++ " adcx %%r10, %%r10;" ++ " adox %%r15, %%r13;" ++ " adcx %%r11, %%r11;" ++ " adox %%r15, %%r14;" ++ " adcx %%r12, %%r12;" ++ " adcx %%r13, %%r13;" ++ " adcx %%r14, %%r14;" ++ ++ /* Step 3: Compute intermediate squares */ ++ " movq 32(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[0]^2 */ ++ " movq %%rax, 64(%0);" ++ " add %%rcx, %%r8;" " movq %%r8, 72(%0);" ++ " movq 40(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[1]^2 */ ++ " adcx %%rax, %%r9;" " movq %%r9, 80(%0);" ++ " adcx %%rcx, %%r10;" " movq %%r10, 88(%0);" ++ " movq 48(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[2]^2 */ ++ " adcx %%rax, %%r11;" " movq %%r11, 96(%0);" ++ " adcx %%rcx, %%r12;" " movq %%r12, 104(%0);" ++ " movq 56(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[3]^2 */ ++ " adcx %%rax, %%r13;" " movq %%r13, 112(%0);" ++ " adcx %%rcx, %%r14;" " movq %%r14, 120(%0);" ++ ++ /* Line up pointers */ ++ " mov %0, %1;" ++ " mov %2, %0;" ++ ++ /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ ++ " mov $38, %%rdx;" ++ " mulxq 32(%1), %%r8, %%r13;" ++ " xor %%rcx, %%rcx;" ++ " adoxq 0(%1), %%r8;" ++ " mulxq 40(%1), %%r9, %%r12;" ++ " adcx %%r13, %%r9;" ++ " adoxq 8(%1), %%r9;" ++ " mulxq 48(%1), %%r10, %%r13;" ++ " adcx %%r12, %%r10;" ++ " adoxq 16(%1), %%r10;" ++ " mulxq 56(%1), %%r11, %%rax;" ++ " adcx %%r13, %%r11;" ++ " adoxq 24(%1), %%r11;" ++ " adcx %%rcx, %%rax;" ++ " adox %%rcx, %%rax;" ++ " imul %%rdx, %%rax;" ++ ++ /* Step 2: Fold the carry back into dst */ ++ " add %%rax, %%r8;" ++ " adcx %%rcx, %%r9;" ++ " movq %%r9, 8(%0);" ++ " adcx %%rcx, %%r10;" ++ " movq %%r10, 16(%0);" ++ " adcx %%rcx, %%r11;" ++ " movq %%r11, 24(%0);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rdx, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 0(%0);" ++ ++ /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ ++ " mov $38, %%rdx;" ++ " mulxq 96(%1), %%r8, %%r13;" ++ " xor %%rcx, %%rcx;" ++ " adoxq 64(%1), %%r8;" ++ " mulxq 104(%1), %%r9, %%r12;" ++ " adcx %%r13, %%r9;" ++ " adoxq 72(%1), %%r9;" ++ " mulxq 112(%1), %%r10, %%r13;" ++ " adcx %%r12, %%r10;" ++ " adoxq 80(%1), %%r10;" ++ " mulxq 120(%1), %%r11, %%rax;" ++ " adcx %%r13, %%r11;" ++ " adoxq 88(%1), %%r11;" ++ " adcx %%rcx, %%rax;" ++ " adox %%rcx, %%rax;" ++ " imul %%rdx, %%rax;" ++ ++ /* Step 2: Fold the carry back into dst */ ++ " add %%rax, %%r8;" ++ " adcx %%rcx, %%r9;" ++ " movq %%r9, 40(%0);" ++ " adcx %%rcx, %%r10;" ++ " movq %%r10, 48(%0);" ++ " adcx %%rcx, %%r11;" ++ " movq %%r11, 56(%0);" ++ ++ /* Step 3: Fold the carry bit back in; guaranteed not to carry at this point */ ++ " mov $0, %%rax;" ++ " cmovc %%rdx, %%rax;" ++ " add %%rax, %%r8;" ++ " movq %%r8, 32(%0);" ++ : "+&r" (tmp), "+&r" (f), "+&r" (out) ++ : ++ : "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc" + ); + } + +-static void curve25519_adx(u8 shared[CURVE25519_KEY_SIZE], +- const u8 private_key[CURVE25519_KEY_SIZE], +- const u8 session_key[CURVE25519_KEY_SIZE]) +-{ +- struct { +- u64 buffer[4 * NUM_WORDS_ELTFP25519]; +- u64 coordinates[4 * NUM_WORDS_ELTFP25519]; +- u64 workspace[6 * NUM_WORDS_ELTFP25519]; +- u8 session[CURVE25519_KEY_SIZE]; +- u8 private[CURVE25519_KEY_SIZE]; +- } __aligned(32) m; +- +- int i = 0, j = 0; +- u64 prev = 0; +- u64 *const X1 = (u64 *)m.session; +- u64 *const key = (u64 *)m.private; +- u64 *const Px = m.coordinates + 0; +- u64 *const Pz = m.coordinates + 4; +- u64 *const Qx = m.coordinates + 8; +- u64 *const Qz = m.coordinates + 12; +- u64 *const X2 = Qx; +- u64 *const Z2 = Qz; +- u64 *const X3 = Px; +- u64 *const Z3 = Pz; +- u64 *const X2Z2 = Qx; +- u64 *const X3Z3 = Px; +- +- u64 *const A = m.workspace + 0; +- u64 *const B = m.workspace + 4; +- u64 *const D = m.workspace + 8; +- u64 *const C = m.workspace + 12; +- u64 *const DA = m.workspace + 16; +- u64 *const CB = m.workspace + 20; +- u64 *const AB = A; +- u64 *const DC = D; +- u64 *const DACB = DA; +- +- memcpy(m.private, private_key, sizeof(m.private)); +- memcpy(m.session, session_key, sizeof(m.session)); +- +- curve25519_clamp_secret(m.private); +- +- /* As in the draft: +- * When receiving such an array, implementations of curve25519 +- * MUST mask the most-significant bit in the final byte. This +- * is done to preserve compatibility with point formats which +- * reserve the sign bit for use in other protocols and to +- * increase resistance to implementation fingerprinting +- */ +- m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1; +- +- copy_eltfp25519_1w(Px, X1); +- setzero_eltfp25519_1w(Pz); +- setzero_eltfp25519_1w(Qx); +- setzero_eltfp25519_1w(Qz); +- +- Pz[0] = 1; +- Qx[0] = 1; +- +- /* main-loop */ +- prev = 0; +- j = 62; +- for (i = 3; i >= 0; --i) { +- while (j >= 0) { +- u64 bit = (key[i] >> j) & 0x1; +- u64 swap = bit ^ prev; +- prev = bit; +- +- add_eltfp25519_1w_adx(A, X2, Z2); /* A = (X2+Z2) */ +- sub_eltfp25519_1w(B, X2, Z2); /* B = (X2-Z2) */ +- add_eltfp25519_1w_adx(C, X3, Z3); /* C = (X3+Z3) */ +- sub_eltfp25519_1w(D, X3, Z3); /* D = (X3-Z3) */ +- mul_eltfp25519_2w_adx(DACB, AB, DC); /* [DA|CB] = [A|B]*[D|C] */ +- +- cselect(swap, A, C); +- cselect(swap, B, D); +- +- sqr_eltfp25519_2w_adx(AB); /* [AA|BB] = [A^2|B^2] */ +- add_eltfp25519_1w_adx(X3, DA, CB); /* X3 = (DA+CB) */ +- sub_eltfp25519_1w(Z3, DA, CB); /* Z3 = (DA-CB) */ +- sqr_eltfp25519_2w_adx(X3Z3); /* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */ +- +- copy_eltfp25519_1w(X2, B); /* X2 = B^2 */ +- sub_eltfp25519_1w(Z2, A, B); /* Z2 = E = AA-BB */ +- +- mul_a24_eltfp25519_1w(B, Z2); /* B = a24*E */ +- add_eltfp25519_1w_adx(B, B, X2); /* B = a24*E+B */ +- mul_eltfp25519_2w_adx(X2Z2, X2Z2, AB); /* [X2|Z2] = [B|E]*[A|a24*E+B] */ +- mul_eltfp25519_1w_adx(Z3, Z3, X1); /* Z3 = Z3*X1 */ +- --j; +- } +- j = 63; +- } +- +- inv_eltfp25519_1w_adx(A, Qz); +- mul_eltfp25519_1w_adx((u64 *)shared, Qx, A); +- fred_eltfp25519_1w((u64 *)shared); +- +- memzero_explicit(&m, sizeof(m)); +-} +- +-static void curve25519_adx_base(u8 session_key[CURVE25519_KEY_SIZE], +- const u8 private_key[CURVE25519_KEY_SIZE]) ++static void point_add_and_double(u64 *q, u64 *p01_tmp1, u64 *tmp2) + { +- struct { +- u64 buffer[4 * NUM_WORDS_ELTFP25519]; +- u64 coordinates[4 * NUM_WORDS_ELTFP25519]; +- u64 workspace[4 * NUM_WORDS_ELTFP25519]; +- u8 private[CURVE25519_KEY_SIZE]; +- } __aligned(32) m; +- +- const int ite[4] = { 64, 64, 64, 63 }; +- const int q = 3; +- u64 swap = 1; +- +- int i = 0, j = 0, k = 0; +- u64 *const key = (u64 *)m.private; +- u64 *const Ur1 = m.coordinates + 0; +- u64 *const Zr1 = m.coordinates + 4; +- u64 *const Ur2 = m.coordinates + 8; +- u64 *const Zr2 = m.coordinates + 12; +- +- u64 *const UZr1 = m.coordinates + 0; +- u64 *const ZUr2 = m.coordinates + 8; +- +- u64 *const A = m.workspace + 0; +- u64 *const B = m.workspace + 4; +- u64 *const C = m.workspace + 8; +- u64 *const D = m.workspace + 12; +- +- u64 *const AB = m.workspace + 0; +- u64 *const CD = m.workspace + 8; +- +- const u64 *const P = table_ladder_8k; +- +- memcpy(m.private, private_key, sizeof(m.private)); +- +- curve25519_clamp_secret(m.private); +- +- setzero_eltfp25519_1w(Ur1); +- setzero_eltfp25519_1w(Zr1); +- setzero_eltfp25519_1w(Zr2); +- Ur1[0] = 1; +- Zr1[0] = 1; +- Zr2[0] = 1; +- +- /* G-S */ +- Ur2[3] = 0x1eaecdeee27cab34UL; +- Ur2[2] = 0xadc7a0b9235d48e2UL; +- Ur2[1] = 0xbbf095ae14b2edf8UL; +- Ur2[0] = 0x7e94e1fec82faabdUL; +- +- /* main-loop */ +- j = q; +- for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) { +- while (j < ite[i]) { +- u64 bit = (key[i] >> j) & 0x1; +- k = (64 * i + j - q); +- swap = swap ^ bit; +- cswap(swap, Ur1, Ur2); +- cswap(swap, Zr1, Zr2); +- swap = bit; +- /* Addition */ +- sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ +- add_eltfp25519_1w_adx(A, Ur1, Zr1); /* A = Ur1+Zr1 */ +- mul_eltfp25519_1w_adx(C, &P[4 * k], B); /* C = M0-B */ +- sub_eltfp25519_1w(B, A, C); /* B = (Ur1+Zr1) - M*(Ur1-Zr1) */ +- add_eltfp25519_1w_adx(A, A, C); /* A = (Ur1+Zr1) + M*(Ur1-Zr1) */ +- sqr_eltfp25519_2w_adx(AB); /* A = A^2 | B = B^2 */ +- mul_eltfp25519_2w_adx(UZr1, ZUr2, AB); /* Ur1 = Zr2*A | Zr1 = Ur2*B */ +- ++j; ++ u64 *nq = p01_tmp1; ++ u64 *nq_p1 = p01_tmp1 + (u32)8U; ++ u64 *tmp1 = p01_tmp1 + (u32)16U; ++ u64 *x1 = q; ++ u64 *x2 = nq; ++ u64 *z2 = nq + (u32)4U; ++ u64 *z3 = nq_p1 + (u32)4U; ++ u64 *a = tmp1; ++ u64 *b = tmp1 + (u32)4U; ++ u64 *ab = tmp1; ++ u64 *dc = tmp1 + (u32)8U; ++ u64 *x3; ++ u64 *z31; ++ u64 *d0; ++ u64 *c0; ++ u64 *a1; ++ u64 *b1; ++ u64 *d; ++ u64 *c; ++ u64 *ab1; ++ u64 *dc1; ++ fadd(a, x2, z2); ++ fsub(b, x2, z2); ++ x3 = nq_p1; ++ z31 = nq_p1 + (u32)4U; ++ d0 = dc; ++ c0 = dc + (u32)4U; ++ fadd(c0, x3, z31); ++ fsub(d0, x3, z31); ++ fmul2(dc, dc, ab, tmp2); ++ fadd(x3, d0, c0); ++ fsub(z31, d0, c0); ++ a1 = tmp1; ++ b1 = tmp1 + (u32)4U; ++ d = tmp1 + (u32)8U; ++ c = tmp1 + (u32)12U; ++ ab1 = tmp1; ++ dc1 = tmp1 + (u32)8U; ++ fsqr2(dc1, ab1, tmp2); ++ fsqr2(nq_p1, nq_p1, tmp2); ++ a1[0U] = c[0U]; ++ a1[1U] = c[1U]; ++ a1[2U] = c[2U]; ++ a1[3U] = c[3U]; ++ fsub(c, d, c); ++ fmul_scalar(b1, c, (u64)121665U); ++ fadd(b1, b1, d); ++ fmul2(nq, dc1, ab1, tmp2); ++ fmul(z3, z3, x1, tmp2); ++} ++ ++static void point_double(u64 *nq, u64 *tmp1, u64 *tmp2) ++{ ++ u64 *x2 = nq; ++ u64 *z2 = nq + (u32)4U; ++ u64 *a = tmp1; ++ u64 *b = tmp1 + (u32)4U; ++ u64 *d = tmp1 + (u32)8U; ++ u64 *c = tmp1 + (u32)12U; ++ u64 *ab = tmp1; ++ u64 *dc = tmp1 + (u32)8U; ++ fadd(a, x2, z2); ++ fsub(b, x2, z2); ++ fsqr2(dc, ab, tmp2); ++ a[0U] = c[0U]; ++ a[1U] = c[1U]; ++ a[2U] = c[2U]; ++ a[3U] = c[3U]; ++ fsub(c, d, c); ++ fmul_scalar(b, c, (u64)121665U); ++ fadd(b, b, d); ++ fmul2(nq, dc, ab, tmp2); ++} ++ ++static void montgomery_ladder(u64 *out, const u8 *key, u64 *init1) ++{ ++ u64 tmp2[16U] = { 0U }; ++ u64 p01_tmp1_swap[33U] = { 0U }; ++ u64 *p0 = p01_tmp1_swap; ++ u64 *p01 = p01_tmp1_swap; ++ u64 *p03 = p01; ++ u64 *p11 = p01 + (u32)8U; ++ u64 *x0; ++ u64 *z0; ++ u64 *p01_tmp1; ++ u64 *p01_tmp11; ++ u64 *nq10; ++ u64 *nq_p11; ++ u64 *swap1; ++ u64 sw0; ++ u64 *nq1; ++ u64 *tmp1; ++ memcpy(p11, init1, (u32)8U * sizeof(init1[0U])); ++ x0 = p03; ++ z0 = p03 + (u32)4U; ++ x0[0U] = (u64)1U; ++ x0[1U] = (u64)0U; ++ x0[2U] = (u64)0U; ++ x0[3U] = (u64)0U; ++ z0[0U] = (u64)0U; ++ z0[1U] = (u64)0U; ++ z0[2U] = (u64)0U; ++ z0[3U] = (u64)0U; ++ p01_tmp1 = p01_tmp1_swap; ++ p01_tmp11 = p01_tmp1_swap; ++ nq10 = p01_tmp1_swap; ++ nq_p11 = p01_tmp1_swap + (u32)8U; ++ swap1 = p01_tmp1_swap + (u32)32U; ++ cswap2((u64)1U, nq10, nq_p11); ++ point_add_and_double(init1, p01_tmp11, tmp2); ++ swap1[0U] = (u64)1U; ++ { ++ u32 i; ++ for (i = (u32)0U; i < (u32)251U; i = i + (u32)1U) { ++ u64 *p01_tmp12 = p01_tmp1_swap; ++ u64 *swap2 = p01_tmp1_swap + (u32)32U; ++ u64 *nq2 = p01_tmp12; ++ u64 *nq_p12 = p01_tmp12 + (u32)8U; ++ u64 bit = (u64)(key[((u32)253U - i) / (u32)8U] >> ((u32)253U - i) % (u32)8U & (u8)1U); ++ u64 sw = swap2[0U] ^ bit; ++ cswap2(sw, nq2, nq_p12); ++ point_add_and_double(init1, p01_tmp12, tmp2); ++ swap2[0U] = bit; + } +- j = 0; + } +- +- /* Doubling */ +- for (i = 0; i < q; ++i) { +- add_eltfp25519_1w_adx(A, Ur1, Zr1); /* A = Ur1+Zr1 */ +- sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ +- sqr_eltfp25519_2w_adx(AB); /* A = A**2 B = B**2 */ +- copy_eltfp25519_1w(C, B); /* C = B */ +- sub_eltfp25519_1w(B, A, B); /* B = A-B */ +- mul_a24_eltfp25519_1w(D, B); /* D = my_a24*B */ +- add_eltfp25519_1w_adx(D, D, C); /* D = D+C */ +- mul_eltfp25519_2w_adx(UZr1, AB, CD); /* Ur1 = A*B Zr1 = Zr1*A */ +- } +- +- /* Convert to affine coordinates */ +- inv_eltfp25519_1w_adx(A, Zr1); +- mul_eltfp25519_1w_adx((u64 *)session_key, Ur1, A); +- fred_eltfp25519_1w((u64 *)session_key); +- +- memzero_explicit(&m, sizeof(m)); +-} +- +-static void curve25519_bmi2(u8 shared[CURVE25519_KEY_SIZE], +- const u8 private_key[CURVE25519_KEY_SIZE], +- const u8 session_key[CURVE25519_KEY_SIZE]) +-{ +- struct { +- u64 buffer[4 * NUM_WORDS_ELTFP25519]; +- u64 coordinates[4 * NUM_WORDS_ELTFP25519]; +- u64 workspace[6 * NUM_WORDS_ELTFP25519]; +- u8 session[CURVE25519_KEY_SIZE]; +- u8 private[CURVE25519_KEY_SIZE]; +- } __aligned(32) m; +- +- int i = 0, j = 0; +- u64 prev = 0; +- u64 *const X1 = (u64 *)m.session; +- u64 *const key = (u64 *)m.private; +- u64 *const Px = m.coordinates + 0; +- u64 *const Pz = m.coordinates + 4; +- u64 *const Qx = m.coordinates + 8; +- u64 *const Qz = m.coordinates + 12; +- u64 *const X2 = Qx; +- u64 *const Z2 = Qz; +- u64 *const X3 = Px; +- u64 *const Z3 = Pz; +- u64 *const X2Z2 = Qx; +- u64 *const X3Z3 = Px; +- +- u64 *const A = m.workspace + 0; +- u64 *const B = m.workspace + 4; +- u64 *const D = m.workspace + 8; +- u64 *const C = m.workspace + 12; +- u64 *const DA = m.workspace + 16; +- u64 *const CB = m.workspace + 20; +- u64 *const AB = A; +- u64 *const DC = D; +- u64 *const DACB = DA; +- +- memcpy(m.private, private_key, sizeof(m.private)); +- memcpy(m.session, session_key, sizeof(m.session)); +- +- curve25519_clamp_secret(m.private); +- +- /* As in the draft: +- * When receiving such an array, implementations of curve25519 +- * MUST mask the most-significant bit in the final byte. This +- * is done to preserve compatibility with point formats which +- * reserve the sign bit for use in other protocols and to +- * increase resistance to implementation fingerprinting +- */ +- m.session[CURVE25519_KEY_SIZE - 1] &= (1 << (255 % 8)) - 1; +- +- copy_eltfp25519_1w(Px, X1); +- setzero_eltfp25519_1w(Pz); +- setzero_eltfp25519_1w(Qx); +- setzero_eltfp25519_1w(Qz); +- +- Pz[0] = 1; +- Qx[0] = 1; +- +- /* main-loop */ +- prev = 0; +- j = 62; +- for (i = 3; i >= 0; --i) { +- while (j >= 0) { +- u64 bit = (key[i] >> j) & 0x1; +- u64 swap = bit ^ prev; +- prev = bit; +- +- add_eltfp25519_1w_bmi2(A, X2, Z2); /* A = (X2+Z2) */ +- sub_eltfp25519_1w(B, X2, Z2); /* B = (X2-Z2) */ +- add_eltfp25519_1w_bmi2(C, X3, Z3); /* C = (X3+Z3) */ +- sub_eltfp25519_1w(D, X3, Z3); /* D = (X3-Z3) */ +- mul_eltfp25519_2w_bmi2(DACB, AB, DC); /* [DA|CB] = [A|B]*[D|C] */ +- +- cselect(swap, A, C); +- cselect(swap, B, D); +- +- sqr_eltfp25519_2w_bmi2(AB); /* [AA|BB] = [A^2|B^2] */ +- add_eltfp25519_1w_bmi2(X3, DA, CB); /* X3 = (DA+CB) */ +- sub_eltfp25519_1w(Z3, DA, CB); /* Z3 = (DA-CB) */ +- sqr_eltfp25519_2w_bmi2(X3Z3); /* [X3|Z3] = [(DA+CB)|(DA+CB)]^2 */ +- +- copy_eltfp25519_1w(X2, B); /* X2 = B^2 */ +- sub_eltfp25519_1w(Z2, A, B); /* Z2 = E = AA-BB */ +- +- mul_a24_eltfp25519_1w(B, Z2); /* B = a24*E */ +- add_eltfp25519_1w_bmi2(B, B, X2); /* B = a24*E+B */ +- mul_eltfp25519_2w_bmi2(X2Z2, X2Z2, AB); /* [X2|Z2] = [B|E]*[A|a24*E+B] */ +- mul_eltfp25519_1w_bmi2(Z3, Z3, X1); /* Z3 = Z3*X1 */ +- --j; ++ sw0 = swap1[0U]; ++ cswap2(sw0, nq10, nq_p11); ++ nq1 = p01_tmp1; ++ tmp1 = p01_tmp1 + (u32)16U; ++ point_double(nq1, tmp1, tmp2); ++ point_double(nq1, tmp1, tmp2); ++ point_double(nq1, tmp1, tmp2); ++ memcpy(out, p0, (u32)8U * sizeof(p0[0U])); ++ ++ memzero_explicit(tmp2, sizeof(tmp2)); ++ memzero_explicit(p01_tmp1_swap, sizeof(p01_tmp1_swap)); ++} ++ ++static void fsquare_times(u64 *o, const u64 *inp, u64 *tmp, u32 n1) ++{ ++ u32 i; ++ fsqr(o, inp, tmp); ++ for (i = (u32)0U; i < n1 - (u32)1U; i = i + (u32)1U) ++ fsqr(o, o, tmp); ++} ++ ++static void finv(u64 *o, const u64 *i, u64 *tmp) ++{ ++ u64 t1[16U] = { 0U }; ++ u64 *a0 = t1; ++ u64 *b = t1 + (u32)4U; ++ u64 *c = t1 + (u32)8U; ++ u64 *t00 = t1 + (u32)12U; ++ u64 *tmp1 = tmp; ++ u64 *a; ++ u64 *t0; ++ fsquare_times(a0, i, tmp1, (u32)1U); ++ fsquare_times(t00, a0, tmp1, (u32)2U); ++ fmul(b, t00, i, tmp); ++ fmul(a0, b, a0, tmp); ++ fsquare_times(t00, a0, tmp1, (u32)1U); ++ fmul(b, t00, b, tmp); ++ fsquare_times(t00, b, tmp1, (u32)5U); ++ fmul(b, t00, b, tmp); ++ fsquare_times(t00, b, tmp1, (u32)10U); ++ fmul(c, t00, b, tmp); ++ fsquare_times(t00, c, tmp1, (u32)20U); ++ fmul(t00, t00, c, tmp); ++ fsquare_times(t00, t00, tmp1, (u32)10U); ++ fmul(b, t00, b, tmp); ++ fsquare_times(t00, b, tmp1, (u32)50U); ++ fmul(c, t00, b, tmp); ++ fsquare_times(t00, c, tmp1, (u32)100U); ++ fmul(t00, t00, c, tmp); ++ fsquare_times(t00, t00, tmp1, (u32)50U); ++ fmul(t00, t00, b, tmp); ++ fsquare_times(t00, t00, tmp1, (u32)5U); ++ a = t1; ++ t0 = t1 + (u32)12U; ++ fmul(o, t0, a, tmp); ++} ++ ++static void store_felem(u64 *b, u64 *f) ++{ ++ u64 f30 = f[3U]; ++ u64 top_bit0 = f30 >> (u32)63U; ++ u64 carry0; ++ u64 f31; ++ u64 top_bit; ++ u64 carry; ++ u64 f0; ++ u64 f1; ++ u64 f2; ++ u64 f3; ++ u64 m0; ++ u64 m1; ++ u64 m2; ++ u64 m3; ++ u64 mask; ++ u64 f0_; ++ u64 f1_; ++ u64 f2_; ++ u64 f3_; ++ u64 o0; ++ u64 o1; ++ u64 o2; ++ u64 o3; ++ f[3U] = f30 & (u64)0x7fffffffffffffffU; ++ carry0 = add_scalar(f, f, (u64)19U * top_bit0); ++ f31 = f[3U]; ++ top_bit = f31 >> (u32)63U; ++ f[3U] = f31 & (u64)0x7fffffffffffffffU; ++ carry = add_scalar(f, f, (u64)19U * top_bit); ++ f0 = f[0U]; ++ f1 = f[1U]; ++ f2 = f[2U]; ++ f3 = f[3U]; ++ m0 = gte_mask(f0, (u64)0xffffffffffffffedU); ++ m1 = eq_mask(f1, (u64)0xffffffffffffffffU); ++ m2 = eq_mask(f2, (u64)0xffffffffffffffffU); ++ m3 = eq_mask(f3, (u64)0x7fffffffffffffffU); ++ mask = ((m0 & m1) & m2) & m3; ++ f0_ = f0 - (mask & (u64)0xffffffffffffffedU); ++ f1_ = f1 - (mask & (u64)0xffffffffffffffffU); ++ f2_ = f2 - (mask & (u64)0xffffffffffffffffU); ++ f3_ = f3 - (mask & (u64)0x7fffffffffffffffU); ++ o0 = f0_; ++ o1 = f1_; ++ o2 = f2_; ++ o3 = f3_; ++ b[0U] = o0; ++ b[1U] = o1; ++ b[2U] = o2; ++ b[3U] = o3; ++} ++ ++static void encode_point(u8 *o, const u64 *i) ++{ ++ const u64 *x = i; ++ const u64 *z = i + (u32)4U; ++ u64 tmp[4U] = { 0U }; ++ u64 tmp_w[16U] = { 0U }; ++ finv(tmp, z, tmp_w); ++ fmul(tmp, tmp, x, tmp_w); ++ store_felem((u64 *)o, tmp); ++} ++ ++static void curve25519_ever64(u8 *out, const u8 *priv, const u8 *pub) ++{ ++ u64 init1[8U] = { 0U }; ++ u64 tmp[4U] = { 0U }; ++ u64 tmp3; ++ u64 *x; ++ u64 *z; ++ { ++ u32 i; ++ for (i = (u32)0U; i < (u32)4U; i = i + (u32)1U) { ++ u64 *os = tmp; ++ const u8 *bj = pub + i * (u32)8U; ++ u64 u = *(u64 *)bj; ++ u64 r = u; ++ u64 x0 = r; ++ os[i] = x0; + } +- j = 63; + } ++ tmp3 = tmp[3U]; ++ tmp[3U] = tmp3 & (u64)0x7fffffffffffffffU; ++ x = init1; ++ z = init1 + (u32)4U; ++ z[0U] = (u64)1U; ++ z[1U] = (u64)0U; ++ z[2U] = (u64)0U; ++ z[3U] = (u64)0U; ++ x[0U] = tmp[0U]; ++ x[1U] = tmp[1U]; ++ x[2U] = tmp[2U]; ++ x[3U] = tmp[3U]; ++ montgomery_ladder(init1, priv, init1); ++ encode_point(out, init1); ++} ++ ++/* The below constants were generated using this sage script: ++ * ++ * #!/usr/bin/env sage ++ * import sys ++ * from sage.all import * ++ * def limbs(n): ++ * n = int(n) ++ * l = ((n >> 0) % 2^64, (n >> 64) % 2^64, (n >> 128) % 2^64, (n >> 192) % 2^64) ++ * return "0x%016xULL, 0x%016xULL, 0x%016xULL, 0x%016xULL" % l ++ * ec = EllipticCurve(GF(2^255 - 19), [0, 486662, 0, 1, 0]) ++ * p_minus_s = (ec.lift_x(9) - ec.lift_x(1))[0] ++ * print("static const u64 p_minus_s[] = { %s };\n" % limbs(p_minus_s)) ++ * print("static const u64 table_ladder[] = {") ++ * p = ec.lift_x(9) ++ * for i in range(252): ++ * l = (p[0] + p[2]) / (p[0] - p[2]) ++ * print(("\t%s" + ("," if i != 251 else "")) % limbs(l)) ++ * p = p * 2 ++ * print("};") ++ * ++ */ + +- inv_eltfp25519_1w_bmi2(A, Qz); +- mul_eltfp25519_1w_bmi2((u64 *)shared, Qx, A); +- fred_eltfp25519_1w((u64 *)shared); ++static const u64 p_minus_s[] = { 0x816b1e0137d48290ULL, 0x440f6a51eb4d1207ULL, 0x52385f46dca2b71dULL, 0x215132111d8354cbULL }; + +- memzero_explicit(&m, sizeof(m)); +-} ++static const u64 table_ladder[] = { ++ 0xfffffffffffffff3ULL, 0xffffffffffffffffULL, 0xffffffffffffffffULL, 0x5fffffffffffffffULL, ++ 0x6b8220f416aafe96ULL, 0x82ebeb2b4f566a34ULL, 0xd5a9a5b075a5950fULL, 0x5142b2cf4b2488f4ULL, ++ 0x6aaebc750069680cULL, 0x89cf7820a0f99c41ULL, 0x2a58d9183b56d0f4ULL, 0x4b5aca80e36011a4ULL, ++ 0x329132348c29745dULL, 0xf4a2e616e1642fd7ULL, 0x1e45bb03ff67bc34ULL, 0x306912d0f42a9b4aULL, ++ 0xff886507e6af7154ULL, 0x04f50e13dfeec82fULL, 0xaa512fe82abab5ceULL, 0x174e251a68d5f222ULL, ++ 0xcf96700d82028898ULL, 0x1743e3370a2c02c5ULL, 0x379eec98b4e86eaaULL, 0x0c59888a51e0482eULL, ++ 0xfbcbf1d699b5d189ULL, 0xacaef0d58e9fdc84ULL, 0xc1c20d06231f7614ULL, 0x2938218da274f972ULL, ++ 0xf6af49beff1d7f18ULL, 0xcc541c22387ac9c2ULL, 0x96fcc9ef4015c56bULL, 0x69c1627c690913a9ULL, ++ 0x7a86fd2f4733db0eULL, 0xfdb8c4f29e087de9ULL, 0x095e4b1a8ea2a229ULL, 0x1ad7a7c829b37a79ULL, ++ 0x342d89cad17ea0c0ULL, 0x67bedda6cced2051ULL, 0x19ca31bf2bb42f74ULL, 0x3df7b4c84980acbbULL, ++ 0xa8c6444dc80ad883ULL, 0xb91e440366e3ab85ULL, 0xc215cda00164f6d8ULL, 0x3d867c6ef247e668ULL, ++ 0xc7dd582bcc3e658cULL, 0xfd2c4748ee0e5528ULL, 0xa0fd9b95cc9f4f71ULL, 0x7529d871b0675ddfULL, ++ 0xb8f568b42d3cbd78ULL, 0x1233011b91f3da82ULL, 0x2dce6ccd4a7c3b62ULL, 0x75e7fc8e9e498603ULL, ++ 0x2f4f13f1fcd0b6ecULL, 0xf1a8ca1f29ff7a45ULL, 0xc249c1a72981e29bULL, 0x6ebe0dbb8c83b56aULL, ++ 0x7114fa8d170bb222ULL, 0x65a2dcd5bf93935fULL, 0xbdc41f68b59c979aULL, 0x2f0eef79a2ce9289ULL, ++ 0x42ecbf0c083c37ceULL, 0x2930bc09ec496322ULL, 0xf294b0c19cfeac0dULL, 0x3780aa4bedfabb80ULL, ++ 0x56c17d3e7cead929ULL, 0xe7cb4beb2e5722c5ULL, 0x0ce931732dbfe15aULL, 0x41b883c7621052f8ULL, ++ 0xdbf75ca0c3d25350ULL, 0x2936be086eb1e351ULL, 0xc936e03cb4a9b212ULL, 0x1d45bf82322225aaULL, ++ 0xe81ab1036a024cc5ULL, 0xe212201c304c9a72ULL, 0xc5d73fba6832b1fcULL, 0x20ffdb5a4d839581ULL, ++ 0xa283d367be5d0fadULL, 0x6c2b25ca8b164475ULL, 0x9d4935467caaf22eULL, 0x5166408eee85ff49ULL, ++ 0x3c67baa2fab4e361ULL, 0xb3e433c67ef35cefULL, 0x5259729241159b1cULL, 0x6a621892d5b0ab33ULL, ++ 0x20b74a387555cdcbULL, 0x532aa10e1208923fULL, 0xeaa17b7762281dd1ULL, 0x61ab3443f05c44bfULL, ++ 0x257a6c422324def8ULL, 0x131c6c1017e3cf7fULL, 0x23758739f630a257ULL, 0x295a407a01a78580ULL, ++ 0xf8c443246d5da8d9ULL, 0x19d775450c52fa5dULL, 0x2afcfc92731bf83dULL, 0x7d10c8e81b2b4700ULL, ++ 0xc8e0271f70baa20bULL, 0x993748867ca63957ULL, 0x5412efb3cb7ed4bbULL, 0x3196d36173e62975ULL, ++ 0xde5bcad141c7dffcULL, 0x47cc8cd2b395c848ULL, 0xa34cd942e11af3cbULL, 0x0256dbf2d04ecec2ULL, ++ 0x875ab7e94b0e667fULL, 0xcad4dd83c0850d10ULL, 0x47f12e8f4e72c79fULL, 0x5f1a87bb8c85b19bULL, ++ 0x7ae9d0b6437f51b8ULL, 0x12c7ce5518879065ULL, 0x2ade09fe5cf77aeeULL, 0x23a05a2f7d2c5627ULL, ++ 0x5908e128f17c169aULL, 0xf77498dd8ad0852dULL, 0x74b4c4ceab102f64ULL, 0x183abadd10139845ULL, ++ 0xb165ba8daa92aaacULL, 0xd5c5ef9599386705ULL, 0xbe2f8f0cf8fc40d1ULL, 0x2701e635ee204514ULL, ++ 0x629fa80020156514ULL, 0xf223868764a8c1ceULL, 0x5b894fff0b3f060eULL, 0x60d9944cf708a3faULL, ++ 0xaeea001a1c7a201fULL, 0xebf16a633ee2ce63ULL, 0x6f7709594c7a07e1ULL, 0x79b958150d0208cbULL, ++ 0x24b55e5301d410e7ULL, 0xe3a34edff3fdc84dULL, 0xd88768e4904032d8ULL, 0x131384427b3aaeecULL, ++ 0x8405e51286234f14ULL, 0x14dc4739adb4c529ULL, 0xb8a2b5b250634ffdULL, 0x2fe2a94ad8a7ff93ULL, ++ 0xec5c57efe843faddULL, 0x2843ce40f0bb9918ULL, 0xa4b561d6cf3d6305ULL, 0x743629bde8fb777eULL, ++ 0x343edd46bbaf738fULL, 0xed981828b101a651ULL, 0xa401760b882c797aULL, 0x1fc223e28dc88730ULL, ++ 0x48604e91fc0fba0eULL, 0xb637f78f052c6fa4ULL, 0x91ccac3d09e9239cULL, 0x23f7eed4437a687cULL, ++ 0x5173b1118d9bd800ULL, 0x29d641b63189d4a7ULL, 0xfdbf177988bbc586ULL, 0x2959894fcad81df5ULL, ++ 0xaebc8ef3b4bbc899ULL, 0x4148995ab26992b9ULL, 0x24e20b0134f92cfbULL, 0x40d158894a05dee8ULL, ++ 0x46b00b1185af76f6ULL, 0x26bac77873187a79ULL, 0x3dc0bf95ab8fff5fULL, 0x2a608bd8945524d7ULL, ++ 0x26449588bd446302ULL, 0x7c4bc21c0388439cULL, 0x8e98a4f383bd11b2ULL, 0x26218d7bc9d876b9ULL, ++ 0xe3081542997c178aULL, 0x3c2d29a86fb6606fULL, 0x5c217736fa279374ULL, 0x7dde05734afeb1faULL, ++ 0x3bf10e3906d42babULL, 0xe4f7803e1980649cULL, 0xe6053bf89595bf7aULL, 0x394faf38da245530ULL, ++ 0x7a8efb58896928f4ULL, 0xfbc778e9cc6a113cULL, 0x72670ce330af596fULL, 0x48f222a81d3d6cf7ULL, ++ 0xf01fce410d72caa7ULL, 0x5a20ecc7213b5595ULL, 0x7bc21165c1fa1483ULL, 0x07f89ae31da8a741ULL, ++ 0x05d2c2b4c6830ff9ULL, 0xd43e330fc6316293ULL, 0xa5a5590a96d3a904ULL, 0x705edb91a65333b6ULL, ++ 0x048ee15e0bb9a5f7ULL, 0x3240cfca9e0aaf5dULL, 0x8f4b71ceedc4a40bULL, 0x621c0da3de544a6dULL, ++ 0x92872836a08c4091ULL, 0xce8375b010c91445ULL, 0x8a72eb524f276394ULL, 0x2667fcfa7ec83635ULL, ++ 0x7f4c173345e8752aULL, 0x061b47feee7079a5ULL, 0x25dd9afa9f86ff34ULL, 0x3780cef5425dc89cULL, ++ 0x1a46035a513bb4e9ULL, 0x3e1ef379ac575adaULL, 0xc78c5f1c5fa24b50ULL, 0x321a967634fd9f22ULL, ++ 0x946707b8826e27faULL, 0x3dca84d64c506fd0ULL, 0xc189218075e91436ULL, 0x6d9284169b3b8484ULL, ++ 0x3a67e840383f2ddfULL, 0x33eec9a30c4f9b75ULL, 0x3ec7c86fa783ef47ULL, 0x26ec449fbac9fbc4ULL, ++ 0x5c0f38cba09b9e7dULL, 0x81168cc762a3478cULL, 0x3e23b0d306fc121cULL, 0x5a238aa0a5efdcddULL, ++ 0x1ba26121c4ea43ffULL, 0x36f8c77f7c8832b5ULL, 0x88fbea0b0adcf99aULL, 0x5ca9938ec25bebf9ULL, ++ 0xd5436a5e51fccda0ULL, 0x1dbc4797c2cd893bULL, 0x19346a65d3224a08ULL, 0x0f5034e49b9af466ULL, ++ 0xf23c3967a1e0b96eULL, 0xe58b08fa867a4d88ULL, 0xfb2fabc6a7341679ULL, 0x2a75381eb6026946ULL, ++ 0xc80a3be4c19420acULL, 0x66b1f6c681f2b6dcULL, 0x7cf7036761e93388ULL, 0x25abbbd8a660a4c4ULL, ++ 0x91ea12ba14fd5198ULL, 0x684950fc4a3cffa9ULL, 0xf826842130f5ad28ULL, 0x3ea988f75301a441ULL, ++ 0xc978109a695f8c6fULL, 0x1746eb4a0530c3f3ULL, 0x444d6d77b4459995ULL, 0x75952b8c054e5cc7ULL, ++ 0xa3703f7915f4d6aaULL, 0x66c346202f2647d8ULL, 0xd01469df811d644bULL, 0x77fea47d81a5d71fULL, ++ 0xc5e9529ef57ca381ULL, 0x6eeeb4b9ce2f881aULL, 0xb6e91a28e8009bd6ULL, 0x4b80be3e9afc3fecULL, ++ 0x7e3773c526aed2c5ULL, 0x1b4afcb453c9a49dULL, 0xa920bdd7baffb24dULL, 0x7c54699f122d400eULL, ++ 0xef46c8e14fa94bc8ULL, 0xe0b074ce2952ed5eULL, 0xbea450e1dbd885d5ULL, 0x61b68649320f712cULL, ++ 0x8a485f7309ccbdd1ULL, 0xbd06320d7d4d1a2dULL, 0x25232973322dbef4ULL, 0x445dc4758c17f770ULL, ++ 0xdb0434177cc8933cULL, 0xed6fe82175ea059fULL, 0x1efebefdc053db34ULL, 0x4adbe867c65daf99ULL, ++ 0x3acd71a2a90609dfULL, 0xe5e991856dd04050ULL, 0x1ec69b688157c23cULL, 0x697427f6885cfe4dULL, ++ 0xd7be7b9b65e1a851ULL, 0xa03d28d522c536ddULL, 0x28399d658fd2b645ULL, 0x49e5b7e17c2641e1ULL, ++ 0x6f8c3a98700457a4ULL, 0x5078f0a25ebb6778ULL, 0xd13c3ccbc382960fULL, 0x2e003258a7df84b1ULL, ++ 0x8ad1f39be6296a1cULL, 0xc1eeaa652a5fbfb2ULL, 0x33ee0673fd26f3cbULL, 0x59256173a69d2cccULL, ++ 0x41ea07aa4e18fc41ULL, 0xd9fc19527c87a51eULL, 0xbdaacb805831ca6fULL, 0x445b652dc916694fULL, ++ 0xce92a3a7f2172315ULL, 0x1edc282de11b9964ULL, 0xa1823aafe04c314aULL, 0x790a2d94437cf586ULL, ++ 0x71c447fb93f6e009ULL, 0x8922a56722845276ULL, 0xbf70903b204f5169ULL, 0x2f7a89891ba319feULL, ++ 0x02a08eb577e2140cULL, 0xed9a4ed4427bdcf4ULL, 0x5253ec44e4323cd1ULL, 0x3e88363c14e9355bULL, ++ 0xaa66c14277110b8cULL, 0x1ae0391610a23390ULL, 0x2030bd12c93fc2a2ULL, 0x3ee141579555c7abULL, ++ 0x9214de3a6d6e7d41ULL, 0x3ccdd88607f17efeULL, 0x674f1288f8e11217ULL, 0x5682250f329f93d0ULL, ++ 0x6cf00b136d2e396eULL, 0x6e4cf86f1014debfULL, 0x5930b1b5bfcc4e83ULL, 0x047069b48aba16b6ULL, ++ 0x0d4ce4ab69b20793ULL, 0xb24db91a97d0fb9eULL, 0xcdfa50f54e00d01dULL, 0x221b1085368bddb5ULL, ++ 0xe7e59468b1e3d8d2ULL, 0x53c56563bd122f93ULL, 0xeee8a903e0663f09ULL, 0x61efa662cbbe3d42ULL, ++ 0x2cf8ddddde6eab2aULL, 0x9bf80ad51435f231ULL, 0x5deadacec9f04973ULL, 0x29275b5d41d29b27ULL, ++ 0xcfde0f0895ebf14fULL, 0xb9aab96b054905a7ULL, 0xcae80dd9a1c420fdULL, 0x0a63bf2f1673bbc7ULL, ++ 0x092f6e11958fbc8cULL, 0x672a81e804822fadULL, 0xcac8351560d52517ULL, 0x6f3f7722c8f192f8ULL, ++ 0xf8ba90ccc2e894b7ULL, 0x2c7557a438ff9f0dULL, 0x894d1d855ae52359ULL, 0x68e122157b743d69ULL, ++ 0xd87e5570cfb919f3ULL, 0x3f2cdecd95798db9ULL, 0x2121154710c0a2ceULL, 0x3c66a115246dc5b2ULL, ++ 0xcbedc562294ecb72ULL, 0xba7143c36a280b16ULL, 0x9610c2efd4078b67ULL, 0x6144735d946a4b1eULL, ++ 0x536f111ed75b3350ULL, 0x0211db8c2041d81bULL, 0xf93cb1000e10413cULL, 0x149dfd3c039e8876ULL, ++ 0xd479dde46b63155bULL, 0xb66e15e93c837976ULL, 0xdafde43b1f13e038ULL, 0x5fafda1a2e4b0b35ULL, ++ 0x3600bbdf17197581ULL, 0x3972050bbe3cd2c2ULL, 0x5938906dbdd5be86ULL, 0x34fce5e43f9b860fULL, ++ 0x75a8a4cd42d14d02ULL, 0x828dabc53441df65ULL, 0x33dcabedd2e131d3ULL, 0x3ebad76fb814d25fULL, ++ 0xd4906f566f70e10fULL, 0x5d12f7aa51690f5aULL, 0x45adb16e76cefcf2ULL, 0x01f768aead232999ULL, ++ 0x2b6cc77b6248febdULL, 0x3cd30628ec3aaffdULL, 0xce1c0b80d4ef486aULL, 0x4c3bff2ea6f66c23ULL, ++ 0x3f2ec4094aeaeb5fULL, 0x61b19b286e372ca7ULL, 0x5eefa966de2a701dULL, 0x23b20565de55e3efULL, ++ 0xe301ca5279d58557ULL, 0x07b2d4ce27c2874fULL, 0xa532cd8a9dcf1d67ULL, 0x2a52fee23f2bff56ULL, ++ 0x8624efb37cd8663dULL, 0xbbc7ac20ffbd7594ULL, 0x57b85e9c82d37445ULL, 0x7b3052cb86a6ec66ULL, ++ 0x3482f0ad2525e91eULL, 0x2cb68043d28edca0ULL, 0xaf4f6d052e1b003aULL, 0x185f8c2529781b0aULL, ++ 0xaa41de5bd80ce0d6ULL, 0x9407b2416853e9d6ULL, 0x563ec36e357f4c3aULL, 0x4cc4b8dd0e297bceULL, ++ 0xa2fc1a52ffb8730eULL, 0x1811f16e67058e37ULL, 0x10f9a366cddf4ee1ULL, 0x72f4a0c4a0b9f099ULL, ++ 0x8c16c06f663f4ea7ULL, 0x693b3af74e970fbaULL, 0x2102e7f1d69ec345ULL, 0x0ba53cbc968a8089ULL, ++ 0xca3d9dc7fea15537ULL, 0x4c6824bb51536493ULL, 0xb9886314844006b1ULL, 0x40d2a72ab454cc60ULL, ++ 0x5936a1b712570975ULL, 0x91b9d648debda657ULL, 0x3344094bb64330eaULL, 0x006ba10d12ee51d0ULL, ++ 0x19228468f5de5d58ULL, 0x0eb12f4c38cc05b0ULL, 0xa1039f9dd5601990ULL, 0x4502d4ce4fff0e0bULL, ++ 0xeb2054106837c189ULL, 0xd0f6544c6dd3b93cULL, 0x40727064c416d74fULL, 0x6e15c6114b502ef0ULL, ++ 0x4df2a398cfb1a76bULL, 0x11256c7419f2f6b1ULL, 0x4a497962066e6043ULL, 0x705b3aab41355b44ULL, ++ 0x365ef536d797b1d8ULL, 0x00076bd622ddf0dbULL, 0x3bbf33b0e0575a88ULL, 0x3777aa05c8e4ca4dULL, ++ 0x392745c85578db5fULL, 0x6fda4149dbae5ae2ULL, 0xb1f0b00b8adc9867ULL, 0x09963437d36f1da3ULL, ++ 0x7e824e90a5dc3853ULL, 0xccb5f6641f135cbdULL, 0x6736d86c87ce8fccULL, 0x625f3ce26604249fULL, ++ 0xaf8ac8059502f63fULL, 0x0c05e70a2e351469ULL, 0x35292e9c764b6305ULL, 0x1a394360c7e23ac3ULL, ++ 0xd5c6d53251183264ULL, 0x62065abd43c2b74fULL, 0xb5fbf5d03b973f9bULL, 0x13a3da3661206e5eULL, ++ 0xc6bd5837725d94e5ULL, 0x18e30912205016c5ULL, 0x2088ce1570033c68ULL, 0x7fba1f495c837987ULL, ++ 0x5a8c7423f2f9079dULL, 0x1735157b34023fc5ULL, 0xe4f9b49ad2fab351ULL, 0x6691ff72c878e33cULL, ++ 0x122c2adedc5eff3eULL, 0xf8dd4bf1d8956cf4ULL, 0xeb86205d9e9e5bdaULL, 0x049b92b9d975c743ULL, ++ 0xa5379730b0f6c05aULL, 0x72a0ffacc6f3a553ULL, 0xb0032c34b20dcd6dULL, 0x470e9dbc88d5164aULL, ++ 0xb19cf10ca237c047ULL, 0xb65466711f6c81a2ULL, 0xb3321bd16dd80b43ULL, 0x48c14f600c5fbe8eULL, ++ 0x66451c264aa6c803ULL, 0xb66e3904a4fa7da6ULL, 0xd45f19b0b3128395ULL, 0x31602627c3c9bc10ULL, ++ 0x3120dc4832e4e10dULL, 0xeb20c46756c717f7ULL, 0x00f52e3f67280294ULL, 0x566d4fc14730c509ULL, ++ 0x7e3a5d40fd837206ULL, 0xc1e926dc7159547aULL, 0x216730fba68d6095ULL, 0x22e8c3843f69cea7ULL, ++ 0x33d074e8930e4b2bULL, 0xb6e4350e84d15816ULL, 0x5534c26ad6ba2365ULL, 0x7773c12f89f1f3f3ULL, ++ 0x8cba404da57962aaULL, 0x5b9897a81999ce56ULL, 0x508e862f121692fcULL, 0x3a81907fa093c291ULL, ++ 0x0dded0ff4725a510ULL, 0x10d8cc10673fc503ULL, 0x5b9d151c9f1f4e89ULL, 0x32a5c1d5cb09a44cULL, ++ 0x1e0aa442b90541fbULL, 0x5f85eb7cc1b485dbULL, 0xbee595ce8a9df2e5ULL, 0x25e496c722422236ULL, ++ 0x5edf3c46cd0fe5b9ULL, 0x34e75a7ed2a43388ULL, 0xe488de11d761e352ULL, 0x0e878a01a085545cULL, ++ 0xba493c77e021bb04ULL, 0x2b4d1843c7df899aULL, 0x9ea37a487ae80d67ULL, 0x67a9958011e41794ULL, ++ 0x4b58051a6697b065ULL, 0x47e33f7d8d6ba6d4ULL, 0xbb4da8d483ca46c1ULL, 0x68becaa181c2db0dULL, ++ 0x8d8980e90b989aa5ULL, 0xf95eb14a2c93c99bULL, 0x51c6c7c4796e73a2ULL, 0x6e228363b5efb569ULL, ++ 0xc6bbc0b02dd624c8ULL, 0x777eb47dec8170eeULL, 0x3cde15a004cfafa9ULL, 0x1dc6bc087160bf9bULL, ++ 0x2e07e043eec34002ULL, 0x18e9fc677a68dc7fULL, 0xd8da03188bd15b9aULL, 0x48fbc3bb00568253ULL, ++ 0x57547d4cfb654ce1ULL, 0xd3565b82a058e2adULL, 0xf63eaf0bbf154478ULL, 0x47531ef114dfbb18ULL, ++ 0xe1ec630a4278c587ULL, 0x5507d546ca8e83f3ULL, 0x85e135c63adc0c2bULL, 0x0aa7efa85682844eULL, ++ 0x72691ba8b3e1f615ULL, 0x32b4e9701fbe3ffaULL, 0x97b6d92e39bb7868ULL, 0x2cfe53dea02e39e8ULL, ++ 0x687392cd85cd52b0ULL, 0x27ff66c910e29831ULL, 0x97134556a9832d06ULL, 0x269bb0360a84f8a0ULL, ++ 0x706e55457643f85cULL, 0x3734a48c9b597d1bULL, 0x7aee91e8c6efa472ULL, 0x5cd6abc198a9d9e0ULL, ++ 0x0e04de06cb3ce41aULL, 0xd8c6eb893402e138ULL, 0x904659bb686e3772ULL, 0x7215c371746ba8c8ULL, ++ 0xfd12a97eeae4a2d9ULL, 0x9514b7516394f2c5ULL, 0x266fd5809208f294ULL, 0x5c847085619a26b9ULL, ++ 0x52985410fed694eaULL, 0x3c905b934a2ed254ULL, 0x10bb47692d3be467ULL, 0x063b3d2d69e5e9e1ULL, ++ 0x472726eedda57debULL, 0xefb6c4ae10f41891ULL, 0x2b1641917b307614ULL, 0x117c554fc4f45b7cULL, ++ 0xc07cf3118f9d8812ULL, 0x01dbd82050017939ULL, 0xd7e803f4171b2827ULL, 0x1015e87487d225eaULL, ++ 0xc58de3fed23acc4dULL, 0x50db91c294a7be2dULL, 0x0b94d43d1c9cf457ULL, 0x6b1640fa6e37524aULL, ++ 0x692f346c5fda0d09ULL, 0x200b1c59fa4d3151ULL, 0xb8c46f760777a296ULL, 0x4b38395f3ffdfbcfULL, ++ 0x18d25e00be54d671ULL, 0x60d50582bec8aba6ULL, 0x87ad8f263b78b982ULL, 0x50fdf64e9cda0432ULL, ++ 0x90f567aac578dcf0ULL, 0xef1e9b0ef2a3133bULL, 0x0eebba9242d9de71ULL, 0x15473c9bf03101c7ULL, ++ 0x7c77e8ae56b78095ULL, 0xb678e7666e6f078eULL, 0x2da0b9615348ba1fULL, 0x7cf931c1ff733f0bULL, ++ 0x26b357f50a0a366cULL, 0xe9708cf42b87d732ULL, 0xc13aeea5f91cb2c0ULL, 0x35d90c991143bb4cULL, ++ 0x47c1c404a9a0d9dcULL, 0x659e58451972d251ULL, 0x3875a8c473b38c31ULL, 0x1fbd9ed379561f24ULL, ++ 0x11fabc6fd41ec28dULL, 0x7ef8dfe3cd2a2dcaULL, 0x72e73b5d8c404595ULL, 0x6135fa4954b72f27ULL, ++ 0xccfc32a2de24b69cULL, 0x3f55698c1f095d88ULL, 0xbe3350ed5ac3f929ULL, 0x5e9bf806ca477eebULL, ++ 0xe9ce8fb63c309f68ULL, 0x5376f63565e1f9f4ULL, 0xd1afcfb35a6393f1ULL, 0x6632a1ede5623506ULL, ++ 0x0b7d6c390c2ded4cULL, 0x56cb3281df04cb1fULL, 0x66305a1249ecc3c7ULL, 0x5d588b60a38ca72aULL, ++ 0xa6ecbf78e8e5f42dULL, 0x86eeb44b3c8a3eecULL, 0xec219c48fbd21604ULL, 0x1aaf1af517c36731ULL, ++ 0xc306a2836769bde7ULL, 0x208280622b1e2adbULL, 0x8027f51ffbff94a6ULL, 0x76cfa1ce1124f26bULL, ++ 0x18eb00562422abb6ULL, 0xf377c4d58f8c29c3ULL, 0x4dbbc207f531561aULL, 0x0253b7f082128a27ULL, ++ 0x3d1f091cb62c17e0ULL, 0x4860e1abd64628a9ULL, 0x52d17436309d4253ULL, 0x356f97e13efae576ULL, ++ 0xd351e11aa150535bULL, 0x3e6b45bb1dd878ccULL, 0x0c776128bed92c98ULL, 0x1d34ae93032885b8ULL, ++ 0x4ba0488ca85ba4c3ULL, 0x985348c33c9ce6ceULL, 0x66124c6f97bda770ULL, 0x0f81a0290654124aULL, ++ 0x9ed09ca6569b86fdULL, 0x811009fd18af9a2dULL, 0xff08d03f93d8c20aULL, 0x52a148199faef26bULL, ++ 0x3e03f9dc2d8d1b73ULL, 0x4205801873961a70ULL, 0xc0d987f041a35970ULL, 0x07aa1f15a1c0d549ULL, ++ 0xdfd46ce08cd27224ULL, 0x6d0a024f934e4239ULL, 0x808a7a6399897b59ULL, 0x0a4556e9e13d95a2ULL, ++ 0xd21a991fe9c13045ULL, 0x9b0e8548fe7751b8ULL, 0x5da643cb4bf30035ULL, 0x77db28d63940f721ULL, ++ 0xfc5eeb614adc9011ULL, 0x5229419ae8c411ebULL, 0x9ec3e7787d1dcf74ULL, 0x340d053e216e4cb5ULL, ++ 0xcac7af39b48df2b4ULL, 0xc0faec2871a10a94ULL, 0x140a69245ca575edULL, 0x0cf1c37134273a4cULL, ++ 0xc8ee306ac224b8a5ULL, 0x57eaee7ccb4930b0ULL, 0xa1e806bdaacbe74fULL, 0x7d9a62742eeb657dULL, ++ 0x9eb6b6ef546c4830ULL, 0x885cca1fddb36e2eULL, 0xe6b9f383ef0d7105ULL, 0x58654fef9d2e0412ULL, ++ 0xa905c4ffbe0e8e26ULL, 0x942de5df9b31816eULL, 0x497d723f802e88e1ULL, 0x30684dea602f408dULL, ++ 0x21e5a278a3e6cb34ULL, 0xaefb6e6f5b151dc4ULL, 0xb30b8e049d77ca15ULL, 0x28c3c9cf53b98981ULL, ++ 0x287fb721556cdd2aULL, 0x0d317ca897022274ULL, 0x7468c7423a543258ULL, 0x4a7f11464eb5642fULL, ++ 0xa237a4774d193aa6ULL, 0xd865986ea92129a1ULL, 0x24c515ecf87c1a88ULL, 0x604003575f39f5ebULL, ++ 0x47b9f189570a9b27ULL, 0x2b98cede465e4b78ULL, 0x026df551dbb85c20ULL, 0x74fcd91047e21901ULL, ++ 0x13e2a90a23c1bfa3ULL, 0x0cb0074e478519f6ULL, 0x5ff1cbbe3af6cf44ULL, 0x67fe5438be812dbeULL, ++ 0xd13cf64fa40f05b0ULL, 0x054dfb2f32283787ULL, 0x4173915b7f0d2aeaULL, 0x482f144f1f610d4eULL, ++ 0xf6210201b47f8234ULL, 0x5d0ae1929e70b990ULL, 0xdcd7f455b049567cULL, 0x7e93d0f1f0916f01ULL, ++ 0xdd79cbf18a7db4faULL, 0xbe8391bf6f74c62fULL, 0x027145d14b8291bdULL, 0x585a73ea2cbf1705ULL, ++ 0x485ca03e928a0db2ULL, 0x10fc01a5742857e7ULL, 0x2f482edbd6d551a7ULL, 0x0f0433b5048fdb8aULL, ++ 0x60da2e8dd7dc6247ULL, 0x88b4c9d38cd4819aULL, 0x13033ac001f66697ULL, 0x273b24fe3b367d75ULL, ++ 0xc6e8f66a31b3b9d4ULL, 0x281514a494df49d5ULL, 0xd1726fdfc8b23da7ULL, 0x4b3ae7d103dee548ULL, ++ 0xc6256e19ce4b9d7eULL, 0xff5c5cf186e3c61cULL, 0xacc63ca34b8ec145ULL, 0x74621888fee66574ULL, ++ 0x956f409645290a1eULL, 0xef0bf8e3263a962eULL, 0xed6a50eb5ec2647bULL, 0x0694283a9dca7502ULL, ++ 0x769b963643a2dcd1ULL, 0x42b7c8ea09fc5353ULL, 0x4f002aee13397eabULL, 0x63005e2c19b7d63aULL, ++ 0xca6736da63023beaULL, 0x966c7f6db12a99b7ULL, 0xace09390c537c5e1ULL, 0x0b696063a1aa89eeULL, ++ 0xebb03e97288c56e5ULL, 0x432a9f9f938c8be8ULL, 0xa6a5a93d5b717f71ULL, 0x1a5fb4c3e18f9d97ULL, ++ 0x1c94e7ad1c60cdceULL, 0xee202a43fc02c4a0ULL, 0x8dafe4d867c46a20ULL, 0x0a10263c8ac27b58ULL, ++ 0xd0dea9dfe4432a4aULL, 0x856af87bbe9277c5ULL, 0xce8472acc212c71aULL, 0x6f151b6d9bbb1e91ULL, ++ 0x26776c527ceed56aULL, 0x7d211cb7fbf8faecULL, 0x37ae66a6fd4609ccULL, 0x1f81b702d2770c42ULL, ++ 0x2fb0b057eac58392ULL, 0xe1dd89fe29744e9dULL, 0xc964f8eb17beb4f8ULL, 0x29571073c9a2d41eULL, ++ 0xa948a18981c0e254ULL, 0x2df6369b65b22830ULL, 0xa33eb2d75fcfd3c6ULL, 0x078cd6ec4199a01fULL, ++ 0x4a584a41ad900d2fULL, 0x32142b78e2c74c52ULL, 0x68c4e8338431c978ULL, 0x7f69ea9008689fc2ULL, ++ 0x52f2c81e46a38265ULL, 0xfd78072d04a832fdULL, 0x8cd7d5fa25359e94ULL, 0x4de71b7454cc29d2ULL, ++ 0x42eb60ad1eda6ac9ULL, 0x0aad37dfdbc09c3aULL, 0x81004b71e33cc191ULL, 0x44e6be345122803cULL, ++ 0x03fe8388ba1920dbULL, 0xf5d57c32150db008ULL, 0x49c8c4281af60c29ULL, 0x21edb518de701aeeULL, ++ 0x7fb63e418f06dc99ULL, 0xa4460d99c166d7b8ULL, 0x24dd5248ce520a83ULL, 0x5ec3ad712b928358ULL, ++ 0x15022a5fbd17930fULL, 0xa4f64a77d82570e3ULL, 0x12bc8d6915783712ULL, 0x498194c0fc620abbULL, ++ 0x38a2d9d255686c82ULL, 0x785c6bd9193e21f0ULL, 0xe4d5c81ab24a5484ULL, 0x56307860b2e20989ULL, ++ 0x429d55f78b4d74c4ULL, 0x22f1834643350131ULL, 0x1e60c24598c71fffULL, 0x59f2f014979983efULL, ++ 0x46a47d56eb494a44ULL, 0x3e22a854d636a18eULL, 0xb346e15274491c3bULL, 0x2ceafd4e5390cde7ULL, ++ 0xba8a8538be0d6675ULL, 0x4b9074bb50818e23ULL, 0xcbdab89085d304c3ULL, 0x61a24fe0e56192c4ULL, ++ 0xcb7615e6db525bcbULL, 0xdd7d8c35a567e4caULL, 0xe6b4153acafcdd69ULL, 0x2d668e097f3c9766ULL, ++ 0xa57e7e265ce55ef0ULL, 0x5d9f4e527cd4b967ULL, 0xfbc83606492fd1e5ULL, 0x090d52beb7c3f7aeULL, ++ 0x09b9515a1e7b4d7cULL, 0x1f266a2599da44c0ULL, 0xa1c49548e2c55504ULL, 0x7ef04287126f15ccULL, ++ 0xfed1659dbd30ef15ULL, 0x8b4ab9eec4e0277bULL, 0x884d6236a5df3291ULL, 0x1fd96ea6bf5cf788ULL, ++ 0x42a161981f190d9aULL, 0x61d849507e6052c1ULL, 0x9fe113bf285a2cd5ULL, 0x7c22d676dbad85d8ULL, ++ 0x82e770ed2bfbd27dULL, 0x4c05b2ece996f5a5ULL, 0xcd40a9c2b0900150ULL, 0x5895319213d9bf64ULL, ++ 0xe7cc5d703fea2e08ULL, 0xb50c491258e2188cULL, 0xcce30baa48205bf0ULL, 0x537c659ccfa32d62ULL, ++ 0x37b6623a98cfc088ULL, 0xfe9bed1fa4d6aca4ULL, 0x04d29b8e56a8d1b0ULL, 0x725f71c40b519575ULL, ++ 0x28c7f89cd0339ce6ULL, 0x8367b14469ddc18bULL, 0x883ada83a6a1652cULL, 0x585f1974034d6c17ULL, ++ 0x89cfb266f1b19188ULL, 0xe63b4863e7c35217ULL, 0xd88c9da6b4c0526aULL, 0x3e035c9df0954635ULL, ++ 0xdd9d5412fb45de9dULL, 0xdd684532e4cff40dULL, 0x4b5c999b151d671cULL, 0x2d8c2cc811e7f690ULL, ++ 0x7f54be1d90055d40ULL, 0xa464c5df464aaf40ULL, 0x33979624f0e917beULL, 0x2c018dc527356b30ULL, ++ 0xa5415024e330b3d4ULL, 0x73ff3d96691652d3ULL, 0x94ec42c4ef9b59f1ULL, 0x0747201618d08e5aULL, ++ 0x4d6ca48aca411c53ULL, 0x66415f2fcfa66119ULL, 0x9c4dd40051e227ffULL, 0x59810bc09a02f7ebULL, ++ 0x2a7eb171b3dc101dULL, 0x441c5ab99ffef68eULL, 0x32025c9b93b359eaULL, 0x5e8ce0a71e9d112fULL, ++ 0xbfcccb92429503fdULL, 0xd271ba752f095d55ULL, 0x345ead5e972d091eULL, 0x18c8df11a83103baULL, ++ 0x90cd949a9aed0f4cULL, 0xc5d1f4cb6660e37eULL, 0xb8cac52d56c52e0bULL, 0x6e42e400c5808e0dULL, ++ 0xa3b46966eeaefd23ULL, 0x0c4f1f0be39ecdcaULL, 0x189dc8c9d683a51dULL, 0x51f27f054c09351bULL, ++ 0x4c487ccd2a320682ULL, 0x587ea95bb3df1c96ULL, 0xc8ccf79e555cb8e8ULL, 0x547dc829a206d73dULL, ++ 0xb822a6cd80c39b06ULL, 0xe96d54732000d4c6ULL, 0x28535b6f91463b4dULL, 0x228f4660e2486e1dULL, ++ 0x98799538de8d3abfULL, 0x8cd8330045ebca6eULL, 0x79952a008221e738ULL, 0x4322e1a7535cd2bbULL, ++ 0xb114c11819d1801cULL, 0x2016e4d84f3f5ec7ULL, 0xdd0e2df409260f4cULL, 0x5ec362c0ae5f7266ULL, ++ 0xc0462b18b8b2b4eeULL, 0x7cc8d950274d1afbULL, 0xf25f7105436b02d2ULL, 0x43bbf8dcbff9ccd3ULL, ++ 0xb6ad1767a039e9dfULL, 0xb0714da8f69d3583ULL, 0x5e55fa18b42931f5ULL, 0x4ed5558f33c60961ULL, ++ 0x1fe37901c647a5ddULL, 0x593ddf1f8081d357ULL, 0x0249a4fd813fd7a6ULL, 0x69acca274e9caf61ULL, ++ 0x047ba3ea330721c9ULL, 0x83423fc20e7e1ea0ULL, 0x1df4c0af01314a60ULL, 0x09a62dab89289527ULL, ++ 0xa5b325a49cc6cb00ULL, 0xe94b5dc654b56cb6ULL, 0x3be28779adc994a0ULL, 0x4296e8f8ba3a4aadULL, ++ 0x328689761e451eabULL, 0x2e4d598bff59594aULL, 0x49b96853d7a7084aULL, 0x4980a319601420a8ULL, ++ 0x9565b9e12f552c42ULL, 0x8a5318db7100fe96ULL, 0x05c90b4d43add0d7ULL, 0x538b4cd66a5d4edaULL, ++ 0xf4e94fc3e89f039fULL, 0x592c9af26f618045ULL, 0x08a36eb5fd4b9550ULL, 0x25fffaf6c2ed1419ULL, ++ 0x34434459cc79d354ULL, 0xeeecbfb4b1d5476bULL, 0xddeb34a061615d99ULL, 0x5129cecceb64b773ULL, ++ 0xee43215894993520ULL, 0x772f9c7cf14c0b3bULL, 0xd2e2fce306bedad5ULL, 0x715f42b546f06a97ULL, ++ 0x434ecdceda5b5f1aULL, 0x0da17115a49741a9ULL, 0x680bd77c73edad2eULL, 0x487c02354edd9041ULL, ++ 0xb8efeff3a70ed9c4ULL, 0x56a32aa3e857e302ULL, 0xdf3a68bd48a2a5a0ULL, 0x07f650b73176c444ULL, ++ 0xe38b9b1626e0ccb1ULL, 0x79e053c18b09fb36ULL, 0x56d90319c9f94964ULL, 0x1ca941e7ac9ff5c4ULL, ++ 0x49c4df29162fa0bbULL, 0x8488cf3282b33305ULL, 0x95dfda14cabb437dULL, 0x3391f78264d5ad86ULL, ++ 0x729ae06ae2b5095dULL, 0xd58a58d73259a946ULL, 0xe9834262d13921edULL, 0x27fedafaa54bb592ULL, ++ 0xa99dc5b829ad48bbULL, 0x5f025742499ee260ULL, 0x802c8ecd5d7513fdULL, 0x78ceb3ef3f6dd938ULL, ++ 0xc342f44f8a135d94ULL, 0x7b9edb44828cdda3ULL, 0x9436d11a0537cfe7ULL, 0x5064b164ec1ab4c8ULL, ++ 0x7020eccfd37eb2fcULL, 0x1f31ea3ed90d25fcULL, 0x1b930d7bdfa1bb34ULL, 0x5344467a48113044ULL, ++ 0x70073170f25e6dfbULL, 0xe385dc1a50114cc8ULL, 0x2348698ac8fc4f00ULL, 0x2a77a55284dd40d8ULL, ++ 0xfe06afe0c98c6ce4ULL, 0xc235df96dddfd6e4ULL, 0x1428d01e33bf1ed3ULL, 0x785768ec9300bdafULL, ++ 0x9702e57a91deb63bULL, 0x61bdb8bfe5ce8b80ULL, 0x645b426f3d1d58acULL, 0x4804a82227a557bcULL, ++ 0x8e57048ab44d2601ULL, 0x68d6501a4b3a6935ULL, 0xc39c9ec3f9e1c293ULL, 0x4172f257d4de63e2ULL, ++ 0xd368b450330c6401ULL, 0x040d3017418f2391ULL, 0x2c34bb6090b7d90dULL, 0x16f649228fdfd51fULL, ++ 0xbea6818e2b928ef5ULL, 0xe28ccf91cdc11e72ULL, 0x594aaa68e77a36cdULL, 0x313034806c7ffd0fULL, ++ 0x8a9d27ac2249bd65ULL, 0x19a3b464018e9512ULL, 0xc26ccff352b37ec7ULL, 0x056f68341d797b21ULL, ++ 0x5e79d6757efd2327ULL, 0xfabdbcb6553afe15ULL, 0xd3e7222c6eaf5a60ULL, 0x7046c76d4dae743bULL, ++ 0x660be872b18d4a55ULL, 0x19992518574e1496ULL, 0xc103053a302bdcbbULL, 0x3ed8e9800b218e8eULL, ++ 0x7b0b9239fa75e03eULL, 0xefe9fb684633c083ULL, 0x98a35fbe391a7793ULL, 0x6065510fe2d0fe34ULL, ++ 0x55cb668548abad0cULL, 0xb4584548da87e527ULL, 0x2c43ecea0107c1ddULL, 0x526028809372de35ULL, ++ 0x3415c56af9213b1fULL, 0x5bee1a4d017e98dbULL, 0x13f6b105b5cf709bULL, 0x5ff20e3482b29ab6ULL, ++ 0x0aa29c75cc2e6c90ULL, 0xfc7d73ca3a70e206ULL, 0x899fc38fc4b5c515ULL, 0x250386b124ffc207ULL, ++ 0x54ea28d5ae3d2b56ULL, 0x9913149dd6de60ceULL, 0x16694fc58f06d6c1ULL, 0x46b23975eb018fc7ULL, ++ 0x470a6a0fb4b7b4e2ULL, 0x5d92475a8f7253deULL, 0xabeee5b52fbd3adbULL, 0x7fa20801a0806968ULL, ++ 0x76f3faf19f7714d2ULL, 0xb3e840c12f4660c3ULL, 0x0fb4cd8df212744eULL, 0x4b065a251d3a2dd2ULL, ++ 0x5cebde383d77cd4aULL, 0x6adf39df882c9cb1ULL, 0xa2dd242eb09af759ULL, 0x3147c0e50e5f6422ULL, ++ 0x164ca5101d1350dbULL, 0xf8d13479c33fc962ULL, 0xe640ce4d13e5da08ULL, 0x4bdee0c45061f8baULL, ++ 0xd7c46dc1a4edb1c9ULL, 0x5514d7b6437fd98aULL, 0x58942f6bb2a1c00bULL, 0x2dffb2ab1d70710eULL, ++ 0xccdfcf2fc18b6d68ULL, 0xa8ebcba8b7806167ULL, 0x980697f95e2937e3ULL, 0x02fbba1cd0126e8cULL ++}; + +-static void curve25519_bmi2_base(u8 session_key[CURVE25519_KEY_SIZE], +- const u8 private_key[CURVE25519_KEY_SIZE]) ++static void curve25519_ever64_base(u8 *out, const u8 *priv) + { +- struct { +- u64 buffer[4 * NUM_WORDS_ELTFP25519]; +- u64 coordinates[4 * NUM_WORDS_ELTFP25519]; +- u64 workspace[4 * NUM_WORDS_ELTFP25519]; +- u8 private[CURVE25519_KEY_SIZE]; +- } __aligned(32) m; +- +- const int ite[4] = { 64, 64, 64, 63 }; +- const int q = 3; + u64 swap = 1; +- +- int i = 0, j = 0, k = 0; +- u64 *const key = (u64 *)m.private; +- u64 *const Ur1 = m.coordinates + 0; +- u64 *const Zr1 = m.coordinates + 4; +- u64 *const Ur2 = m.coordinates + 8; +- u64 *const Zr2 = m.coordinates + 12; +- +- u64 *const UZr1 = m.coordinates + 0; +- u64 *const ZUr2 = m.coordinates + 8; +- +- u64 *const A = m.workspace + 0; +- u64 *const B = m.workspace + 4; +- u64 *const C = m.workspace + 8; +- u64 *const D = m.workspace + 12; +- +- u64 *const AB = m.workspace + 0; +- u64 *const CD = m.workspace + 8; +- +- const u64 *const P = table_ladder_8k; +- +- memcpy(m.private, private_key, sizeof(m.private)); +- +- curve25519_clamp_secret(m.private); +- +- setzero_eltfp25519_1w(Ur1); +- setzero_eltfp25519_1w(Zr1); +- setzero_eltfp25519_1w(Zr2); +- Ur1[0] = 1; +- Zr1[0] = 1; +- Zr2[0] = 1; +- +- /* G-S */ +- Ur2[3] = 0x1eaecdeee27cab34UL; +- Ur2[2] = 0xadc7a0b9235d48e2UL; +- Ur2[1] = 0xbbf095ae14b2edf8UL; +- Ur2[0] = 0x7e94e1fec82faabdUL; +- +- /* main-loop */ +- j = q; +- for (i = 0; i < NUM_WORDS_ELTFP25519; ++i) { +- while (j < ite[i]) { +- u64 bit = (key[i] >> j) & 0x1; +- k = (64 * i + j - q); ++ int i, j, k; ++ u64 tmp[16 + 32 + 4]; ++ u64 *x1 = &tmp[0]; ++ u64 *z1 = &tmp[4]; ++ u64 *x2 = &tmp[8]; ++ u64 *z2 = &tmp[12]; ++ u64 *xz1 = &tmp[0]; ++ u64 *xz2 = &tmp[8]; ++ u64 *a = &tmp[0 + 16]; ++ u64 *b = &tmp[4 + 16]; ++ u64 *c = &tmp[8 + 16]; ++ u64 *ab = &tmp[0 + 16]; ++ u64 *abcd = &tmp[0 + 16]; ++ u64 *ef = &tmp[16 + 16]; ++ u64 *efgh = &tmp[16 + 16]; ++ u64 *key = &tmp[0 + 16 + 32]; ++ ++ memcpy(key, priv, 32); ++ ((u8 *)key)[0] &= 248; ++ ((u8 *)key)[31] = (((u8 *)key)[31] & 127) | 64; ++ ++ x1[0] = 1, x1[1] = x1[2] = x1[3] = 0; ++ z1[0] = 1, z1[1] = z1[2] = z1[3] = 0; ++ z2[0] = 1, z2[1] = z2[2] = z2[3] = 0; ++ memcpy(x2, p_minus_s, sizeof(p_minus_s)); ++ ++ j = 3; ++ for (i = 0; i < 4; ++i) { ++ while (j < (const int[]){ 64, 64, 64, 63 }[i]) { ++ u64 bit = (key[i] >> j) & 1; ++ k = (64 * i + j - 3); + swap = swap ^ bit; +- cswap(swap, Ur1, Ur2); +- cswap(swap, Zr1, Zr2); ++ cswap2(swap, xz1, xz2); + swap = bit; +- /* Addition */ +- sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ +- add_eltfp25519_1w_bmi2(A, Ur1, Zr1); /* A = Ur1+Zr1 */ +- mul_eltfp25519_1w_bmi2(C, &P[4 * k], B);/* C = M0-B */ +- sub_eltfp25519_1w(B, A, C); /* B = (Ur1+Zr1) - M*(Ur1-Zr1) */ +- add_eltfp25519_1w_bmi2(A, A, C); /* A = (Ur1+Zr1) + M*(Ur1-Zr1) */ +- sqr_eltfp25519_2w_bmi2(AB); /* A = A^2 | B = B^2 */ +- mul_eltfp25519_2w_bmi2(UZr1, ZUr2, AB); /* Ur1 = Zr2*A | Zr1 = Ur2*B */ ++ fsub(b, x1, z1); ++ fadd(a, x1, z1); ++ fmul(c, &table_ladder[4 * k], b, ef); ++ fsub(b, a, c); ++ fadd(a, a, c); ++ fsqr2(ab, ab, efgh); ++ fmul2(xz1, xz2, ab, efgh); + ++j; + } + j = 0; + } + +- /* Doubling */ +- for (i = 0; i < q; ++i) { +- add_eltfp25519_1w_bmi2(A, Ur1, Zr1); /* A = Ur1+Zr1 */ +- sub_eltfp25519_1w(B, Ur1, Zr1); /* B = Ur1-Zr1 */ +- sqr_eltfp25519_2w_bmi2(AB); /* A = A**2 B = B**2 */ +- copy_eltfp25519_1w(C, B); /* C = B */ +- sub_eltfp25519_1w(B, A, B); /* B = A-B */ +- mul_a24_eltfp25519_1w(D, B); /* D = my_a24*B */ +- add_eltfp25519_1w_bmi2(D, D, C); /* D = D+C */ +- mul_eltfp25519_2w_bmi2(UZr1, AB, CD); /* Ur1 = A*B Zr1 = Zr1*A */ +- } +- +- /* Convert to affine coordinates */ +- inv_eltfp25519_1w_bmi2(A, Zr1); +- mul_eltfp25519_1w_bmi2((u64 *)session_key, Ur1, A); +- fred_eltfp25519_1w((u64 *)session_key); ++ point_double(xz1, abcd, efgh); ++ point_double(xz1, abcd, efgh); ++ point_double(xz1, abcd, efgh); ++ encode_point(out, xz1); + +- memzero_explicit(&m, sizeof(m)); ++ memzero_explicit(tmp, sizeof(tmp)); + } + ++static __ro_after_init DEFINE_STATIC_KEY_FALSE(curve25519_use_bmi2_adx); ++ + void curve25519_arch(u8 mypublic[CURVE25519_KEY_SIZE], + const u8 secret[CURVE25519_KEY_SIZE], + const u8 basepoint[CURVE25519_KEY_SIZE]) + { +- if (static_branch_likely(&curve25519_use_adx)) +- curve25519_adx(mypublic, secret, basepoint); +- else if (static_branch_likely(&curve25519_use_bmi2)) +- curve25519_bmi2(mypublic, secret, basepoint); ++ if (static_branch_likely(&curve25519_use_bmi2_adx)) ++ curve25519_ever64(mypublic, secret, basepoint); + else + curve25519_generic(mypublic, secret, basepoint); + } +@@ -2355,10 +1395,8 @@ EXPORT_SYMBOL(curve25519_arch); + void curve25519_base_arch(u8 pub[CURVE25519_KEY_SIZE], + const u8 secret[CURVE25519_KEY_SIZE]) + { +- if (static_branch_likely(&curve25519_use_adx)) +- curve25519_adx_base(pub, secret); +- else if (static_branch_likely(&curve25519_use_bmi2)) +- curve25519_bmi2_base(pub, secret); ++ if (static_branch_likely(&curve25519_use_bmi2_adx)) ++ curve25519_ever64_base(pub, secret); + else + curve25519_generic(pub, secret, curve25519_base_point); + } +@@ -2449,12 +1487,11 @@ static struct kpp_alg curve25519_alg = { + .max_size = curve25519_max_size, + }; + ++ + static int __init curve25519_mod_init(void) + { +- if (boot_cpu_has(X86_FEATURE_BMI2)) +- static_branch_enable(&curve25519_use_bmi2); +- else if (boot_cpu_has(X86_FEATURE_ADX)) +- static_branch_enable(&curve25519_use_adx); ++ if (boot_cpu_has(X86_FEATURE_BMI2) && boot_cpu_has(X86_FEATURE_ADX)) ++ static_branch_enable(&curve25519_use_bmi2_adx); + else + return 0; + return IS_REACHABLE(CONFIG_CRYPTO_KPP) ? +@@ -2474,3 +1511,4 @@ module_exit(curve25519_mod_exit); + MODULE_ALIAS_CRYPTO("curve25519"); + MODULE_ALIAS_CRYPTO("curve25519-x86"); + MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Jason A. Donenfeld "); diff --git a/ipq806x/backport-5.4/080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch b/ipq806x/backport-5.4/080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch new file mode 100644 index 0000000..d5b11e0 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0055-crypto-x86-curve25519-leave-r12-as-spare-register.patch @@ -0,0 +1,376 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 1 Mar 2020 16:06:56 +0800 +Subject: [PATCH] crypto: x86/curve25519 - leave r12 as spare register + +commit dc7fc3a53ae158263196b1892b672aedf67796c5 upstream. + +This updates to the newer register selection proved by HACL*, which +leads to a more compact instruction encoding, and saves around 100 +cycles. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/curve25519-x86_64.c | 110 ++++++++++++++-------------- + 1 file changed, 55 insertions(+), 55 deletions(-) + +--- a/arch/x86/crypto/curve25519-x86_64.c ++++ b/arch/x86/crypto/curve25519-x86_64.c +@@ -167,28 +167,28 @@ static inline void fmul(u64 *out, const + " movq 0(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 0(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 8(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" + /* Compute src1[1] * src2 */ + " movq 8(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" +- " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 16(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 16(%0);" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[2] * src2 */ + " movq 16(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" +- " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 24(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 24(%0);" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[3] * src2 */ + " movq 24(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" +- " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 32(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " movq %%r12, 40(%0);" " mov $0, %%r8;" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 32(%0);" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " movq %%rbx, 40(%0);" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 48(%0);" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" " movq %%rax, 56(%0);" + /* Line up pointers */ +@@ -202,11 +202,11 @@ static inline void fmul(u64 *out, const + " mulxq 32(%1), %%r8, %%r13;" + " xor %3, %3;" + " adoxq 0(%1), %%r8;" +- " mulxq 40(%1), %%r9, %%r12;" ++ " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" + " adoxq 8(%1), %%r9;" + " mulxq 48(%1), %%r10, %%r13;" +- " adcx %%r12, %%r10;" ++ " adcx %%rbx, %%r10;" + " adoxq 16(%1), %%r10;" + " mulxq 56(%1), %%r11, %%rax;" + " adcx %%r13, %%r11;" +@@ -231,7 +231,7 @@ static inline void fmul(u64 *out, const + " movq %%r8, 0(%0);" + : "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2) + : +- : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc" ++ : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "memory", "cc" + ); + } + +@@ -248,28 +248,28 @@ static inline void fmul2(u64 *out, const + " movq 0(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 0(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 8(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" + /* Compute src1[1] * src2 */ + " movq 8(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" +- " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 16(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 16(%0);" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[2] * src2 */ + " movq 16(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" +- " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 24(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 24(%0);" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[3] * src2 */ + " movq 24(%1), %%rdx;" + " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" +- " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 32(%0);" +- " mulxq 16(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " movq %%r12, 40(%0);" " mov $0, %%r8;" ++ " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 32(%0);" ++ " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " movq %%rbx, 40(%0);" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 48(%0);" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" " movq %%rax, 56(%0);" + +@@ -279,28 +279,28 @@ static inline void fmul2(u64 *out, const + " movq 32(%1), %%rdx;" + " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 64(%0);" + " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 72(%0);" +- " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" ++ " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" + /* Compute src1[1] * src2 */ + " movq 40(%1), %%rdx;" + " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 72(%0), %%r8;" " movq %%r8, 72(%0);" +- " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 80(%0);" +- " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 80(%0);" ++ " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[2] * src2 */ + " movq 48(%1), %%rdx;" + " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 80(%0), %%r8;" " movq %%r8, 80(%0);" +- " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 88(%0);" +- " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " mov $0, %%r8;" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 88(%0);" ++ " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[3] * src2 */ + " movq 56(%1), %%rdx;" + " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 88(%0), %%r8;" " movq %%r8, 88(%0);" +- " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%r12, %%r10;" " movq %%r10, 96(%0);" +- " mulxq 48(%3), %%r12, %%r13;" " adox %%r11, %%r12;" " adcx %%r14, %%r12;" " movq %%r12, 104(%0);" " mov $0, %%r8;" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 96(%0);" ++ " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " movq %%rbx, 104(%0);" " mov $0, %%r8;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 112(%0);" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" " movq %%rax, 120(%0);" + /* Line up pointers */ +@@ -314,11 +314,11 @@ static inline void fmul2(u64 *out, const + " mulxq 32(%1), %%r8, %%r13;" + " xor %3, %3;" + " adoxq 0(%1), %%r8;" +- " mulxq 40(%1), %%r9, %%r12;" ++ " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" + " adoxq 8(%1), %%r9;" + " mulxq 48(%1), %%r10, %%r13;" +- " adcx %%r12, %%r10;" ++ " adcx %%rbx, %%r10;" + " adoxq 16(%1), %%r10;" + " mulxq 56(%1), %%r11, %%rax;" + " adcx %%r13, %%r11;" +@@ -347,11 +347,11 @@ static inline void fmul2(u64 *out, const + " mulxq 96(%1), %%r8, %%r13;" + " xor %3, %3;" + " adoxq 64(%1), %%r8;" +- " mulxq 104(%1), %%r9, %%r12;" ++ " mulxq 104(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" + " adoxq 72(%1), %%r9;" + " mulxq 112(%1), %%r10, %%r13;" +- " adcx %%r12, %%r10;" ++ " adcx %%rbx, %%r10;" + " adoxq 80(%1), %%r10;" + " mulxq 120(%1), %%r11, %%rax;" + " adcx %%r13, %%r11;" +@@ -376,7 +376,7 @@ static inline void fmul2(u64 *out, const + " movq %%r8, 32(%0);" + : "+&r" (tmp), "+&r" (f1), "+&r" (out), "+&r" (f2) + : +- : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "memory", "cc" ++ : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "memory", "cc" + ); + } + +@@ -388,11 +388,11 @@ static inline void fmul_scalar(u64 *out, + asm volatile( + /* Compute the raw multiplication of f1*f2 */ + " mulxq 0(%2), %%r8, %%rcx;" /* f1[0]*f2 */ +- " mulxq 8(%2), %%r9, %%r12;" /* f1[1]*f2 */ ++ " mulxq 8(%2), %%r9, %%rbx;" /* f1[1]*f2 */ + " add %%rcx, %%r9;" + " mov $0, %%rcx;" + " mulxq 16(%2), %%r10, %%r13;" /* f1[2]*f2 */ +- " adcx %%r12, %%r10;" ++ " adcx %%rbx, %%r10;" + " mulxq 24(%2), %%r11, %%rax;" /* f1[3]*f2 */ + " adcx %%r13, %%r11;" + " adcx %%rcx, %%rax;" +@@ -419,7 +419,7 @@ static inline void fmul_scalar(u64 *out, + " movq %%r8, 0(%1);" + : "+&r" (f2_r) + : "r" (out), "r" (f1) +- : "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "memory", "cc" ++ : "%rax", "%rcx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "memory", "cc" + ); + } + +@@ -520,8 +520,8 @@ static inline void fsqr(u64 *out, const + " mulxq 16(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ + " mulxq 24(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ + " movq 24(%1), %%rdx;" /* f[3] */ +- " mulxq 8(%1), %%r11, %%r12;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ +- " mulxq 16(%1), %%rax, %%r13;" " adcx %%rax, %%r12;" /* f[2]*f[3] */ ++ " mulxq 8(%1), %%r11, %%rbx;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ ++ " mulxq 16(%1), %%rax, %%r13;" " adcx %%rax, %%rbx;" /* f[2]*f[3] */ + " movq 8(%1), %%rdx;" " adcx %%r15, %%r13;" /* f1 */ + " mulxq 16(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ + +@@ -531,12 +531,12 @@ static inline void fsqr(u64 *out, const + " adcx %%r8, %%r8;" + " adox %%rcx, %%r11;" + " adcx %%r9, %%r9;" +- " adox %%r15, %%r12;" ++ " adox %%r15, %%rbx;" + " adcx %%r10, %%r10;" + " adox %%r15, %%r13;" + " adcx %%r11, %%r11;" + " adox %%r15, %%r14;" +- " adcx %%r12, %%r12;" ++ " adcx %%rbx, %%rbx;" + " adcx %%r13, %%r13;" + " adcx %%r14, %%r14;" + +@@ -549,7 +549,7 @@ static inline void fsqr(u64 *out, const + " adcx %%rcx, %%r10;" " movq %%r10, 24(%0);" + " movq 16(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[2]^2 */ + " adcx %%rax, %%r11;" " movq %%r11, 32(%0);" +- " adcx %%rcx, %%r12;" " movq %%r12, 40(%0);" ++ " adcx %%rcx, %%rbx;" " movq %%rbx, 40(%0);" + " movq 24(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[3]^2 */ + " adcx %%rax, %%r13;" " movq %%r13, 48(%0);" + " adcx %%rcx, %%r14;" " movq %%r14, 56(%0);" +@@ -565,11 +565,11 @@ static inline void fsqr(u64 *out, const + " mulxq 32(%1), %%r8, %%r13;" + " xor %%rcx, %%rcx;" + " adoxq 0(%1), %%r8;" +- " mulxq 40(%1), %%r9, %%r12;" ++ " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" + " adoxq 8(%1), %%r9;" + " mulxq 48(%1), %%r10, %%r13;" +- " adcx %%r12, %%r10;" ++ " adcx %%rbx, %%r10;" + " adoxq 16(%1), %%r10;" + " mulxq 56(%1), %%r11, %%rax;" + " adcx %%r13, %%r11;" +@@ -594,7 +594,7 @@ static inline void fsqr(u64 *out, const + " movq %%r8, 0(%0);" + : "+&r" (tmp), "+&r" (f), "+&r" (out) + : +- : "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc" ++ : "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "%r15", "memory", "cc" + ); + } + +@@ -611,8 +611,8 @@ static inline void fsqr2(u64 *out, const + " mulxq 16(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ + " mulxq 24(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ + " movq 24(%1), %%rdx;" /* f[3] */ +- " mulxq 8(%1), %%r11, %%r12;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ +- " mulxq 16(%1), %%rax, %%r13;" " adcx %%rax, %%r12;" /* f[2]*f[3] */ ++ " mulxq 8(%1), %%r11, %%rbx;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ ++ " mulxq 16(%1), %%rax, %%r13;" " adcx %%rax, %%rbx;" /* f[2]*f[3] */ + " movq 8(%1), %%rdx;" " adcx %%r15, %%r13;" /* f1 */ + " mulxq 16(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ + +@@ -622,12 +622,12 @@ static inline void fsqr2(u64 *out, const + " adcx %%r8, %%r8;" + " adox %%rcx, %%r11;" + " adcx %%r9, %%r9;" +- " adox %%r15, %%r12;" ++ " adox %%r15, %%rbx;" + " adcx %%r10, %%r10;" + " adox %%r15, %%r13;" + " adcx %%r11, %%r11;" + " adox %%r15, %%r14;" +- " adcx %%r12, %%r12;" ++ " adcx %%rbx, %%rbx;" + " adcx %%r13, %%r13;" + " adcx %%r14, %%r14;" + +@@ -640,7 +640,7 @@ static inline void fsqr2(u64 *out, const + " adcx %%rcx, %%r10;" " movq %%r10, 24(%0);" + " movq 16(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[2]^2 */ + " adcx %%rax, %%r11;" " movq %%r11, 32(%0);" +- " adcx %%rcx, %%r12;" " movq %%r12, 40(%0);" ++ " adcx %%rcx, %%rbx;" " movq %%rbx, 40(%0);" + " movq 24(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[3]^2 */ + " adcx %%rax, %%r13;" " movq %%r13, 48(%0);" + " adcx %%rcx, %%r14;" " movq %%r14, 56(%0);" +@@ -651,8 +651,8 @@ static inline void fsqr2(u64 *out, const + " mulxq 48(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ + " mulxq 56(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ + " movq 56(%1), %%rdx;" /* f[3] */ +- " mulxq 40(%1), %%r11, %%r12;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ +- " mulxq 48(%1), %%rax, %%r13;" " adcx %%rax, %%r12;" /* f[2]*f[3] */ ++ " mulxq 40(%1), %%r11, %%rbx;" " adcx %%rcx, %%r11;" /* f[1]*f[3] */ ++ " mulxq 48(%1), %%rax, %%r13;" " adcx %%rax, %%rbx;" /* f[2]*f[3] */ + " movq 40(%1), %%rdx;" " adcx %%r15, %%r13;" /* f1 */ + " mulxq 48(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ + +@@ -662,12 +662,12 @@ static inline void fsqr2(u64 *out, const + " adcx %%r8, %%r8;" + " adox %%rcx, %%r11;" + " adcx %%r9, %%r9;" +- " adox %%r15, %%r12;" ++ " adox %%r15, %%rbx;" + " adcx %%r10, %%r10;" + " adox %%r15, %%r13;" + " adcx %%r11, %%r11;" + " adox %%r15, %%r14;" +- " adcx %%r12, %%r12;" ++ " adcx %%rbx, %%rbx;" + " adcx %%r13, %%r13;" + " adcx %%r14, %%r14;" + +@@ -680,7 +680,7 @@ static inline void fsqr2(u64 *out, const + " adcx %%rcx, %%r10;" " movq %%r10, 88(%0);" + " movq 48(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[2]^2 */ + " adcx %%rax, %%r11;" " movq %%r11, 96(%0);" +- " adcx %%rcx, %%r12;" " movq %%r12, 104(%0);" ++ " adcx %%rcx, %%rbx;" " movq %%rbx, 104(%0);" + " movq 56(%1), %%rdx;" " mulx %%rdx, %%rax, %%rcx;" /* f[3]^2 */ + " adcx %%rax, %%r13;" " movq %%r13, 112(%0);" + " adcx %%rcx, %%r14;" " movq %%r14, 120(%0);" +@@ -694,11 +694,11 @@ static inline void fsqr2(u64 *out, const + " mulxq 32(%1), %%r8, %%r13;" + " xor %%rcx, %%rcx;" + " adoxq 0(%1), %%r8;" +- " mulxq 40(%1), %%r9, %%r12;" ++ " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" + " adoxq 8(%1), %%r9;" + " mulxq 48(%1), %%r10, %%r13;" +- " adcx %%r12, %%r10;" ++ " adcx %%rbx, %%r10;" + " adoxq 16(%1), %%r10;" + " mulxq 56(%1), %%r11, %%rax;" + " adcx %%r13, %%r11;" +@@ -727,11 +727,11 @@ static inline void fsqr2(u64 *out, const + " mulxq 96(%1), %%r8, %%r13;" + " xor %%rcx, %%rcx;" + " adoxq 64(%1), %%r8;" +- " mulxq 104(%1), %%r9, %%r12;" ++ " mulxq 104(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" + " adoxq 72(%1), %%r9;" + " mulxq 112(%1), %%r10, %%r13;" +- " adcx %%r12, %%r10;" ++ " adcx %%rbx, %%r10;" + " adoxq 80(%1), %%r10;" + " mulxq 120(%1), %%r11, %%rax;" + " adcx %%r13, %%r11;" +@@ -756,7 +756,7 @@ static inline void fsqr2(u64 *out, const + " movq %%r8, 32(%0);" + : "+&r" (tmp), "+&r" (f), "+&r" (out) + : +- : "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "memory", "cc" ++ : "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%rbx", "%r13", "%r14", "%r15", "memory", "cc" + ); + } + diff --git a/ipq806x/backport-5.4/080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch b/ipq806x/backport-5.4/080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch new file mode 100644 index 0000000..6553716 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0056-crypto-arm-64-poly1305-add-artifact-to-.gitignore-fi.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 19 Mar 2020 11:56:17 -0600 +Subject: [PATCH] crypto: arm[64]/poly1305 - add artifact to .gitignore files + +commit 6e4e00d8b68ca7eb30d08afb740033e0d36abe55 upstream. + +The .S_shipped yields a .S, and the pattern in these directories is to +add that to .gitignore so that git-status doesn't raise a fuss. + +Fixes: a6b803b3ddc7 ("crypto: arm/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation") +Fixes: f569ca164751 ("crypto: arm64/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation") +Reported-by: Emil Renner Berthing +Cc: Ard Biesheuvel +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/.gitignore | 1 + + arch/arm64/crypto/.gitignore | 1 + + 2 files changed, 2 insertions(+) + +--- a/arch/arm/crypto/.gitignore ++++ b/arch/arm/crypto/.gitignore +@@ -1,3 +1,4 @@ + aesbs-core.S + sha256-core.S + sha512-core.S ++poly1305-core.S +--- a/arch/arm64/crypto/.gitignore ++++ b/arch/arm64/crypto/.gitignore +@@ -1,2 +1,3 @@ + sha256-core.S + sha512-core.S ++poly1305-core.S diff --git a/ipq806x/backport-5.4/080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch b/ipq806x/backport-5.4/080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch new file mode 100644 index 0000000..f8828f2 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0057-crypto-arch-lib-limit-simd-usage-to-4k-chunks.patch @@ -0,0 +1,243 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 23 Apr 2020 15:54:04 -0600 +Subject: [PATCH] crypto: arch/lib - limit simd usage to 4k chunks + +commit 706024a52c614b478b63f7728d202532ce6591a9 upstream. + +The initial Zinc patchset, after some mailing list discussion, contained +code to ensure that kernel_fpu_enable would not be kept on for more than +a 4k chunk, since it disables preemption. The choice of 4k isn't totally +scientific, but it's not a bad guess either, and it's what's used in +both the x86 poly1305, blake2s, and nhpoly1305 code already (in the form +of PAGE_SIZE, which this commit corrects to be explicitly 4k for the +former two). + +Ard did some back of the envelope calculations and found that +at 5 cycles/byte (overestimate) on a 1ghz processor (pretty slow), 4k +means we have a maximum preemption disabling of 20us, which Sebastian +confirmed was probably a good limit. + +Unfortunately the chunking appears to have been left out of the final +patchset that added the glue code. So, this commit adds it back in. + +Fixes: 84e03fa39fbe ("crypto: x86/chacha - expose SIMD ChaCha routine as library function") +Fixes: b3aad5bad26a ("crypto: arm64/chacha - expose arm64 ChaCha routine as library function") +Fixes: a44a3430d71b ("crypto: arm/chacha - expose ARM ChaCha routine as library function") +Fixes: d7d7b8535662 ("crypto: x86/poly1305 - wire up faster implementations for kernel") +Fixes: f569ca164751 ("crypto: arm64/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation") +Fixes: a6b803b3ddc7 ("crypto: arm/poly1305 - incorporate OpenSSL/CRYPTOGAMS NEON implementation") +Fixes: ed0356eda153 ("crypto: blake2s - x86_64 SIMD implementation") +Cc: Eric Biggers +Cc: Ard Biesheuvel +Cc: Sebastian Andrzej Siewior +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Reviewed-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/chacha-glue.c | 14 +++++++++++--- + arch/arm/crypto/poly1305-glue.c | 15 +++++++++++---- + arch/arm64/crypto/chacha-neon-glue.c | 14 +++++++++++--- + arch/arm64/crypto/poly1305-glue.c | 15 +++++++++++---- + arch/x86/crypto/blake2s-glue.c | 10 ++++------ + arch/x86/crypto/chacha_glue.c | 14 +++++++++++--- + arch/x86/crypto/poly1305_glue.c | 13 ++++++------- + 7 files changed, 65 insertions(+), 30 deletions(-) + +--- a/arch/arm/crypto/chacha-glue.c ++++ b/arch/arm/crypto/chacha-glue.c +@@ -91,9 +91,17 @@ void chacha_crypt_arch(u32 *state, u8 *d + return; + } + +- kernel_neon_begin(); +- chacha_doneon(state, dst, src, bytes, nrounds); +- kernel_neon_end(); ++ do { ++ unsigned int todo = min_t(unsigned int, bytes, SZ_4K); ++ ++ kernel_neon_begin(); ++ chacha_doneon(state, dst, src, todo, nrounds); ++ kernel_neon_end(); ++ ++ bytes -= todo; ++ src += todo; ++ dst += todo; ++ } while (bytes); + } + EXPORT_SYMBOL(chacha_crypt_arch); + +--- a/arch/arm/crypto/poly1305-glue.c ++++ b/arch/arm/crypto/poly1305-glue.c +@@ -160,13 +160,20 @@ void poly1305_update_arch(struct poly130 + unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE); + + if (static_branch_likely(&have_neon) && do_neon) { +- kernel_neon_begin(); +- poly1305_blocks_neon(&dctx->h, src, len, 1); +- kernel_neon_end(); ++ do { ++ unsigned int todo = min_t(unsigned int, len, SZ_4K); ++ ++ kernel_neon_begin(); ++ poly1305_blocks_neon(&dctx->h, src, todo, 1); ++ kernel_neon_end(); ++ ++ len -= todo; ++ src += todo; ++ } while (len); + } else { + poly1305_blocks_arm(&dctx->h, src, len, 1); ++ src += len; + } +- src += len; + nbytes %= POLY1305_BLOCK_SIZE; + } + +--- a/arch/arm64/crypto/chacha-neon-glue.c ++++ b/arch/arm64/crypto/chacha-neon-glue.c +@@ -87,9 +87,17 @@ void chacha_crypt_arch(u32 *state, u8 *d + !crypto_simd_usable()) + return chacha_crypt_generic(state, dst, src, bytes, nrounds); + +- kernel_neon_begin(); +- chacha_doneon(state, dst, src, bytes, nrounds); +- kernel_neon_end(); ++ do { ++ unsigned int todo = min_t(unsigned int, bytes, SZ_4K); ++ ++ kernel_neon_begin(); ++ chacha_doneon(state, dst, src, todo, nrounds); ++ kernel_neon_end(); ++ ++ bytes -= todo; ++ src += todo; ++ dst += todo; ++ } while (bytes); + } + EXPORT_SYMBOL(chacha_crypt_arch); + +--- a/arch/arm64/crypto/poly1305-glue.c ++++ b/arch/arm64/crypto/poly1305-glue.c +@@ -143,13 +143,20 @@ void poly1305_update_arch(struct poly130 + unsigned int len = round_down(nbytes, POLY1305_BLOCK_SIZE); + + if (static_branch_likely(&have_neon) && crypto_simd_usable()) { +- kernel_neon_begin(); +- poly1305_blocks_neon(&dctx->h, src, len, 1); +- kernel_neon_end(); ++ do { ++ unsigned int todo = min_t(unsigned int, len, SZ_4K); ++ ++ kernel_neon_begin(); ++ poly1305_blocks_neon(&dctx->h, src, todo, 1); ++ kernel_neon_end(); ++ ++ len -= todo; ++ src += todo; ++ } while (len); + } else { + poly1305_blocks(&dctx->h, src, len, 1); ++ src += len; + } +- src += len; + nbytes %= POLY1305_BLOCK_SIZE; + } + +--- a/arch/x86/crypto/blake2s-glue.c ++++ b/arch/x86/crypto/blake2s-glue.c +@@ -32,16 +32,16 @@ void blake2s_compress_arch(struct blake2 + const u32 inc) + { + /* SIMD disables preemption, so relax after processing each page. */ +- BUILD_BUG_ON(PAGE_SIZE / BLAKE2S_BLOCK_SIZE < 8); ++ BUILD_BUG_ON(SZ_4K / BLAKE2S_BLOCK_SIZE < 8); + + if (!static_branch_likely(&blake2s_use_ssse3) || !crypto_simd_usable()) { + blake2s_compress_generic(state, block, nblocks, inc); + return; + } + +- for (;;) { ++ do { + const size_t blocks = min_t(size_t, nblocks, +- PAGE_SIZE / BLAKE2S_BLOCK_SIZE); ++ SZ_4K / BLAKE2S_BLOCK_SIZE); + + kernel_fpu_begin(); + if (IS_ENABLED(CONFIG_AS_AVX512) && +@@ -52,10 +52,8 @@ void blake2s_compress_arch(struct blake2 + kernel_fpu_end(); + + nblocks -= blocks; +- if (!nblocks) +- break; + block += blocks * BLAKE2S_BLOCK_SIZE; +- } ++ } while (nblocks); + } + EXPORT_SYMBOL(blake2s_compress_arch); + +--- a/arch/x86/crypto/chacha_glue.c ++++ b/arch/x86/crypto/chacha_glue.c +@@ -154,9 +154,17 @@ void chacha_crypt_arch(u32 *state, u8 *d + bytes <= CHACHA_BLOCK_SIZE) + return chacha_crypt_generic(state, dst, src, bytes, nrounds); + +- kernel_fpu_begin(); +- chacha_dosimd(state, dst, src, bytes, nrounds); +- kernel_fpu_end(); ++ do { ++ unsigned int todo = min_t(unsigned int, bytes, SZ_4K); ++ ++ kernel_fpu_begin(); ++ chacha_dosimd(state, dst, src, todo, nrounds); ++ kernel_fpu_end(); ++ ++ bytes -= todo; ++ src += todo; ++ dst += todo; ++ } while (bytes); + } + EXPORT_SYMBOL(chacha_crypt_arch); + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -91,8 +91,8 @@ static void poly1305_simd_blocks(void *c + struct poly1305_arch_internal *state = ctx; + + /* SIMD disables preemption, so relax after processing each page. */ +- BUILD_BUG_ON(PAGE_SIZE < POLY1305_BLOCK_SIZE || +- PAGE_SIZE % POLY1305_BLOCK_SIZE); ++ BUILD_BUG_ON(SZ_4K < POLY1305_BLOCK_SIZE || ++ SZ_4K % POLY1305_BLOCK_SIZE); + + if (!IS_ENABLED(CONFIG_AS_AVX) || !static_branch_likely(&poly1305_use_avx) || + (len < (POLY1305_BLOCK_SIZE * 18) && !state->is_base2_26) || +@@ -102,8 +102,8 @@ static void poly1305_simd_blocks(void *c + return; + } + +- for (;;) { +- const size_t bytes = min_t(size_t, len, PAGE_SIZE); ++ do { ++ const size_t bytes = min_t(size_t, len, SZ_4K); + + kernel_fpu_begin(); + if (IS_ENABLED(CONFIG_AS_AVX512) && static_branch_likely(&poly1305_use_avx512)) +@@ -113,11 +113,10 @@ static void poly1305_simd_blocks(void *c + else + poly1305_blocks_avx(ctx, inp, bytes, padbit); + kernel_fpu_end(); ++ + len -= bytes; +- if (!len) +- break; + inp += bytes; +- } ++ } while (len); + } + + static void poly1305_simd_emit(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], diff --git a/ipq806x/backport-5.4/080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch b/ipq806x/backport-5.4/080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch new file mode 100644 index 0000000..736147f --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0058-crypto-lib-chacha20poly1305-Add-missing-function-dec.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 8 Jul 2020 12:41:13 +1000 +Subject: [PATCH] crypto: lib/chacha20poly1305 - Add missing function + declaration + +commit 06cc2afbbdf9a9e8df3e2f8db724997dd6e1b4ac upstream. + +This patch adds a declaration for chacha20poly1305_selftest to +silence a sparse warning. + +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + include/crypto/chacha20poly1305.h | 2 ++ + lib/crypto/chacha20poly1305.c | 2 -- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/include/crypto/chacha20poly1305.h ++++ b/include/crypto/chacha20poly1305.h +@@ -45,4 +45,6 @@ bool chacha20poly1305_decrypt_sg_inplace + const u64 nonce, + const u8 key[CHACHA20POLY1305_KEY_SIZE]); + ++bool chacha20poly1305_selftest(void); ++ + #endif /* __CHACHA20POLY1305_H */ +--- a/lib/crypto/chacha20poly1305.c ++++ b/lib/crypto/chacha20poly1305.c +@@ -21,8 +21,6 @@ + + #define CHACHA_KEY_WORDS (CHACHA_KEY_SIZE / sizeof(u32)) + +-bool __init chacha20poly1305_selftest(void); +- + static void chacha_load_key(u32 *k, const u8 *in) + { + k[0] = get_unaligned_le32(in); diff --git a/ipq806x/backport-5.4/080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch b/ipq806x/backport-5.4/080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch new file mode 100644 index 0000000..5284787 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0059-crypto-x86-chacha-sse3-use-unaligned-loads-for-state.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Wed, 8 Jul 2020 12:11:18 +0300 +Subject: [PATCH] crypto: x86/chacha-sse3 - use unaligned loads for state array + +commit e79a31715193686e92dadb4caedfbb1f5de3659c upstream. + +Due to the fact that the x86 port does not support allocating objects +on the stack with an alignment that exceeds 8 bytes, we have a rather +ugly hack in the x86 code for ChaCha to ensure that the state array is +aligned to 16 bytes, allowing the SSE3 implementation of the algorithm +to use aligned loads. + +Given that the performance benefit of using of aligned loads appears to +be limited (~0.25% for 1k blocks using tcrypt on a Corei7-8650U), and +the fact that this hack has leaked into generic ChaCha code, let's just +remove it. + +Cc: Martin Willi +Cc: Herbert Xu +Cc: Eric Biggers +Signed-off-by: Ard Biesheuvel +Reviewed-by: Martin Willi +Reviewed-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/chacha-ssse3-x86_64.S | 16 ++++++++-------- + arch/x86/crypto/chacha_glue.c | 17 ++--------------- + include/crypto/chacha.h | 4 ---- + 3 files changed, 10 insertions(+), 27 deletions(-) + +--- a/arch/x86/crypto/chacha-ssse3-x86_64.S ++++ b/arch/x86/crypto/chacha-ssse3-x86_64.S +@@ -120,10 +120,10 @@ ENTRY(chacha_block_xor_ssse3) + FRAME_BEGIN + + # x0..3 = s0..3 +- movdqa 0x00(%rdi),%xmm0 +- movdqa 0x10(%rdi),%xmm1 +- movdqa 0x20(%rdi),%xmm2 +- movdqa 0x30(%rdi),%xmm3 ++ movdqu 0x00(%rdi),%xmm0 ++ movdqu 0x10(%rdi),%xmm1 ++ movdqu 0x20(%rdi),%xmm2 ++ movdqu 0x30(%rdi),%xmm3 + movdqa %xmm0,%xmm8 + movdqa %xmm1,%xmm9 + movdqa %xmm2,%xmm10 +@@ -205,10 +205,10 @@ ENTRY(hchacha_block_ssse3) + # %edx: nrounds + FRAME_BEGIN + +- movdqa 0x00(%rdi),%xmm0 +- movdqa 0x10(%rdi),%xmm1 +- movdqa 0x20(%rdi),%xmm2 +- movdqa 0x30(%rdi),%xmm3 ++ movdqu 0x00(%rdi),%xmm0 ++ movdqu 0x10(%rdi),%xmm1 ++ movdqu 0x20(%rdi),%xmm2 ++ movdqu 0x30(%rdi),%xmm3 + + mov %edx,%r8d + call chacha_permute +--- a/arch/x86/crypto/chacha_glue.c ++++ b/arch/x86/crypto/chacha_glue.c +@@ -14,8 +14,6 @@ + #include + #include + +-#define CHACHA_STATE_ALIGN 16 +- + asmlinkage void chacha_block_xor_ssse3(u32 *state, u8 *dst, const u8 *src, + unsigned int len, int nrounds); + asmlinkage void chacha_4block_xor_ssse3(u32 *state, u8 *dst, const u8 *src, +@@ -125,8 +123,6 @@ static void chacha_dosimd(u32 *state, u8 + + void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds) + { +- state = PTR_ALIGN(state, CHACHA_STATE_ALIGN); +- + if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable()) { + hchacha_block_generic(state, stream, nrounds); + } else { +@@ -139,8 +135,6 @@ EXPORT_SYMBOL(hchacha_block_arch); + + void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv) + { +- state = PTR_ALIGN(state, CHACHA_STATE_ALIGN); +- + chacha_init_generic(state, key, iv); + } + EXPORT_SYMBOL(chacha_init_arch); +@@ -148,8 +142,6 @@ EXPORT_SYMBOL(chacha_init_arch); + void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes, + int nrounds) + { +- state = PTR_ALIGN(state, CHACHA_STATE_ALIGN); +- + if (!static_branch_likely(&chacha_use_simd) || !crypto_simd_usable() || + bytes <= CHACHA_BLOCK_SIZE) + return chacha_crypt_generic(state, dst, src, bytes, nrounds); +@@ -171,15 +163,12 @@ EXPORT_SYMBOL(chacha_crypt_arch); + static int chacha_simd_stream_xor(struct skcipher_request *req, + const struct chacha_ctx *ctx, const u8 *iv) + { +- u32 *state, state_buf[16 + 2] __aligned(8); ++ u32 state[CHACHA_STATE_WORDS] __aligned(8); + struct skcipher_walk walk; + int err; + + err = skcipher_walk_virt(&walk, req, false); + +- BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16); +- state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN); +- + chacha_init_generic(state, ctx->key, iv); + + while (walk.nbytes > 0) { +@@ -218,12 +207,10 @@ static int xchacha_simd(struct skcipher_ + { + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); +- u32 *state, state_buf[16 + 2] __aligned(8); ++ u32 state[CHACHA_STATE_WORDS] __aligned(8); + struct chacha_ctx subctx; + u8 real_iv[16]; + +- BUILD_BUG_ON(CHACHA_STATE_ALIGN != 16); +- state = PTR_ALIGN(state_buf + 0, CHACHA_STATE_ALIGN); + chacha_init_generic(state, ctx->key, req->iv); + + if (req->cryptlen > CHACHA_BLOCK_SIZE && crypto_simd_usable()) { +--- a/include/crypto/chacha.h ++++ b/include/crypto/chacha.h +@@ -25,11 +25,7 @@ + #define CHACHA_BLOCK_SIZE 64 + #define CHACHAPOLY_IV_SIZE 12 + +-#ifdef CONFIG_X86_64 +-#define CHACHA_STATE_WORDS ((CHACHA_BLOCK_SIZE + 12) / sizeof(u32)) +-#else + #define CHACHA_STATE_WORDS (CHACHA_BLOCK_SIZE / sizeof(u32)) +-#endif + + /* 192-bit nonce, then 64-bit stream position */ + #define XCHACHA_IV_SIZE 32 diff --git a/ipq806x/backport-5.4/080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch b/ipq806x/backport-5.4/080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch new file mode 100644 index 0000000..5a2d20a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0060-crypto-x86-curve25519-Remove-unused-carry-variables.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Thu, 23 Jul 2020 17:50:48 +1000 +Subject: [PATCH] crypto: x86/curve25519 - Remove unused carry variables + +commit 054a5540fb8f7268e2c79e9deab4242db15c8cba upstream. + +The carry variables are assigned but never used, which upsets +the compiler. This patch removes them. + +Signed-off-by: Herbert Xu +Reviewed-by: Karthikeyan Bhargavan +Acked-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/curve25519-x86_64.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/arch/x86/crypto/curve25519-x86_64.c ++++ b/arch/x86/crypto/curve25519-x86_64.c +@@ -948,10 +948,8 @@ static void store_felem(u64 *b, u64 *f) + { + u64 f30 = f[3U]; + u64 top_bit0 = f30 >> (u32)63U; +- u64 carry0; + u64 f31; + u64 top_bit; +- u64 carry; + u64 f0; + u64 f1; + u64 f2; +@@ -970,11 +968,11 @@ static void store_felem(u64 *b, u64 *f) + u64 o2; + u64 o3; + f[3U] = f30 & (u64)0x7fffffffffffffffU; +- carry0 = add_scalar(f, f, (u64)19U * top_bit0); ++ add_scalar(f, f, (u64)19U * top_bit0); + f31 = f[3U]; + top_bit = f31 >> (u32)63U; + f[3U] = f31 & (u64)0x7fffffffffffffffU; +- carry = add_scalar(f, f, (u64)19U * top_bit); ++ add_scalar(f, f, (u64)19U * top_bit); + f0 = f[0U]; + f1 = f[1U]; + f2 = f[2U]; diff --git a/ipq806x/backport-5.4/080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch b/ipq806x/backport-5.4/080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch new file mode 100644 index 0000000..b58fd08 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0061-crypto-arm-curve25519-include-linux-scatterlist.h.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fabio Estevam +Date: Mon, 24 Aug 2020 11:09:53 -0300 +Subject: [PATCH] crypto: arm/curve25519 - include + +commit 6779d0e6b0fe193ab3010ea201782ca6f75a3862 upstream. + +Building ARM allmodconfig leads to the following warnings: + +arch/arm/crypto/curve25519-glue.c:73:12: error: implicit declaration of function 'sg_copy_to_buffer' [-Werror=implicit-function-declaration] +arch/arm/crypto/curve25519-glue.c:74:9: error: implicit declaration of function 'sg_nents_for_len' [-Werror=implicit-function-declaration] +arch/arm/crypto/curve25519-glue.c:88:11: error: implicit declaration of function 'sg_copy_from_buffer' [-Werror=implicit-function-declaration] + +Include to fix such warnings + +Reported-by: Olof's autobuilder +Fixes: 0c3dc787a62a ("crypto: algapi - Remove skbuff.h inclusion") +Signed-off-by: Fabio Estevam +Acked-by: Ard Biesheuvel +Acked-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/curve25519-glue.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/crypto/curve25519-glue.c ++++ b/arch/arm/crypto/curve25519-glue.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + asmlinkage void curve25519_neon(u8 mypublic[CURVE25519_KEY_SIZE], diff --git a/ipq806x/backport-5.4/080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch b/ipq806x/backport-5.4/080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch new file mode 100644 index 0000000..cf3724a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0062-crypto-arm-poly1305-Add-prototype-for-poly1305_block.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Tue, 25 Aug 2020 11:23:00 +1000 +Subject: [PATCH] crypto: arm/poly1305 - Add prototype for poly1305_blocks_neon + +commit 51982ea02aef972132eb35c583d3e4c5b83166e5 upstream. + +This patch adds a prototype for poly1305_blocks_neon to slience +a compiler warning: + + CC [M] arch/arm/crypto/poly1305-glue.o +../arch/arm/crypto/poly1305-glue.c:25:13: warning: no previous prototype for `poly1305_blocks_neon' [-Wmissing-prototypes] + void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit) + ^~~~~~~~~~~~~~~~~~~~ + +Signed-off-by: Herbert Xu +Acked-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/poly1305-glue.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/crypto/poly1305-glue.c ++++ b/arch/arm/crypto/poly1305-glue.c +@@ -20,6 +20,7 @@ + + void poly1305_init_arm(void *state, const u8 *key); + void poly1305_blocks_arm(void *state, const u8 *src, u32 len, u32 hibit); ++void poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit); + void poly1305_emit_arm(void *state, u8 *digest, const u32 *nonce); + + void __weak poly1305_blocks_neon(void *state, const u8 *src, u32 len, u32 hibit) diff --git a/ipq806x/backport-5.4/080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch b/ipq806x/backport-5.4/080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch new file mode 100644 index 0000000..dd76e2a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0063-crypto-curve25519-x86_64-Use-XORL-r32-32.patch @@ -0,0 +1,261 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Uros Bizjak +Date: Thu, 27 Aug 2020 19:30:58 +0200 +Subject: [PATCH] crypto: curve25519-x86_64 - Use XORL r32,32 + +commit db719539fd3889836900bf912755aa30a5985e9a upstream. + +x86_64 zero extends 32bit operations, so for 64bit operands, +XORL r32,r32 is functionally equal to XORL r64,r64, but avoids +a REX prefix byte when legacy registers are used. + +Signed-off-by: Uros Bizjak +Cc: Herbert Xu +Cc: "David S. Miller" +Acked-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/curve25519-x86_64.c | 68 ++++++++++++++--------------- + 1 file changed, 34 insertions(+), 34 deletions(-) + +--- a/arch/x86/crypto/curve25519-x86_64.c ++++ b/arch/x86/crypto/curve25519-x86_64.c +@@ -45,11 +45,11 @@ static inline u64 add_scalar(u64 *out, c + + asm volatile( + /* Clear registers to propagate the carry bit */ +- " xor %%r8, %%r8;" +- " xor %%r9, %%r9;" +- " xor %%r10, %%r10;" +- " xor %%r11, %%r11;" +- " xor %1, %1;" ++ " xor %%r8d, %%r8d;" ++ " xor %%r9d, %%r9d;" ++ " xor %%r10d, %%r10d;" ++ " xor %%r11d, %%r11d;" ++ " xor %k1, %k1;" + + /* Begin addition chain */ + " addq 0(%3), %0;" +@@ -93,7 +93,7 @@ static inline void fadd(u64 *out, const + " cmovc %0, %%rax;" + + /* Step 2: Add carry*38 to the original sum */ +- " xor %%rcx, %%rcx;" ++ " xor %%ecx, %%ecx;" + " add %%rax, %%r8;" + " adcx %%rcx, %%r9;" + " movq %%r9, 8(%1);" +@@ -165,28 +165,28 @@ static inline void fmul(u64 *out, const + + /* Compute src1[0] * src2 */ + " movq 0(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 0(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " movq %%r8, 0(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 8(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" + /* Compute src1[1] * src2 */ + " movq 8(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 16(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[2] * src2 */ + " movq 16(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 24(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[3] * src2 */ + " movq 24(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 32(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " movq %%rbx, 40(%0);" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 48(%0);" " mov $0, %%rax;" +@@ -200,7 +200,7 @@ static inline void fmul(u64 *out, const + /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ + " mov $38, %%rdx;" + " mulxq 32(%1), %%r8, %%r13;" +- " xor %3, %3;" ++ " xor %k3, %k3;" + " adoxq 0(%1), %%r8;" + " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" +@@ -246,28 +246,28 @@ static inline void fmul2(u64 *out, const + + /* Compute src1[0] * src2 */ + " movq 0(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 0(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " movq %%r8, 0(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 8(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" + /* Compute src1[1] * src2 */ + " movq 8(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 8(%0), %%r8;" " movq %%r8, 8(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 16(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[2] * src2 */ + " movq 16(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 16(%0), %%r8;" " movq %%r8, 16(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 24(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[3] * src2 */ + " movq 24(%1), %%rdx;" +- " mulxq 0(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" ++ " mulxq 0(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 24(%0), %%r8;" " movq %%r8, 24(%0);" + " mulxq 8(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 32(%0);" + " mulxq 16(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " movq %%rbx, 40(%0);" " mov $0, %%r8;" + " mulxq 24(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 48(%0);" " mov $0, %%rax;" +@@ -277,29 +277,29 @@ static inline void fmul2(u64 *out, const + + /* Compute src1[0] * src2 */ + " movq 32(%1), %%rdx;" +- " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " movq %%r8, 64(%0);" +- " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 72(%0);" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " movq %%r8, 64(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " movq %%r10, 72(%0);" + " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" + /* Compute src1[1] * src2 */ + " movq 40(%1), %%rdx;" +- " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 72(%0), %%r8;" " movq %%r8, 72(%0);" +- " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 80(%0);" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 72(%0), %%r8;" " movq %%r8, 72(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 80(%0);" + " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[2] * src2 */ + " movq 48(%1), %%rdx;" +- " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 80(%0), %%r8;" " movq %%r8, 80(%0);" +- " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 88(%0);" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 80(%0), %%r8;" " movq %%r8, 80(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 88(%0);" + " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " mov $0, %%r8;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" + /* Compute src1[3] * src2 */ + " movq 56(%1), %%rdx;" +- " mulxq 32(%3), %%r8, %%r9;" " xor %%r10, %%r10;" " adcxq 88(%0), %%r8;" " movq %%r8, 88(%0);" +- " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 96(%0);" ++ " mulxq 32(%3), %%r8, %%r9;" " xor %%r10d, %%r10d;" " adcxq 88(%0), %%r8;" " movq %%r8, 88(%0);" ++ " mulxq 40(%3), %%r10, %%r11;" " adox %%r9, %%r10;" " adcx %%rbx, %%r10;" " movq %%r10, 96(%0);" + " mulxq 48(%3), %%rbx, %%r13;" " adox %%r11, %%rbx;" " adcx %%r14, %%rbx;" " movq %%rbx, 104(%0);" " mov $0, %%r8;" + " mulxq 56(%3), %%r14, %%rdx;" " adox %%r13, %%r14;" " adcx %%rax, %%r14;" " movq %%r14, 112(%0);" " mov $0, %%rax;" + " adox %%rdx, %%rax;" " adcx %%r8, %%rax;" " movq %%rax, 120(%0);" +@@ -312,7 +312,7 @@ static inline void fmul2(u64 *out, const + /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ + " mov $38, %%rdx;" + " mulxq 32(%1), %%r8, %%r13;" +- " xor %3, %3;" ++ " xor %k3, %k3;" + " adoxq 0(%1), %%r8;" + " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" +@@ -345,7 +345,7 @@ static inline void fmul2(u64 *out, const + /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ + " mov $38, %%rdx;" + " mulxq 96(%1), %%r8, %%r13;" +- " xor %3, %3;" ++ " xor %k3, %k3;" + " adoxq 64(%1), %%r8;" + " mulxq 104(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" +@@ -516,7 +516,7 @@ static inline void fsqr(u64 *out, const + + /* Step 1: Compute all partial products */ + " movq 0(%1), %%rdx;" /* f[0] */ +- " mulxq 8(%1), %%r8, %%r14;" " xor %%r15, %%r15;" /* f[1]*f[0] */ ++ " mulxq 8(%1), %%r8, %%r14;" " xor %%r15d, %%r15d;" /* f[1]*f[0] */ + " mulxq 16(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ + " mulxq 24(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ + " movq 24(%1), %%rdx;" /* f[3] */ +@@ -526,7 +526,7 @@ static inline void fsqr(u64 *out, const + " mulxq 16(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ + + /* Step 2: Compute two parallel carry chains */ +- " xor %%r15, %%r15;" ++ " xor %%r15d, %%r15d;" + " adox %%rax, %%r10;" + " adcx %%r8, %%r8;" + " adox %%rcx, %%r11;" +@@ -563,7 +563,7 @@ static inline void fsqr(u64 *out, const + /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ + " mov $38, %%rdx;" + " mulxq 32(%1), %%r8, %%r13;" +- " xor %%rcx, %%rcx;" ++ " xor %%ecx, %%ecx;" + " adoxq 0(%1), %%r8;" + " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" +@@ -607,7 +607,7 @@ static inline void fsqr2(u64 *out, const + asm volatile( + /* Step 1: Compute all partial products */ + " movq 0(%1), %%rdx;" /* f[0] */ +- " mulxq 8(%1), %%r8, %%r14;" " xor %%r15, %%r15;" /* f[1]*f[0] */ ++ " mulxq 8(%1), %%r8, %%r14;" " xor %%r15d, %%r15d;" /* f[1]*f[0] */ + " mulxq 16(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ + " mulxq 24(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ + " movq 24(%1), %%rdx;" /* f[3] */ +@@ -617,7 +617,7 @@ static inline void fsqr2(u64 *out, const + " mulxq 16(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ + + /* Step 2: Compute two parallel carry chains */ +- " xor %%r15, %%r15;" ++ " xor %%r15d, %%r15d;" + " adox %%rax, %%r10;" + " adcx %%r8, %%r8;" + " adox %%rcx, %%r11;" +@@ -647,7 +647,7 @@ static inline void fsqr2(u64 *out, const + + /* Step 1: Compute all partial products */ + " movq 32(%1), %%rdx;" /* f[0] */ +- " mulxq 40(%1), %%r8, %%r14;" " xor %%r15, %%r15;" /* f[1]*f[0] */ ++ " mulxq 40(%1), %%r8, %%r14;" " xor %%r15d, %%r15d;" /* f[1]*f[0] */ + " mulxq 48(%1), %%r9, %%r10;" " adcx %%r14, %%r9;" /* f[2]*f[0] */ + " mulxq 56(%1), %%rax, %%rcx;" " adcx %%rax, %%r10;" /* f[3]*f[0] */ + " movq 56(%1), %%rdx;" /* f[3] */ +@@ -657,7 +657,7 @@ static inline void fsqr2(u64 *out, const + " mulxq 48(%1), %%rax, %%rcx;" " mov $0, %%r14;" /* f[2]*f[1] */ + + /* Step 2: Compute two parallel carry chains */ +- " xor %%r15, %%r15;" ++ " xor %%r15d, %%r15d;" + " adox %%rax, %%r10;" + " adcx %%r8, %%r8;" + " adox %%rcx, %%r11;" +@@ -692,7 +692,7 @@ static inline void fsqr2(u64 *out, const + /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ + " mov $38, %%rdx;" + " mulxq 32(%1), %%r8, %%r13;" +- " xor %%rcx, %%rcx;" ++ " xor %%ecx, %%ecx;" + " adoxq 0(%1), %%r8;" + " mulxq 40(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" +@@ -725,7 +725,7 @@ static inline void fsqr2(u64 *out, const + /* Step 1: Compute dst + carry == tmp_hi * 38 + tmp_lo */ + " mov $38, %%rdx;" + " mulxq 96(%1), %%r8, %%r13;" +- " xor %%rcx, %%rcx;" ++ " xor %%ecx, %%ecx;" + " adoxq 64(%1), %%r8;" + " mulxq 104(%1), %%r9, %%rbx;" + " adcx %%r13, %%r9;" diff --git a/ipq806x/backport-5.4/080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch b/ipq806x/backport-5.4/080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch new file mode 100644 index 0000000..4fcaa1e --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0064-crypto-poly1305-x86_64-Use-XORL-r32-32.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Uros Bizjak +Date: Thu, 27 Aug 2020 19:38:31 +0200 +Subject: [PATCH] crypto: poly1305-x86_64 - Use XORL r32,32 + +commit 7dfd1e01b3dfc13431b1b25720cf2692a7e111ef upstream. + +x86_64 zero extends 32bit operations, so for 64bit operands, +XORL r32,r32 is functionally equal to XORQ r64,r64, but avoids +a REX prefix byte when legacy registers are used. + +Signed-off-by: Uros Bizjak +Cc: Herbert Xu +Cc: "David S. Miller" +Acked-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305-x86_64-cryptogams.pl | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/x86/crypto/poly1305-x86_64-cryptogams.pl ++++ b/arch/x86/crypto/poly1305-x86_64-cryptogams.pl +@@ -246,7 +246,7 @@ $code.=<<___ if (!$kernel); + ___ + &declare_function("poly1305_init_x86_64", 32, 3); + $code.=<<___; +- xor %rax,%rax ++ xor %eax,%eax + mov %rax,0($ctx) # initialize hash value + mov %rax,8($ctx) + mov %rax,16($ctx) +@@ -2869,7 +2869,7 @@ $code.=<<___; + .type poly1305_init_base2_44,\@function,3 + .align 32 + poly1305_init_base2_44: +- xor %rax,%rax ++ xor %eax,%eax + mov %rax,0($ctx) # initialize hash value + mov %rax,8($ctx) + mov %rax,16($ctx) +@@ -3963,7 +3963,7 @@ xor128_decrypt_n_pad: + mov \$16,$len + sub %r10,$len + xor %eax,%eax +- xor %r11,%r11 ++ xor %r11d,%r11d + .Loop_dec_byte: + mov ($inp,$otp),%r11b + mov ($otp),%al +@@ -4101,7 +4101,7 @@ avx_handler: + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi +- xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER ++ xor %ecx,%ecx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry diff --git a/ipq806x/backport-5.4/080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch b/ipq806x/backport-5.4/080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch new file mode 100644 index 0000000..ee64bfe --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0065-crypto-x86-poly1305-Remove-assignments-with-no-effec.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Thu, 24 Sep 2020 13:29:04 +1000 +Subject: [PATCH] crypto: x86/poly1305 - Remove assignments with no effect + +commit 4a0c1de64bf9d9027a6f19adfba89fc27893db23 upstream. + +This patch removes a few ineffectual assignments from the function +crypto_poly1305_setdctxkey. + +Reported-by: kernel test robot +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305_glue.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -157,9 +157,6 @@ static unsigned int crypto_poly1305_setd + dctx->s[1] = get_unaligned_le32(&inp[4]); + dctx->s[2] = get_unaligned_le32(&inp[8]); + dctx->s[3] = get_unaligned_le32(&inp[12]); +- inp += POLY1305_BLOCK_SIZE; +- len -= POLY1305_BLOCK_SIZE; +- acc += POLY1305_BLOCK_SIZE; + dctx->sset = true; + } + } diff --git a/ipq806x/backport-5.4/080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch b/ipq806x/backport-5.4/080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch new file mode 100644 index 0000000..dce8bb9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0066-crypto-x86-poly1305-add-back-a-needed-assignment.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Fri, 23 Oct 2020 15:27:48 -0700 +Subject: [PATCH] crypto: x86/poly1305 - add back a needed assignment + +commit c3a98c3ad5c0dc60a1ac66bf91147a3f39cac96b upstream. + +One of the assignments that was removed by commit 4a0c1de64bf9 ("crypto: +x86/poly1305 - Remove assignments with no effect") is actually needed, +since it affects the return value. + +This fixes the following crypto self-test failure: + + alg: shash: poly1305-simd test failed (wrong result) on test vector 2, cfg="init+update+final aligned buffer" + +Fixes: 4a0c1de64bf9 ("crypto: x86/poly1305 - Remove assignments with no effect") +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/x86/crypto/poly1305_glue.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -157,6 +157,7 @@ static unsigned int crypto_poly1305_setd + dctx->s[1] = get_unaligned_le32(&inp[4]); + dctx->s[2] = get_unaligned_le32(&inp[8]); + dctx->s[3] = get_unaligned_le32(&inp[12]); ++ acc += POLY1305_BLOCK_SIZE; + dctx->sset = true; + } + } diff --git a/ipq806x/backport-5.4/080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch b/ipq806x/backport-5.4/080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch new file mode 100644 index 0000000..31c47df --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0067-crypto-Kconfig-CRYPTO_MANAGER_EXTRA_TESTS-requires-t.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 2 Nov 2020 14:48:15 +0100 +Subject: [PATCH] crypto: Kconfig - CRYPTO_MANAGER_EXTRA_TESTS requires the + manager + +commit 6569e3097f1c4a490bdf2b23d326855e04942dfd upstream. + +The extra tests in the manager actually require the manager to be +selected too. Otherwise the linker gives errors like: + +ld: arch/x86/crypto/chacha_glue.o: in function `chacha_simd_stream_xor': +chacha_glue.c:(.text+0x422): undefined reference to `crypto_simd_disabled_for_test' + +Fixes: 2343d1529aff ("crypto: Kconfig - allow tests to be disabled when manager is disabled") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + crypto/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -145,7 +145,7 @@ config CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_MANAGER_EXTRA_TESTS + bool "Enable extra run-time crypto self tests" +- depends on DEBUG_KERNEL && !CRYPTO_MANAGER_DISABLE_TESTS ++ depends on DEBUG_KERNEL && !CRYPTO_MANAGER_DISABLE_TESTS && CRYPTO_MANAGER + help + Enable extra run-time self tests of registered crypto algorithms, + including randomized fuzz tests. diff --git a/ipq806x/backport-5.4/080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch b/ipq806x/backport-5.4/080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch new file mode 100644 index 0000000..b31b8d9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0068-crypto-arm-chacha-neon-optimize-for-non-block-size-m.patch @@ -0,0 +1,272 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Tue, 3 Nov 2020 17:28:09 +0100 +Subject: [PATCH] crypto: arm/chacha-neon - optimize for non-block size + multiples + +commit 86cd97ec4b943af35562a74688bc4e909b32c3d1 upstream. + +The current NEON based ChaCha implementation for ARM is optimized for +multiples of 4x the ChaCha block size (64 bytes). This makes sense for +block encryption, but given that ChaCha is also often used in the +context of networking, it makes sense to consider arbitrary length +inputs as well. + +For example, WireGuard typically uses 1420 byte packets, and performing +ChaCha encryption involves 5 invocations of chacha_4block_xor_neon() +and 3 invocations of chacha_block_xor_neon(), where the last one also +involves a memcpy() using a buffer on the stack to process the final +chunk of 1420 % 64 == 12 bytes. + +Let's optimize for this case as well, by letting chacha_4block_xor_neon() +deal with any input size between 64 and 256 bytes, using NEON permutation +instructions and overlapping loads and stores. This way, the 140 byte +tail of a 1420 byte input buffer can simply be processed in one go. + +This results in the following performance improvements for 1420 byte +blocks, without significant impact on power-of-2 input sizes. (Note +that Raspberry Pi is widely used in combination with a 32-bit kernel, +even though the core is 64-bit capable) + + Cortex-A8 (BeagleBone) : 7% + Cortex-A15 (Calxeda Midway) : 21% + Cortex-A53 (Raspberry Pi 3) : 3% + Cortex-A72 (Raspberry Pi 4) : 19% + +Cc: Eric Biggers +Cc: "Jason A . Donenfeld" +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/chacha-glue.c | 34 +++++------ + arch/arm/crypto/chacha-neon-core.S | 97 +++++++++++++++++++++++++++--- + 2 files changed, 107 insertions(+), 24 deletions(-) + +--- a/arch/arm/crypto/chacha-glue.c ++++ b/arch/arm/crypto/chacha-glue.c +@@ -23,7 +23,7 @@ + asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src, + int nrounds); + asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src, +- int nrounds); ++ int nrounds, unsigned int nbytes); + asmlinkage void hchacha_block_arm(const u32 *state, u32 *out, int nrounds); + asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds); + +@@ -42,24 +42,24 @@ static void chacha_doneon(u32 *state, u8 + { + u8 buf[CHACHA_BLOCK_SIZE]; + +- while (bytes >= CHACHA_BLOCK_SIZE * 4) { +- chacha_4block_xor_neon(state, dst, src, nrounds); +- bytes -= CHACHA_BLOCK_SIZE * 4; +- src += CHACHA_BLOCK_SIZE * 4; +- dst += CHACHA_BLOCK_SIZE * 4; +- state[12] += 4; +- } +- while (bytes >= CHACHA_BLOCK_SIZE) { +- chacha_block_xor_neon(state, dst, src, nrounds); +- bytes -= CHACHA_BLOCK_SIZE; +- src += CHACHA_BLOCK_SIZE; +- dst += CHACHA_BLOCK_SIZE; +- state[12]++; ++ while (bytes > CHACHA_BLOCK_SIZE) { ++ unsigned int l = min(bytes, CHACHA_BLOCK_SIZE * 4U); ++ ++ chacha_4block_xor_neon(state, dst, src, nrounds, l); ++ bytes -= l; ++ src += l; ++ dst += l; ++ state[12] += DIV_ROUND_UP(l, CHACHA_BLOCK_SIZE); + } + if (bytes) { +- memcpy(buf, src, bytes); +- chacha_block_xor_neon(state, buf, buf, nrounds); +- memcpy(dst, buf, bytes); ++ const u8 *s = src; ++ u8 *d = dst; ++ ++ if (bytes != CHACHA_BLOCK_SIZE) ++ s = d = memcpy(buf, src, bytes); ++ chacha_block_xor_neon(state, d, s, nrounds); ++ if (d != dst) ++ memcpy(dst, buf, bytes); + } + } + +--- a/arch/arm/crypto/chacha-neon-core.S ++++ b/arch/arm/crypto/chacha-neon-core.S +@@ -47,6 +47,7 @@ + */ + + #include ++#include + + .text + .fpu neon +@@ -205,7 +206,7 @@ ENDPROC(hchacha_block_neon) + + .align 5 + ENTRY(chacha_4block_xor_neon) +- push {r4-r5} ++ push {r4, lr} + mov r4, sp // preserve the stack pointer + sub ip, sp, #0x20 // allocate a 32 byte buffer + bic ip, ip, #0x1f // aligned to 32 bytes +@@ -229,10 +230,10 @@ ENTRY(chacha_4block_xor_neon) + vld1.32 {q0-q1}, [r0] + vld1.32 {q2-q3}, [ip] + +- adr r5, .Lctrinc ++ adr lr, .Lctrinc + vdup.32 q15, d7[1] + vdup.32 q14, d7[0] +- vld1.32 {q4}, [r5, :128] ++ vld1.32 {q4}, [lr, :128] + vdup.32 q13, d6[1] + vdup.32 q12, d6[0] + vdup.32 q11, d5[1] +@@ -455,7 +456,7 @@ ENTRY(chacha_4block_xor_neon) + + // Re-interleave the words in the first two rows of each block (x0..7). + // Also add the counter values 0-3 to x12[0-3]. +- vld1.32 {q8}, [r5, :128] // load counter values 0-3 ++ vld1.32 {q8}, [lr, :128] // load counter values 0-3 + vzip.32 q0, q1 // => (0 1 0 1) (0 1 0 1) + vzip.32 q2, q3 // => (2 3 2 3) (2 3 2 3) + vzip.32 q4, q5 // => (4 5 4 5) (4 5 4 5) +@@ -493,6 +494,8 @@ ENTRY(chacha_4block_xor_neon) + + // Re-interleave the words in the last two rows of each block (x8..15). + vld1.32 {q8-q9}, [sp, :256] ++ mov sp, r4 // restore original stack pointer ++ ldr r4, [r4, #8] // load number of bytes + vzip.32 q12, q13 // => (12 13 12 13) (12 13 12 13) + vzip.32 q14, q15 // => (14 15 14 15) (14 15 14 15) + vzip.32 q8, q9 // => (8 9 8 9) (8 9 8 9) +@@ -520,41 +523,121 @@ ENTRY(chacha_4block_xor_neon) + // XOR the rest of the data with the keystream + + vld1.8 {q0-q1}, [r2]! ++ subs r4, r4, #96 + veor q0, q0, q8 + veor q1, q1, q12 ++ ble .Lle96 + vst1.8 {q0-q1}, [r1]! + + vld1.8 {q0-q1}, [r2]! ++ subs r4, r4, #32 + veor q0, q0, q2 + veor q1, q1, q6 ++ ble .Lle128 + vst1.8 {q0-q1}, [r1]! + + vld1.8 {q0-q1}, [r2]! ++ subs r4, r4, #32 + veor q0, q0, q10 + veor q1, q1, q14 ++ ble .Lle160 + vst1.8 {q0-q1}, [r1]! + + vld1.8 {q0-q1}, [r2]! ++ subs r4, r4, #32 + veor q0, q0, q4 + veor q1, q1, q5 ++ ble .Lle192 + vst1.8 {q0-q1}, [r1]! + + vld1.8 {q0-q1}, [r2]! ++ subs r4, r4, #32 + veor q0, q0, q9 + veor q1, q1, q13 ++ ble .Lle224 + vst1.8 {q0-q1}, [r1]! + + vld1.8 {q0-q1}, [r2]! ++ subs r4, r4, #32 + veor q0, q0, q3 + veor q1, q1, q7 ++ blt .Llt256 ++.Lout: + vst1.8 {q0-q1}, [r1]! + + vld1.8 {q0-q1}, [r2] +- mov sp, r4 // restore original stack pointer + veor q0, q0, q11 + veor q1, q1, q15 + vst1.8 {q0-q1}, [r1] + +- pop {r4-r5} +- bx lr ++ pop {r4, pc} ++ ++.Lle192: ++ vmov q4, q9 ++ vmov q5, q13 ++ ++.Lle160: ++ // nothing to do ++ ++.Lfinalblock: ++ // Process the final block if processing less than 4 full blocks. ++ // Entered with 32 bytes of ChaCha cipher stream in q4-q5, and the ++ // previous 32 byte output block that still needs to be written at ++ // [r1] in q0-q1. ++ beq .Lfullblock ++ ++.Lpartialblock: ++ adr lr, .Lpermute + 32 ++ add r2, r2, r4 ++ add lr, lr, r4 ++ add r4, r4, r1 ++ ++ vld1.8 {q2-q3}, [lr] ++ vld1.8 {q6-q7}, [r2] ++ ++ add r4, r4, #32 ++ ++ vtbl.8 d4, {q4-q5}, d4 ++ vtbl.8 d5, {q4-q5}, d5 ++ vtbl.8 d6, {q4-q5}, d6 ++ vtbl.8 d7, {q4-q5}, d7 ++ ++ veor q6, q6, q2 ++ veor q7, q7, q3 ++ ++ vst1.8 {q6-q7}, [r4] // overlapping stores ++ vst1.8 {q0-q1}, [r1] ++ pop {r4, pc} ++ ++.Lfullblock: ++ vmov q11, q4 ++ vmov q15, q5 ++ b .Lout ++.Lle96: ++ vmov q4, q2 ++ vmov q5, q6 ++ b .Lfinalblock ++.Lle128: ++ vmov q4, q10 ++ vmov q5, q14 ++ b .Lfinalblock ++.Lle224: ++ vmov q4, q3 ++ vmov q5, q7 ++ b .Lfinalblock ++.Llt256: ++ vmov q4, q11 ++ vmov q5, q15 ++ b .Lpartialblock + ENDPROC(chacha_4block_xor_neon) ++ ++ .align L1_CACHE_SHIFT ++.Lpermute: ++ .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ++ .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ++ .byte 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 ++ .byte 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f ++ .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ++ .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ++ .byte 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 ++ .byte 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f diff --git a/ipq806x/backport-5.4/080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch b/ipq806x/backport-5.4/080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch new file mode 100644 index 0000000..42e9048 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0069-crypto-arm64-chacha-simplify-tail-block-handling.patch @@ -0,0 +1,324 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Fri, 6 Nov 2020 17:39:38 +0100 +Subject: [PATCH] crypto: arm64/chacha - simplify tail block handling + +commit c4fc6328d6c67690a7e6e03f43a5a976a13120ef upstream. + +Based on lessons learnt from optimizing the 32-bit version of this driver, +we can simplify the arm64 version considerably, by reordering the final +two stores when the last block is not a multiple of 64 bytes. This removes +the need to use permutation instructions to calculate the elements that are +clobbered by the final overlapping store, given that the store of the +penultimate block now follows it, and that one carries the correct values +for those elements already. + +While at it, simplify the overlapping loads as well, by calculating the +address of the final overlapping load upfront, and switching to this +address for every load that would otherwise extend past the end of the +source buffer. + +There is no impact on performance, but the resulting code is substantially +smaller and easier to follow. + +Cc: Eric Biggers +Cc: "Jason A . Donenfeld" +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm64/crypto/chacha-neon-core.S | 193 ++++++++++----------------- + 1 file changed, 69 insertions(+), 124 deletions(-) + +--- a/arch/arm64/crypto/chacha-neon-core.S ++++ b/arch/arm64/crypto/chacha-neon-core.S +@@ -195,7 +195,6 @@ ENTRY(chacha_4block_xor_neon) + adr_l x10, .Lpermute + and x5, x4, #63 + add x10, x10, x5 +- add x11, x10, #64 + + // + // This function encrypts four consecutive ChaCha blocks by loading +@@ -645,11 +644,11 @@ CPU_BE( rev a15, a15 ) + zip2 v31.4s, v14.4s, v15.4s + eor a15, a15, w9 + +- mov x3, #64 ++ add x3, x2, x4 ++ sub x3, x3, #128 // start of last block ++ + subs x5, x4, #128 +- add x6, x5, x2 +- csel x3, x3, xzr, ge +- csel x2, x2, x6, ge ++ csel x2, x2, x3, ge + + // interleave 64-bit words in state n, n+2 + zip1 v0.2d, v16.2d, v18.2d +@@ -658,13 +657,10 @@ CPU_BE( rev a15, a15 ) + zip1 v8.2d, v17.2d, v19.2d + zip2 v12.2d, v17.2d, v19.2d + stp a2, a3, [x1, #-56] +- ld1 {v16.16b-v19.16b}, [x2], x3 + + subs x6, x4, #192 +- ccmp x3, xzr, #4, lt +- add x7, x6, x2 +- csel x3, x3, xzr, eq +- csel x2, x2, x7, eq ++ ld1 {v16.16b-v19.16b}, [x2], #64 ++ csel x2, x2, x3, ge + + zip1 v1.2d, v20.2d, v22.2d + zip2 v5.2d, v20.2d, v22.2d +@@ -672,13 +668,10 @@ CPU_BE( rev a15, a15 ) + zip1 v9.2d, v21.2d, v23.2d + zip2 v13.2d, v21.2d, v23.2d + stp a6, a7, [x1, #-40] +- ld1 {v20.16b-v23.16b}, [x2], x3 + + subs x7, x4, #256 +- ccmp x3, xzr, #4, lt +- add x8, x7, x2 +- csel x3, x3, xzr, eq +- csel x2, x2, x8, eq ++ ld1 {v20.16b-v23.16b}, [x2], #64 ++ csel x2, x2, x3, ge + + zip1 v2.2d, v24.2d, v26.2d + zip2 v6.2d, v24.2d, v26.2d +@@ -686,12 +679,10 @@ CPU_BE( rev a15, a15 ) + zip1 v10.2d, v25.2d, v27.2d + zip2 v14.2d, v25.2d, v27.2d + stp a10, a11, [x1, #-24] +- ld1 {v24.16b-v27.16b}, [x2], x3 + + subs x8, x4, #320 +- ccmp x3, xzr, #4, lt +- add x9, x8, x2 +- csel x2, x2, x9, eq ++ ld1 {v24.16b-v27.16b}, [x2], #64 ++ csel x2, x2, x3, ge + + zip1 v3.2d, v28.2d, v30.2d + zip2 v7.2d, v28.2d, v30.2d +@@ -699,151 +690,105 @@ CPU_BE( rev a15, a15 ) + zip1 v11.2d, v29.2d, v31.2d + zip2 v15.2d, v29.2d, v31.2d + stp a14, a15, [x1, #-8] ++ ++ tbnz x5, #63, .Lt128 + ld1 {v28.16b-v31.16b}, [x2] + + // xor with corresponding input, write to output +- tbnz x5, #63, 0f + eor v16.16b, v16.16b, v0.16b + eor v17.16b, v17.16b, v1.16b + eor v18.16b, v18.16b, v2.16b + eor v19.16b, v19.16b, v3.16b +- st1 {v16.16b-v19.16b}, [x1], #64 +- cbz x5, .Lout + +- tbnz x6, #63, 1f ++ tbnz x6, #63, .Lt192 ++ + eor v20.16b, v20.16b, v4.16b + eor v21.16b, v21.16b, v5.16b + eor v22.16b, v22.16b, v6.16b + eor v23.16b, v23.16b, v7.16b +- st1 {v20.16b-v23.16b}, [x1], #64 +- cbz x6, .Lout + +- tbnz x7, #63, 2f ++ st1 {v16.16b-v19.16b}, [x1], #64 ++ tbnz x7, #63, .Lt256 ++ + eor v24.16b, v24.16b, v8.16b + eor v25.16b, v25.16b, v9.16b + eor v26.16b, v26.16b, v10.16b + eor v27.16b, v27.16b, v11.16b +- st1 {v24.16b-v27.16b}, [x1], #64 +- cbz x7, .Lout + +- tbnz x8, #63, 3f ++ st1 {v20.16b-v23.16b}, [x1], #64 ++ tbnz x8, #63, .Lt320 ++ + eor v28.16b, v28.16b, v12.16b + eor v29.16b, v29.16b, v13.16b + eor v30.16b, v30.16b, v14.16b + eor v31.16b, v31.16b, v15.16b ++ ++ st1 {v24.16b-v27.16b}, [x1], #64 + st1 {v28.16b-v31.16b}, [x1] + + .Lout: frame_pop + ret + +- // fewer than 128 bytes of in/output +-0: ld1 {v8.16b}, [x10] +- ld1 {v9.16b}, [x11] +- movi v10.16b, #16 +- sub x2, x1, #64 +- add x1, x1, x5 +- ld1 {v16.16b-v19.16b}, [x2] +- tbl v4.16b, {v0.16b-v3.16b}, v8.16b +- tbx v20.16b, {v16.16b-v19.16b}, v9.16b +- add v8.16b, v8.16b, v10.16b +- add v9.16b, v9.16b, v10.16b +- tbl v5.16b, {v0.16b-v3.16b}, v8.16b +- tbx v21.16b, {v16.16b-v19.16b}, v9.16b +- add v8.16b, v8.16b, v10.16b +- add v9.16b, v9.16b, v10.16b +- tbl v6.16b, {v0.16b-v3.16b}, v8.16b +- tbx v22.16b, {v16.16b-v19.16b}, v9.16b +- add v8.16b, v8.16b, v10.16b +- add v9.16b, v9.16b, v10.16b +- tbl v7.16b, {v0.16b-v3.16b}, v8.16b +- tbx v23.16b, {v16.16b-v19.16b}, v9.16b +- +- eor v20.16b, v20.16b, v4.16b +- eor v21.16b, v21.16b, v5.16b +- eor v22.16b, v22.16b, v6.16b +- eor v23.16b, v23.16b, v7.16b +- st1 {v20.16b-v23.16b}, [x1] +- b .Lout +- + // fewer than 192 bytes of in/output +-1: ld1 {v8.16b}, [x10] +- ld1 {v9.16b}, [x11] +- movi v10.16b, #16 +- add x1, x1, x6 +- tbl v0.16b, {v4.16b-v7.16b}, v8.16b +- tbx v20.16b, {v16.16b-v19.16b}, v9.16b +- add v8.16b, v8.16b, v10.16b +- add v9.16b, v9.16b, v10.16b +- tbl v1.16b, {v4.16b-v7.16b}, v8.16b +- tbx v21.16b, {v16.16b-v19.16b}, v9.16b +- add v8.16b, v8.16b, v10.16b +- add v9.16b, v9.16b, v10.16b +- tbl v2.16b, {v4.16b-v7.16b}, v8.16b +- tbx v22.16b, {v16.16b-v19.16b}, v9.16b +- add v8.16b, v8.16b, v10.16b +- add v9.16b, v9.16b, v10.16b +- tbl v3.16b, {v4.16b-v7.16b}, v8.16b +- tbx v23.16b, {v16.16b-v19.16b}, v9.16b +- +- eor v20.16b, v20.16b, v0.16b +- eor v21.16b, v21.16b, v1.16b +- eor v22.16b, v22.16b, v2.16b +- eor v23.16b, v23.16b, v3.16b +- st1 {v20.16b-v23.16b}, [x1] ++.Lt192: cbz x5, 1f // exactly 128 bytes? ++ ld1 {v28.16b-v31.16b}, [x10] ++ add x5, x5, x1 ++ tbl v28.16b, {v4.16b-v7.16b}, v28.16b ++ tbl v29.16b, {v4.16b-v7.16b}, v29.16b ++ tbl v30.16b, {v4.16b-v7.16b}, v30.16b ++ tbl v31.16b, {v4.16b-v7.16b}, v31.16b ++ ++0: eor v20.16b, v20.16b, v28.16b ++ eor v21.16b, v21.16b, v29.16b ++ eor v22.16b, v22.16b, v30.16b ++ eor v23.16b, v23.16b, v31.16b ++ st1 {v20.16b-v23.16b}, [x5] // overlapping stores ++1: st1 {v16.16b-v19.16b}, [x1] + b .Lout + ++ // fewer than 128 bytes of in/output ++.Lt128: ld1 {v28.16b-v31.16b}, [x10] ++ add x5, x5, x1 ++ sub x1, x1, #64 ++ tbl v28.16b, {v0.16b-v3.16b}, v28.16b ++ tbl v29.16b, {v0.16b-v3.16b}, v29.16b ++ tbl v30.16b, {v0.16b-v3.16b}, v30.16b ++ tbl v31.16b, {v0.16b-v3.16b}, v31.16b ++ ld1 {v16.16b-v19.16b}, [x1] // reload first output block ++ b 0b ++ + // fewer than 256 bytes of in/output +-2: ld1 {v4.16b}, [x10] +- ld1 {v5.16b}, [x11] +- movi v6.16b, #16 +- add x1, x1, x7 ++.Lt256: cbz x6, 2f // exactly 192 bytes? ++ ld1 {v4.16b-v7.16b}, [x10] ++ add x6, x6, x1 + tbl v0.16b, {v8.16b-v11.16b}, v4.16b +- tbx v24.16b, {v20.16b-v23.16b}, v5.16b +- add v4.16b, v4.16b, v6.16b +- add v5.16b, v5.16b, v6.16b +- tbl v1.16b, {v8.16b-v11.16b}, v4.16b +- tbx v25.16b, {v20.16b-v23.16b}, v5.16b +- add v4.16b, v4.16b, v6.16b +- add v5.16b, v5.16b, v6.16b +- tbl v2.16b, {v8.16b-v11.16b}, v4.16b +- tbx v26.16b, {v20.16b-v23.16b}, v5.16b +- add v4.16b, v4.16b, v6.16b +- add v5.16b, v5.16b, v6.16b +- tbl v3.16b, {v8.16b-v11.16b}, v4.16b +- tbx v27.16b, {v20.16b-v23.16b}, v5.16b +- +- eor v24.16b, v24.16b, v0.16b +- eor v25.16b, v25.16b, v1.16b +- eor v26.16b, v26.16b, v2.16b +- eor v27.16b, v27.16b, v3.16b +- st1 {v24.16b-v27.16b}, [x1] ++ tbl v1.16b, {v8.16b-v11.16b}, v5.16b ++ tbl v2.16b, {v8.16b-v11.16b}, v6.16b ++ tbl v3.16b, {v8.16b-v11.16b}, v7.16b ++ ++ eor v28.16b, v28.16b, v0.16b ++ eor v29.16b, v29.16b, v1.16b ++ eor v30.16b, v30.16b, v2.16b ++ eor v31.16b, v31.16b, v3.16b ++ st1 {v28.16b-v31.16b}, [x6] // overlapping stores ++2: st1 {v20.16b-v23.16b}, [x1] + b .Lout + + // fewer than 320 bytes of in/output +-3: ld1 {v4.16b}, [x10] +- ld1 {v5.16b}, [x11] +- movi v6.16b, #16 +- add x1, x1, x8 ++.Lt320: cbz x7, 3f // exactly 256 bytes? ++ ld1 {v4.16b-v7.16b}, [x10] ++ add x7, x7, x1 + tbl v0.16b, {v12.16b-v15.16b}, v4.16b +- tbx v28.16b, {v24.16b-v27.16b}, v5.16b +- add v4.16b, v4.16b, v6.16b +- add v5.16b, v5.16b, v6.16b +- tbl v1.16b, {v12.16b-v15.16b}, v4.16b +- tbx v29.16b, {v24.16b-v27.16b}, v5.16b +- add v4.16b, v4.16b, v6.16b +- add v5.16b, v5.16b, v6.16b +- tbl v2.16b, {v12.16b-v15.16b}, v4.16b +- tbx v30.16b, {v24.16b-v27.16b}, v5.16b +- add v4.16b, v4.16b, v6.16b +- add v5.16b, v5.16b, v6.16b +- tbl v3.16b, {v12.16b-v15.16b}, v4.16b +- tbx v31.16b, {v24.16b-v27.16b}, v5.16b ++ tbl v1.16b, {v12.16b-v15.16b}, v5.16b ++ tbl v2.16b, {v12.16b-v15.16b}, v6.16b ++ tbl v3.16b, {v12.16b-v15.16b}, v7.16b + + eor v28.16b, v28.16b, v0.16b + eor v29.16b, v29.16b, v1.16b + eor v30.16b, v30.16b, v2.16b + eor v31.16b, v31.16b, v3.16b +- st1 {v28.16b-v31.16b}, [x1] ++ st1 {v28.16b-v31.16b}, [x7] // overlapping stores ++3: st1 {v24.16b-v27.16b}, [x1] + b .Lout + ENDPROC(chacha_4block_xor_neon) + +@@ -851,7 +796,7 @@ ENDPROC(chacha_4block_xor_neon) + .align L1_CACHE_SHIFT + .Lpermute: + .set .Li, 0 +- .rept 192 ++ .rept 128 + .byte (.Li - 64) + .set .Li, .Li + 1 + .endr diff --git a/ipq806x/backport-5.4/080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch b/ipq806x/backport-5.4/080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch new file mode 100644 index 0000000..084ae74 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0070-crypto-lib-chacha20poly1305-define-empty-module-exit.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 15 Jan 2021 20:30:12 +0100 +Subject: [PATCH] crypto: lib/chacha20poly1305 - define empty module exit + function + +commit ac88c322d0f2917d41d13553c69e9d7f043c8b6f upstream. + +With no mod_exit function, users are unable to unload the module after +use. I'm not aware of any reason why module unloading should be +prohibited for this one, so this commit simply adds an empty exit +function. + +Reported-and-tested-by: John Donnelly +Acked-by: Ard Biesheuvel +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + lib/crypto/chacha20poly1305.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/lib/crypto/chacha20poly1305.c ++++ b/lib/crypto/chacha20poly1305.c +@@ -364,7 +364,12 @@ static int __init mod_init(void) + return 0; + } + ++static void __exit mod_exit(void) ++{ ++} ++ + module_init(mod_init); ++module_exit(mod_exit); + MODULE_LICENSE("GPL v2"); + MODULE_DESCRIPTION("ChaCha20Poly1305 AEAD construction"); + MODULE_AUTHOR("Jason A. Donenfeld "); diff --git a/ipq806x/backport-5.4/080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch b/ipq806x/backport-5.4/080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch new file mode 100644 index 0000000..ea3cc80 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0071-crypto-arm-chacha-neon-add-missing-counter-increment.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Sun, 13 Dec 2020 15:39:29 +0100 +Subject: [PATCH] crypto: arm/chacha-neon - add missing counter increment + +commit fd16931a2f518a32753920ff20895e5cf04c8ff1 upstream. + +Commit 86cd97ec4b943af3 ("crypto: arm/chacha-neon - optimize for non-block +size multiples") refactored the chacha block handling in the glue code in +a way that may result in the counter increment to be omitted when calling +chacha_block_xor_neon() to process a full block. This violates the skcipher +API, which requires that the output IV is suitable for handling more input +as long as the preceding input has been presented in round multiples of the +block size. Also, the same code is exposed via the chacha library interface +whose callers may actually rely on this increment to occur even for final +blocks that are smaller than the chacha block size. + +So increment the counter after calling chacha_block_xor_neon(). + +Fixes: 86cd97ec4b943af3 ("crypto: arm/chacha-neon - optimize for non-block size multiples") +Reported-by: Eric Biggers +Signed-off-by: Ard Biesheuvel +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/chacha-glue.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/crypto/chacha-glue.c ++++ b/arch/arm/crypto/chacha-glue.c +@@ -60,6 +60,7 @@ static void chacha_doneon(u32 *state, u8 + chacha_block_xor_neon(state, d, s, nrounds); + if (d != dst) + memcpy(dst, buf, bytes); ++ state[12]++; + } + } + diff --git a/ipq806x/backport-5.4/080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch b/ipq806x/backport-5.4/080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch new file mode 100644 index 0000000..9e37bbb --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0072-net-WireGuard-secure-network-tunnel.patch @@ -0,0 +1,8071 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 9 Dec 2019 00:27:34 +0100 +Subject: [PATCH] net: WireGuard secure network tunnel + +commit e7096c131e5161fa3b8e52a650d7719d2857adfd upstream. + +WireGuard is a layer 3 secure networking tunnel made specifically for +the kernel, that aims to be much simpler and easier to audit than IPsec. +Extensive documentation and description of the protocol and +considerations, along with formal proofs of the cryptography, are +available at: + + * https://www.wireguard.com/ + * https://www.wireguard.com/papers/wireguard.pdf + +This commit implements WireGuard as a simple network device driver, +accessible in the usual RTNL way used by virtual network drivers. It +makes use of the udp_tunnel APIs, GRO, GSO, NAPI, and the usual set of +networking subsystem APIs. It has a somewhat novel multicore queueing +system designed for maximum throughput and minimal latency of encryption +operations, but it is implemented modestly using workqueues and NAPI. +Configuration is done via generic Netlink, and following a review from +the Netlink maintainer a year ago, several high profile userspace tools +have already implemented the API. + +This commit also comes with several different tests, both in-kernel +tests and out-of-kernel tests based on network namespaces, taking profit +of the fact that sockets used by WireGuard intentionally stay in the +namespace the WireGuard interface was originally created, exactly like +the semantics of userspace tun devices. See wireguard.com/netns/ for +pictures and examples. + +The source code is fairly short, but rather than combining everything +into a single file, WireGuard is developed as cleanly separable files, +making auditing and comprehension easier. Things are laid out as +follows: + + * noise.[ch], cookie.[ch], messages.h: These implement the bulk of the + cryptographic aspects of the protocol, and are mostly data-only in + nature, taking in buffers of bytes and spitting out buffers of + bytes. They also handle reference counting for their various shared + pieces of data, like keys and key lists. + + * ratelimiter.[ch]: Used as an integral part of cookie.[ch] for + ratelimiting certain types of cryptographic operations in accordance + with particular WireGuard semantics. + + * allowedips.[ch], peerlookup.[ch]: The main lookup structures of + WireGuard, the former being trie-like with particular semantics, an + integral part of the design of the protocol, and the latter just + being nice helper functions around the various hashtables we use. + + * device.[ch]: Implementation of functions for the netdevice and for + rtnl, responsible for maintaining the life of a given interface and + wiring it up to the rest of WireGuard. + + * peer.[ch]: Each interface has a list of peers, with helper functions + available here for creation, destruction, and reference counting. + + * socket.[ch]: Implementation of functions related to udp_socket and + the general set of kernel socket APIs, for sending and receiving + ciphertext UDP packets, and taking care of WireGuard-specific sticky + socket routing semantics for the automatic roaming. + + * netlink.[ch]: Userspace API entry point for configuring WireGuard + peers and devices. The API has been implemented by several userspace + tools and network management utility, and the WireGuard project + distributes the basic wg(8) tool. + + * queueing.[ch]: Shared function on the rx and tx path for handling + the various queues used in the multicore algorithms. + + * send.c: Handles encrypting outgoing packets in parallel on + multiple cores, before sending them in order on a single core, via + workqueues and ring buffers. Also handles sending handshake and cookie + messages as part of the protocol, in parallel. + + * receive.c: Handles decrypting incoming packets in parallel on + multiple cores, before passing them off in order to be ingested via + the rest of the networking subsystem with GRO via the typical NAPI + poll function. Also handles receiving handshake and cookie messages + as part of the protocol, in parallel. + + * timers.[ch]: Uses the timer wheel to implement protocol particular + event timeouts, and gives a set of very simple event-driven entry + point functions for callers. + + * main.c, version.h: Initialization and deinitialization of the module. + + * selftest/*.h: Runtime unit tests for some of the most security + sensitive functions. + + * tools/testing/selftests/wireguard/netns.sh: Aforementioned testing + script using network namespaces. + +This commit aims to be as self-contained as possible, implementing +WireGuard as a standalone module not needing much special handling or +coordination from the network subsystem. I expect for future +optimizations to the network stack to positively improve WireGuard, and +vice-versa, but for the time being, this exists as intentionally +standalone. + +We introduce a menu option for CONFIG_WIREGUARD, as well as providing a +verbose debug log and self-tests via CONFIG_WIREGUARD_DEBUG. + +Signed-off-by: Jason A. Donenfeld +Cc: David Miller +Cc: Greg KH +Cc: Linus Torvalds +Cc: Herbert Xu +Cc: linux-crypto@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Cc: netdev@vger.kernel.org +Signed-off-by: David S. Miller +[Jason: ported to 5.4 by doing the following: + - wg_get_device_start uses genl_family_attrbuf + - trival skb_redirect_reset change from 2c64605b590e is folded in + - skb_list_walk_safe was already backported prior] +Signed-off-by: Jason A. Donenfeld +--- + MAINTAINERS | 8 + + drivers/net/Kconfig | 41 + + drivers/net/Makefile | 1 + + drivers/net/wireguard/Makefile | 18 + + drivers/net/wireguard/allowedips.c | 381 +++++++++ + drivers/net/wireguard/allowedips.h | 59 ++ + drivers/net/wireguard/cookie.c | 236 ++++++ + drivers/net/wireguard/cookie.h | 59 ++ + drivers/net/wireguard/device.c | 458 ++++++++++ + drivers/net/wireguard/device.h | 65 ++ + drivers/net/wireguard/main.c | 64 ++ + drivers/net/wireguard/messages.h | 128 +++ + drivers/net/wireguard/netlink.c | 648 +++++++++++++++ + drivers/net/wireguard/netlink.h | 12 + + drivers/net/wireguard/noise.c | 828 +++++++++++++++++++ + drivers/net/wireguard/noise.h | 137 +++ + drivers/net/wireguard/peer.c | 240 ++++++ + drivers/net/wireguard/peer.h | 83 ++ + drivers/net/wireguard/peerlookup.c | 221 +++++ + drivers/net/wireguard/peerlookup.h | 64 ++ + drivers/net/wireguard/queueing.c | 53 ++ + drivers/net/wireguard/queueing.h | 197 +++++ + drivers/net/wireguard/ratelimiter.c | 223 +++++ + drivers/net/wireguard/ratelimiter.h | 19 + + drivers/net/wireguard/receive.c | 595 +++++++++++++ + drivers/net/wireguard/selftest/allowedips.c | 683 +++++++++++++++ + drivers/net/wireguard/selftest/counter.c | 104 +++ + drivers/net/wireguard/selftest/ratelimiter.c | 226 +++++ + drivers/net/wireguard/send.c | 413 +++++++++ + drivers/net/wireguard/socket.c | 437 ++++++++++ + drivers/net/wireguard/socket.h | 44 + + drivers/net/wireguard/timers.c | 243 ++++++ + drivers/net/wireguard/timers.h | 31 + + drivers/net/wireguard/version.h | 1 + + include/uapi/linux/wireguard.h | 196 +++++ + tools/testing/selftests/wireguard/netns.sh | 537 ++++++++++++ + 36 files changed, 7753 insertions(+) + create mode 100644 drivers/net/wireguard/Makefile + create mode 100644 drivers/net/wireguard/allowedips.c + create mode 100644 drivers/net/wireguard/allowedips.h + create mode 100644 drivers/net/wireguard/cookie.c + create mode 100644 drivers/net/wireguard/cookie.h + create mode 100644 drivers/net/wireguard/device.c + create mode 100644 drivers/net/wireguard/device.h + create mode 100644 drivers/net/wireguard/main.c + create mode 100644 drivers/net/wireguard/messages.h + create mode 100644 drivers/net/wireguard/netlink.c + create mode 100644 drivers/net/wireguard/netlink.h + create mode 100644 drivers/net/wireguard/noise.c + create mode 100644 drivers/net/wireguard/noise.h + create mode 100644 drivers/net/wireguard/peer.c + create mode 100644 drivers/net/wireguard/peer.h + create mode 100644 drivers/net/wireguard/peerlookup.c + create mode 100644 drivers/net/wireguard/peerlookup.h + create mode 100644 drivers/net/wireguard/queueing.c + create mode 100644 drivers/net/wireguard/queueing.h + create mode 100644 drivers/net/wireguard/ratelimiter.c + create mode 100644 drivers/net/wireguard/ratelimiter.h + create mode 100644 drivers/net/wireguard/receive.c + create mode 100644 drivers/net/wireguard/selftest/allowedips.c + create mode 100644 drivers/net/wireguard/selftest/counter.c + create mode 100644 drivers/net/wireguard/selftest/ratelimiter.c + create mode 100644 drivers/net/wireguard/send.c + create mode 100644 drivers/net/wireguard/socket.c + create mode 100644 drivers/net/wireguard/socket.h + create mode 100644 drivers/net/wireguard/timers.c + create mode 100644 drivers/net/wireguard/timers.h + create mode 100644 drivers/net/wireguard/version.h + create mode 100644 include/uapi/linux/wireguard.h + create mode 100755 tools/testing/selftests/wireguard/netns.sh + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -17584,6 +17584,14 @@ L: linux-gpio@vger.kernel.org + S: Maintained + F: drivers/gpio/gpio-ws16c48.c + ++WIREGUARD SECURE NETWORK TUNNEL ++M: Jason A. Donenfeld ++S: Maintained ++F: drivers/net/wireguard/ ++F: tools/testing/selftests/wireguard/ ++L: wireguard@lists.zx2c4.com ++L: netdev@vger.kernel.org ++ + WISTRON LAPTOP BUTTON DRIVER + M: Miloslav Trmac + S: Maintained +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -71,6 +71,47 @@ config DUMMY + To compile this driver as a module, choose M here: the module + will be called dummy. + ++config WIREGUARD ++ tristate "WireGuard secure network tunnel" ++ depends on NET && INET ++ depends on IPV6 || !IPV6 ++ select NET_UDP_TUNNEL ++ select DST_CACHE ++ select CRYPTO ++ select CRYPTO_LIB_CURVE25519 ++ select CRYPTO_LIB_CHACHA20POLY1305 ++ select CRYPTO_LIB_BLAKE2S ++ select CRYPTO_CHACHA20_X86_64 if X86 && 64BIT ++ select CRYPTO_POLY1305_X86_64 if X86 && 64BIT ++ select CRYPTO_BLAKE2S_X86 if X86 && 64BIT ++ select CRYPTO_CURVE25519_X86 if X86 && 64BIT ++ select CRYPTO_CHACHA20_NEON if (ARM || ARM64) && KERNEL_MODE_NEON ++ select CRYPTO_POLY1305_NEON if ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_POLY1305_ARM if ARM ++ select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON ++ select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2 ++ select CRYPTO_POLY1305_MIPS if CPU_MIPS32 || (CPU_MIPS64 && 64BIT) ++ help ++ WireGuard is a secure, fast, and easy to use replacement for IPSec ++ that uses modern cryptography and clever networking tricks. It's ++ designed to be fairly general purpose and abstract enough to fit most ++ use cases, while at the same time remaining extremely simple to ++ configure. See www.wireguard.com for more info. ++ ++ It's safe to say Y or M here, as the driver is very lightweight and ++ is only in use when an administrator chooses to add an interface. ++ ++config WIREGUARD_DEBUG ++ bool "Debugging checks and verbose messages" ++ depends on WIREGUARD ++ help ++ This will write log messages for handshake and other events ++ that occur for a WireGuard interface. It will also perform some ++ extra validation checks and unit tests at various points. This is ++ only useful for debugging. ++ ++ Say N here unless you know what you're doing. ++ + config EQUALIZER + tristate "EQL (serial line load balancing) support" + ---help--- +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_BONDING) += bonding/ + obj-$(CONFIG_IPVLAN) += ipvlan/ + obj-$(CONFIG_IPVTAP) += ipvlan/ + obj-$(CONFIG_DUMMY) += dummy.o ++obj-$(CONFIG_WIREGUARD) += wireguard/ + obj-$(CONFIG_EQUALIZER) += eql.o + obj-$(CONFIG_IFB) += ifb.o + obj-$(CONFIG_MACSEC) += macsec.o +--- /dev/null ++++ b/drivers/net/wireguard/Makefile +@@ -0,0 +1,18 @@ ++ccflags-y := -O3 ++ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt' ++ccflags-$(CONFIG_WIREGUARD_DEBUG) += -DDEBUG ++wireguard-y := main.o ++wireguard-y += noise.o ++wireguard-y += device.o ++wireguard-y += peer.o ++wireguard-y += timers.o ++wireguard-y += queueing.o ++wireguard-y += send.o ++wireguard-y += receive.o ++wireguard-y += socket.o ++wireguard-y += peerlookup.o ++wireguard-y += allowedips.o ++wireguard-y += ratelimiter.o ++wireguard-y += cookie.o ++wireguard-y += netlink.o ++obj-$(CONFIG_WIREGUARD) := wireguard.o +--- /dev/null ++++ b/drivers/net/wireguard/allowedips.c +@@ -0,0 +1,381 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "allowedips.h" ++#include "peer.h" ++ ++static void swap_endian(u8 *dst, const u8 *src, u8 bits) ++{ ++ if (bits == 32) { ++ *(u32 *)dst = be32_to_cpu(*(const __be32 *)src); ++ } else if (bits == 128) { ++ ((u64 *)dst)[0] = be64_to_cpu(((const __be64 *)src)[0]); ++ ((u64 *)dst)[1] = be64_to_cpu(((const __be64 *)src)[1]); ++ } ++} ++ ++static void copy_and_assign_cidr(struct allowedips_node *node, const u8 *src, ++ u8 cidr, u8 bits) ++{ ++ node->cidr = cidr; ++ node->bit_at_a = cidr / 8U; ++#ifdef __LITTLE_ENDIAN ++ node->bit_at_a ^= (bits / 8U - 1U) % 8U; ++#endif ++ node->bit_at_b = 7U - (cidr % 8U); ++ node->bitlen = bits; ++ memcpy(node->bits, src, bits / 8U); ++} ++#define CHOOSE_NODE(parent, key) \ ++ parent->bit[(key[parent->bit_at_a] >> parent->bit_at_b) & 1] ++ ++static void node_free_rcu(struct rcu_head *rcu) ++{ ++ kfree(container_of(rcu, struct allowedips_node, rcu)); ++} ++ ++static void push_rcu(struct allowedips_node **stack, ++ struct allowedips_node __rcu *p, unsigned int *len) ++{ ++ if (rcu_access_pointer(p)) { ++ WARN_ON(IS_ENABLED(DEBUG) && *len >= 128); ++ stack[(*len)++] = rcu_dereference_raw(p); ++ } ++} ++ ++static void root_free_rcu(struct rcu_head *rcu) ++{ ++ struct allowedips_node *node, *stack[128] = { ++ container_of(rcu, struct allowedips_node, rcu) }; ++ unsigned int len = 1; ++ ++ while (len > 0 && (node = stack[--len])) { ++ push_rcu(stack, node->bit[0], &len); ++ push_rcu(stack, node->bit[1], &len); ++ kfree(node); ++ } ++} ++ ++static void root_remove_peer_lists(struct allowedips_node *root) ++{ ++ struct allowedips_node *node, *stack[128] = { root }; ++ unsigned int len = 1; ++ ++ while (len > 0 && (node = stack[--len])) { ++ push_rcu(stack, node->bit[0], &len); ++ push_rcu(stack, node->bit[1], &len); ++ if (rcu_access_pointer(node->peer)) ++ list_del(&node->peer_list); ++ } ++} ++ ++static void walk_remove_by_peer(struct allowedips_node __rcu **top, ++ struct wg_peer *peer, struct mutex *lock) ++{ ++#define REF(p) rcu_access_pointer(p) ++#define DEREF(p) rcu_dereference_protected(*(p), lockdep_is_held(lock)) ++#define PUSH(p) ({ \ ++ WARN_ON(IS_ENABLED(DEBUG) && len >= 128); \ ++ stack[len++] = p; \ ++ }) ++ ++ struct allowedips_node __rcu **stack[128], **nptr; ++ struct allowedips_node *node, *prev; ++ unsigned int len; ++ ++ if (unlikely(!peer || !REF(*top))) ++ return; ++ ++ for (prev = NULL, len = 0, PUSH(top); len > 0; prev = node) { ++ nptr = stack[len - 1]; ++ node = DEREF(nptr); ++ if (!node) { ++ --len; ++ continue; ++ } ++ if (!prev || REF(prev->bit[0]) == node || ++ REF(prev->bit[1]) == node) { ++ if (REF(node->bit[0])) ++ PUSH(&node->bit[0]); ++ else if (REF(node->bit[1])) ++ PUSH(&node->bit[1]); ++ } else if (REF(node->bit[0]) == prev) { ++ if (REF(node->bit[1])) ++ PUSH(&node->bit[1]); ++ } else { ++ if (rcu_dereference_protected(node->peer, ++ lockdep_is_held(lock)) == peer) { ++ RCU_INIT_POINTER(node->peer, NULL); ++ list_del_init(&node->peer_list); ++ if (!node->bit[0] || !node->bit[1]) { ++ rcu_assign_pointer(*nptr, DEREF( ++ &node->bit[!REF(node->bit[0])])); ++ call_rcu(&node->rcu, node_free_rcu); ++ node = DEREF(nptr); ++ } ++ } ++ --len; ++ } ++ } ++ ++#undef REF ++#undef DEREF ++#undef PUSH ++} ++ ++static unsigned int fls128(u64 a, u64 b) ++{ ++ return a ? fls64(a) + 64U : fls64(b); ++} ++ ++static u8 common_bits(const struct allowedips_node *node, const u8 *key, ++ u8 bits) ++{ ++ if (bits == 32) ++ return 32U - fls(*(const u32 *)node->bits ^ *(const u32 *)key); ++ else if (bits == 128) ++ return 128U - fls128( ++ *(const u64 *)&node->bits[0] ^ *(const u64 *)&key[0], ++ *(const u64 *)&node->bits[8] ^ *(const u64 *)&key[8]); ++ return 0; ++} ++ ++static bool prefix_matches(const struct allowedips_node *node, const u8 *key, ++ u8 bits) ++{ ++ /* This could be much faster if it actually just compared the common ++ * bits properly, by precomputing a mask bswap(~0 << (32 - cidr)), and ++ * the rest, but it turns out that common_bits is already super fast on ++ * modern processors, even taking into account the unfortunate bswap. ++ * So, we just inline it like this instead. ++ */ ++ return common_bits(node, key, bits) >= node->cidr; ++} ++ ++static struct allowedips_node *find_node(struct allowedips_node *trie, u8 bits, ++ const u8 *key) ++{ ++ struct allowedips_node *node = trie, *found = NULL; ++ ++ while (node && prefix_matches(node, key, bits)) { ++ if (rcu_access_pointer(node->peer)) ++ found = node; ++ if (node->cidr == bits) ++ break; ++ node = rcu_dereference_bh(CHOOSE_NODE(node, key)); ++ } ++ return found; ++} ++ ++/* Returns a strong reference to a peer */ ++static struct wg_peer *lookup(struct allowedips_node __rcu *root, u8 bits, ++ const void *be_ip) ++{ ++ /* Aligned so it can be passed to fls/fls64 */ ++ u8 ip[16] __aligned(__alignof(u64)); ++ struct allowedips_node *node; ++ struct wg_peer *peer = NULL; ++ ++ swap_endian(ip, be_ip, bits); ++ ++ rcu_read_lock_bh(); ++retry: ++ node = find_node(rcu_dereference_bh(root), bits, ip); ++ if (node) { ++ peer = wg_peer_get_maybe_zero(rcu_dereference_bh(node->peer)); ++ if (!peer) ++ goto retry; ++ } ++ rcu_read_unlock_bh(); ++ return peer; ++} ++ ++static bool node_placement(struct allowedips_node __rcu *trie, const u8 *key, ++ u8 cidr, u8 bits, struct allowedips_node **rnode, ++ struct mutex *lock) ++{ ++ struct allowedips_node *node = rcu_dereference_protected(trie, ++ lockdep_is_held(lock)); ++ struct allowedips_node *parent = NULL; ++ bool exact = false; ++ ++ while (node && node->cidr <= cidr && prefix_matches(node, key, bits)) { ++ parent = node; ++ if (parent->cidr == cidr) { ++ exact = true; ++ break; ++ } ++ node = rcu_dereference_protected(CHOOSE_NODE(parent, key), ++ lockdep_is_held(lock)); ++ } ++ *rnode = parent; ++ return exact; ++} ++ ++static int add(struct allowedips_node __rcu **trie, u8 bits, const u8 *key, ++ u8 cidr, struct wg_peer *peer, struct mutex *lock) ++{ ++ struct allowedips_node *node, *parent, *down, *newnode; ++ ++ if (unlikely(cidr > bits || !peer)) ++ return -EINVAL; ++ ++ if (!rcu_access_pointer(*trie)) { ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (unlikely(!node)) ++ return -ENOMEM; ++ RCU_INIT_POINTER(node->peer, peer); ++ list_add_tail(&node->peer_list, &peer->allowedips_list); ++ copy_and_assign_cidr(node, key, cidr, bits); ++ rcu_assign_pointer(*trie, node); ++ return 0; ++ } ++ if (node_placement(*trie, key, cidr, bits, &node, lock)) { ++ rcu_assign_pointer(node->peer, peer); ++ list_move_tail(&node->peer_list, &peer->allowedips_list); ++ return 0; ++ } ++ ++ newnode = kzalloc(sizeof(*newnode), GFP_KERNEL); ++ if (unlikely(!newnode)) ++ return -ENOMEM; ++ RCU_INIT_POINTER(newnode->peer, peer); ++ list_add_tail(&newnode->peer_list, &peer->allowedips_list); ++ copy_and_assign_cidr(newnode, key, cidr, bits); ++ ++ if (!node) { ++ down = rcu_dereference_protected(*trie, lockdep_is_held(lock)); ++ } else { ++ down = rcu_dereference_protected(CHOOSE_NODE(node, key), ++ lockdep_is_held(lock)); ++ if (!down) { ++ rcu_assign_pointer(CHOOSE_NODE(node, key), newnode); ++ return 0; ++ } ++ } ++ cidr = min(cidr, common_bits(down, key, bits)); ++ parent = node; ++ ++ if (newnode->cidr == cidr) { ++ rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down); ++ if (!parent) ++ rcu_assign_pointer(*trie, newnode); ++ else ++ rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), ++ newnode); ++ } else { ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (unlikely(!node)) { ++ kfree(newnode); ++ return -ENOMEM; ++ } ++ INIT_LIST_HEAD(&node->peer_list); ++ copy_and_assign_cidr(node, newnode->bits, cidr, bits); ++ ++ rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down); ++ rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode); ++ if (!parent) ++ rcu_assign_pointer(*trie, node); ++ else ++ rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), ++ node); ++ } ++ return 0; ++} ++ ++void wg_allowedips_init(struct allowedips *table) ++{ ++ table->root4 = table->root6 = NULL; ++ table->seq = 1; ++} ++ ++void wg_allowedips_free(struct allowedips *table, struct mutex *lock) ++{ ++ struct allowedips_node __rcu *old4 = table->root4, *old6 = table->root6; ++ ++ ++table->seq; ++ RCU_INIT_POINTER(table->root4, NULL); ++ RCU_INIT_POINTER(table->root6, NULL); ++ if (rcu_access_pointer(old4)) { ++ struct allowedips_node *node = rcu_dereference_protected(old4, ++ lockdep_is_held(lock)); ++ ++ root_remove_peer_lists(node); ++ call_rcu(&node->rcu, root_free_rcu); ++ } ++ if (rcu_access_pointer(old6)) { ++ struct allowedips_node *node = rcu_dereference_protected(old6, ++ lockdep_is_held(lock)); ++ ++ root_remove_peer_lists(node); ++ call_rcu(&node->rcu, root_free_rcu); ++ } ++} ++ ++int wg_allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip, ++ u8 cidr, struct wg_peer *peer, struct mutex *lock) ++{ ++ /* Aligned so it can be passed to fls */ ++ u8 key[4] __aligned(__alignof(u32)); ++ ++ ++table->seq; ++ swap_endian(key, (const u8 *)ip, 32); ++ return add(&table->root4, 32, key, cidr, peer, lock); ++} ++ ++int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip, ++ u8 cidr, struct wg_peer *peer, struct mutex *lock) ++{ ++ /* Aligned so it can be passed to fls64 */ ++ u8 key[16] __aligned(__alignof(u64)); ++ ++ ++table->seq; ++ swap_endian(key, (const u8 *)ip, 128); ++ return add(&table->root6, 128, key, cidr, peer, lock); ++} ++ ++void wg_allowedips_remove_by_peer(struct allowedips *table, ++ struct wg_peer *peer, struct mutex *lock) ++{ ++ ++table->seq; ++ walk_remove_by_peer(&table->root4, peer, lock); ++ walk_remove_by_peer(&table->root6, peer, lock); ++} ++ ++int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr) ++{ ++ const unsigned int cidr_bytes = DIV_ROUND_UP(node->cidr, 8U); ++ swap_endian(ip, node->bits, node->bitlen); ++ memset(ip + cidr_bytes, 0, node->bitlen / 8U - cidr_bytes); ++ if (node->cidr) ++ ip[cidr_bytes - 1U] &= ~0U << (-node->cidr % 8U); ++ ++ *cidr = node->cidr; ++ return node->bitlen == 32 ? AF_INET : AF_INET6; ++} ++ ++/* Returns a strong reference to a peer */ ++struct wg_peer *wg_allowedips_lookup_dst(struct allowedips *table, ++ struct sk_buff *skb) ++{ ++ if (skb->protocol == htons(ETH_P_IP)) ++ return lookup(table->root4, 32, &ip_hdr(skb)->daddr); ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ return lookup(table->root6, 128, &ipv6_hdr(skb)->daddr); ++ return NULL; ++} ++ ++/* Returns a strong reference to a peer */ ++struct wg_peer *wg_allowedips_lookup_src(struct allowedips *table, ++ struct sk_buff *skb) ++{ ++ if (skb->protocol == htons(ETH_P_IP)) ++ return lookup(table->root4, 32, &ip_hdr(skb)->saddr); ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ return lookup(table->root6, 128, &ipv6_hdr(skb)->saddr); ++ return NULL; ++} ++ ++#include "selftest/allowedips.c" +--- /dev/null ++++ b/drivers/net/wireguard/allowedips.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_ALLOWEDIPS_H ++#define _WG_ALLOWEDIPS_H ++ ++#include ++#include ++#include ++ ++struct wg_peer; ++ ++struct allowedips_node { ++ struct wg_peer __rcu *peer; ++ struct allowedips_node __rcu *bit[2]; ++ /* While it may seem scandalous that we waste space for v4, ++ * we're alloc'ing to the nearest power of 2 anyway, so this ++ * doesn't actually make a difference. ++ */ ++ u8 bits[16] __aligned(__alignof(u64)); ++ u8 cidr, bit_at_a, bit_at_b, bitlen; ++ ++ /* Keep rarely used list at bottom to be beyond cache line. */ ++ union { ++ struct list_head peer_list; ++ struct rcu_head rcu; ++ }; ++}; ++ ++struct allowedips { ++ struct allowedips_node __rcu *root4; ++ struct allowedips_node __rcu *root6; ++ u64 seq; ++}; ++ ++void wg_allowedips_init(struct allowedips *table); ++void wg_allowedips_free(struct allowedips *table, struct mutex *mutex); ++int wg_allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip, ++ u8 cidr, struct wg_peer *peer, struct mutex *lock); ++int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip, ++ u8 cidr, struct wg_peer *peer, struct mutex *lock); ++void wg_allowedips_remove_by_peer(struct allowedips *table, ++ struct wg_peer *peer, struct mutex *lock); ++/* The ip input pointer should be __aligned(__alignof(u64))) */ ++int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr); ++ ++/* These return a strong reference to a peer: */ ++struct wg_peer *wg_allowedips_lookup_dst(struct allowedips *table, ++ struct sk_buff *skb); ++struct wg_peer *wg_allowedips_lookup_src(struct allowedips *table, ++ struct sk_buff *skb); ++ ++#ifdef DEBUG ++bool wg_allowedips_selftest(void); ++#endif ++ ++#endif /* _WG_ALLOWEDIPS_H */ +--- /dev/null ++++ b/drivers/net/wireguard/cookie.c +@@ -0,0 +1,236 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "cookie.h" ++#include "peer.h" ++#include "device.h" ++#include "messages.h" ++#include "ratelimiter.h" ++#include "timers.h" ++ ++#include ++#include ++ ++#include ++#include ++ ++void wg_cookie_checker_init(struct cookie_checker *checker, ++ struct wg_device *wg) ++{ ++ init_rwsem(&checker->secret_lock); ++ checker->secret_birthdate = ktime_get_coarse_boottime_ns(); ++ get_random_bytes(checker->secret, NOISE_HASH_LEN); ++ checker->device = wg; ++} ++ ++enum { COOKIE_KEY_LABEL_LEN = 8 }; ++static const u8 mac1_key_label[COOKIE_KEY_LABEL_LEN] = "mac1----"; ++static const u8 cookie_key_label[COOKIE_KEY_LABEL_LEN] = "cookie--"; ++ ++static void precompute_key(u8 key[NOISE_SYMMETRIC_KEY_LEN], ++ const u8 pubkey[NOISE_PUBLIC_KEY_LEN], ++ const u8 label[COOKIE_KEY_LABEL_LEN]) ++{ ++ struct blake2s_state blake; ++ ++ blake2s_init(&blake, NOISE_SYMMETRIC_KEY_LEN); ++ blake2s_update(&blake, label, COOKIE_KEY_LABEL_LEN); ++ blake2s_update(&blake, pubkey, NOISE_PUBLIC_KEY_LEN); ++ blake2s_final(&blake, key); ++} ++ ++/* Must hold peer->handshake.static_identity->lock */ ++void wg_cookie_checker_precompute_device_keys(struct cookie_checker *checker) ++{ ++ if (likely(checker->device->static_identity.has_identity)) { ++ precompute_key(checker->cookie_encryption_key, ++ checker->device->static_identity.static_public, ++ cookie_key_label); ++ precompute_key(checker->message_mac1_key, ++ checker->device->static_identity.static_public, ++ mac1_key_label); ++ } else { ++ memset(checker->cookie_encryption_key, 0, ++ NOISE_SYMMETRIC_KEY_LEN); ++ memset(checker->message_mac1_key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ } ++} ++ ++void wg_cookie_checker_precompute_peer_keys(struct wg_peer *peer) ++{ ++ precompute_key(peer->latest_cookie.cookie_decryption_key, ++ peer->handshake.remote_static, cookie_key_label); ++ precompute_key(peer->latest_cookie.message_mac1_key, ++ peer->handshake.remote_static, mac1_key_label); ++} ++ ++void wg_cookie_init(struct cookie *cookie) ++{ ++ memset(cookie, 0, sizeof(*cookie)); ++ init_rwsem(&cookie->lock); ++} ++ ++static void compute_mac1(u8 mac1[COOKIE_LEN], const void *message, size_t len, ++ const u8 key[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ len = len - sizeof(struct message_macs) + ++ offsetof(struct message_macs, mac1); ++ blake2s(mac1, message, key, COOKIE_LEN, len, NOISE_SYMMETRIC_KEY_LEN); ++} ++ ++static void compute_mac2(u8 mac2[COOKIE_LEN], const void *message, size_t len, ++ const u8 cookie[COOKIE_LEN]) ++{ ++ len = len - sizeof(struct message_macs) + ++ offsetof(struct message_macs, mac2); ++ blake2s(mac2, message, cookie, COOKIE_LEN, len, COOKIE_LEN); ++} ++ ++static void make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb, ++ struct cookie_checker *checker) ++{ ++ struct blake2s_state state; ++ ++ if (wg_birthdate_has_expired(checker->secret_birthdate, ++ COOKIE_SECRET_MAX_AGE)) { ++ down_write(&checker->secret_lock); ++ checker->secret_birthdate = ktime_get_coarse_boottime_ns(); ++ get_random_bytes(checker->secret, NOISE_HASH_LEN); ++ up_write(&checker->secret_lock); ++ } ++ ++ down_read(&checker->secret_lock); ++ ++ blake2s_init_key(&state, COOKIE_LEN, checker->secret, NOISE_HASH_LEN); ++ if (skb->protocol == htons(ETH_P_IP)) ++ blake2s_update(&state, (u8 *)&ip_hdr(skb)->saddr, ++ sizeof(struct in_addr)); ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ blake2s_update(&state, (u8 *)&ipv6_hdr(skb)->saddr, ++ sizeof(struct in6_addr)); ++ blake2s_update(&state, (u8 *)&udp_hdr(skb)->source, sizeof(__be16)); ++ blake2s_final(&state, cookie); ++ ++ up_read(&checker->secret_lock); ++} ++ ++enum cookie_mac_state wg_cookie_validate_packet(struct cookie_checker *checker, ++ struct sk_buff *skb, ++ bool check_cookie) ++{ ++ struct message_macs *macs = (struct message_macs *) ++ (skb->data + skb->len - sizeof(*macs)); ++ enum cookie_mac_state ret; ++ u8 computed_mac[COOKIE_LEN]; ++ u8 cookie[COOKIE_LEN]; ++ ++ ret = INVALID_MAC; ++ compute_mac1(computed_mac, skb->data, skb->len, ++ checker->message_mac1_key); ++ if (crypto_memneq(computed_mac, macs->mac1, COOKIE_LEN)) ++ goto out; ++ ++ ret = VALID_MAC_BUT_NO_COOKIE; ++ ++ if (!check_cookie) ++ goto out; ++ ++ make_cookie(cookie, skb, checker); ++ ++ compute_mac2(computed_mac, skb->data, skb->len, cookie); ++ if (crypto_memneq(computed_mac, macs->mac2, COOKIE_LEN)) ++ goto out; ++ ++ ret = VALID_MAC_WITH_COOKIE_BUT_RATELIMITED; ++ if (!wg_ratelimiter_allow(skb, dev_net(checker->device->dev))) ++ goto out; ++ ++ ret = VALID_MAC_WITH_COOKIE; ++ ++out: ++ return ret; ++} ++ ++void wg_cookie_add_mac_to_packet(void *message, size_t len, ++ struct wg_peer *peer) ++{ ++ struct message_macs *macs = (struct message_macs *) ++ ((u8 *)message + len - sizeof(*macs)); ++ ++ down_write(&peer->latest_cookie.lock); ++ compute_mac1(macs->mac1, message, len, ++ peer->latest_cookie.message_mac1_key); ++ memcpy(peer->latest_cookie.last_mac1_sent, macs->mac1, COOKIE_LEN); ++ peer->latest_cookie.have_sent_mac1 = true; ++ up_write(&peer->latest_cookie.lock); ++ ++ down_read(&peer->latest_cookie.lock); ++ if (peer->latest_cookie.is_valid && ++ !wg_birthdate_has_expired(peer->latest_cookie.birthdate, ++ COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY)) ++ compute_mac2(macs->mac2, message, len, ++ peer->latest_cookie.cookie); ++ else ++ memset(macs->mac2, 0, COOKIE_LEN); ++ up_read(&peer->latest_cookie.lock); ++} ++ ++void wg_cookie_message_create(struct message_handshake_cookie *dst, ++ struct sk_buff *skb, __le32 index, ++ struct cookie_checker *checker) ++{ ++ struct message_macs *macs = (struct message_macs *) ++ ((u8 *)skb->data + skb->len - sizeof(*macs)); ++ u8 cookie[COOKIE_LEN]; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE); ++ dst->receiver_index = index; ++ get_random_bytes_wait(dst->nonce, COOKIE_NONCE_LEN); ++ ++ make_cookie(cookie, skb, checker); ++ xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, ++ macs->mac1, COOKIE_LEN, dst->nonce, ++ checker->cookie_encryption_key); ++} ++ ++void wg_cookie_message_consume(struct message_handshake_cookie *src, ++ struct wg_device *wg) ++{ ++ struct wg_peer *peer = NULL; ++ u8 cookie[COOKIE_LEN]; ++ bool ret; ++ ++ if (unlikely(!wg_index_hashtable_lookup(wg->index_hashtable, ++ INDEX_HASHTABLE_HANDSHAKE | ++ INDEX_HASHTABLE_KEYPAIR, ++ src->receiver_index, &peer))) ++ return; ++ ++ down_read(&peer->latest_cookie.lock); ++ if (unlikely(!peer->latest_cookie.have_sent_mac1)) { ++ up_read(&peer->latest_cookie.lock); ++ goto out; ++ } ++ ret = xchacha20poly1305_decrypt( ++ cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie), ++ peer->latest_cookie.last_mac1_sent, COOKIE_LEN, src->nonce, ++ peer->latest_cookie.cookie_decryption_key); ++ up_read(&peer->latest_cookie.lock); ++ ++ if (ret) { ++ down_write(&peer->latest_cookie.lock); ++ memcpy(peer->latest_cookie.cookie, cookie, COOKIE_LEN); ++ peer->latest_cookie.birthdate = ktime_get_coarse_boottime_ns(); ++ peer->latest_cookie.is_valid = true; ++ peer->latest_cookie.have_sent_mac1 = false; ++ up_write(&peer->latest_cookie.lock); ++ } else { ++ net_dbg_ratelimited("%s: Could not decrypt invalid cookie response\n", ++ wg->dev->name); ++ } ++ ++out: ++ wg_peer_put(peer); ++} +--- /dev/null ++++ b/drivers/net/wireguard/cookie.h +@@ -0,0 +1,59 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_COOKIE_H ++#define _WG_COOKIE_H ++ ++#include "messages.h" ++#include ++ ++struct wg_peer; ++ ++struct cookie_checker { ++ u8 secret[NOISE_HASH_LEN]; ++ u8 cookie_encryption_key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 message_mac1_key[NOISE_SYMMETRIC_KEY_LEN]; ++ u64 secret_birthdate; ++ struct rw_semaphore secret_lock; ++ struct wg_device *device; ++}; ++ ++struct cookie { ++ u64 birthdate; ++ bool is_valid; ++ u8 cookie[COOKIE_LEN]; ++ bool have_sent_mac1; ++ u8 last_mac1_sent[COOKIE_LEN]; ++ u8 cookie_decryption_key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 message_mac1_key[NOISE_SYMMETRIC_KEY_LEN]; ++ struct rw_semaphore lock; ++}; ++ ++enum cookie_mac_state { ++ INVALID_MAC, ++ VALID_MAC_BUT_NO_COOKIE, ++ VALID_MAC_WITH_COOKIE_BUT_RATELIMITED, ++ VALID_MAC_WITH_COOKIE ++}; ++ ++void wg_cookie_checker_init(struct cookie_checker *checker, ++ struct wg_device *wg); ++void wg_cookie_checker_precompute_device_keys(struct cookie_checker *checker); ++void wg_cookie_checker_precompute_peer_keys(struct wg_peer *peer); ++void wg_cookie_init(struct cookie *cookie); ++ ++enum cookie_mac_state wg_cookie_validate_packet(struct cookie_checker *checker, ++ struct sk_buff *skb, ++ bool check_cookie); ++void wg_cookie_add_mac_to_packet(void *message, size_t len, ++ struct wg_peer *peer); ++ ++void wg_cookie_message_create(struct message_handshake_cookie *src, ++ struct sk_buff *skb, __le32 index, ++ struct cookie_checker *checker); ++void wg_cookie_message_consume(struct message_handshake_cookie *src, ++ struct wg_device *wg); ++ ++#endif /* _WG_COOKIE_H */ +--- /dev/null ++++ b/drivers/net/wireguard/device.c +@@ -0,0 +1,458 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "queueing.h" ++#include "socket.h" ++#include "timers.h" ++#include "device.h" ++#include "ratelimiter.h" ++#include "peer.h" ++#include "messages.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static LIST_HEAD(device_list); ++ ++static int wg_open(struct net_device *dev) ++{ ++ struct in_device *dev_v4 = __in_dev_get_rtnl(dev); ++ struct inet6_dev *dev_v6 = __in6_dev_get(dev); ++ struct wg_device *wg = netdev_priv(dev); ++ struct wg_peer *peer; ++ int ret; ++ ++ if (dev_v4) { ++ /* At some point we might put this check near the ip_rt_send_ ++ * redirect call of ip_forward in net/ipv4/ip_forward.c, similar ++ * to the current secpath check. ++ */ ++ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); ++ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false; ++ } ++ if (dev_v6) ++ dev_v6->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_NONE; ++ ++ ret = wg_socket_init(wg, wg->incoming_port); ++ if (ret < 0) ++ return ret; ++ mutex_lock(&wg->device_update_lock); ++ list_for_each_entry(peer, &wg->peer_list, peer_list) { ++ wg_packet_send_staged_packets(peer); ++ if (peer->persistent_keepalive_interval) ++ wg_packet_send_keepalive(peer); ++ } ++ mutex_unlock(&wg->device_update_lock); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int wg_pm_notification(struct notifier_block *nb, unsigned long action, ++ void *data) ++{ ++ struct wg_device *wg; ++ struct wg_peer *peer; ++ ++ /* If the machine is constantly suspending and resuming, as part of ++ * its normal operation rather than as a somewhat rare event, then we ++ * don't actually want to clear keys. ++ */ ++ if (IS_ENABLED(CONFIG_PM_AUTOSLEEP) || IS_ENABLED(CONFIG_ANDROID)) ++ return 0; ++ ++ if (action != PM_HIBERNATION_PREPARE && action != PM_SUSPEND_PREPARE) ++ return 0; ++ ++ rtnl_lock(); ++ list_for_each_entry(wg, &device_list, device_list) { ++ mutex_lock(&wg->device_update_lock); ++ list_for_each_entry(peer, &wg->peer_list, peer_list) { ++ del_timer(&peer->timer_zero_key_material); ++ wg_noise_handshake_clear(&peer->handshake); ++ wg_noise_keypairs_clear(&peer->keypairs); ++ } ++ mutex_unlock(&wg->device_update_lock); ++ } ++ rtnl_unlock(); ++ rcu_barrier(); ++ return 0; ++} ++ ++static struct notifier_block pm_notifier = { .notifier_call = wg_pm_notification }; ++#endif ++ ++static int wg_stop(struct net_device *dev) ++{ ++ struct wg_device *wg = netdev_priv(dev); ++ struct wg_peer *peer; ++ ++ mutex_lock(&wg->device_update_lock); ++ list_for_each_entry(peer, &wg->peer_list, peer_list) { ++ wg_packet_purge_staged_packets(peer); ++ wg_timers_stop(peer); ++ wg_noise_handshake_clear(&peer->handshake); ++ wg_noise_keypairs_clear(&peer->keypairs); ++ wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake); ++ } ++ mutex_unlock(&wg->device_update_lock); ++ skb_queue_purge(&wg->incoming_handshakes); ++ wg_socket_reinit(wg, NULL, NULL); ++ return 0; ++} ++ ++static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct wg_device *wg = netdev_priv(dev); ++ struct sk_buff_head packets; ++ struct wg_peer *peer; ++ struct sk_buff *next; ++ sa_family_t family; ++ u32 mtu; ++ int ret; ++ ++ if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol)) { ++ ret = -EPROTONOSUPPORT; ++ net_dbg_ratelimited("%s: Invalid IP packet\n", dev->name); ++ goto err; ++ } ++ ++ peer = wg_allowedips_lookup_dst(&wg->peer_allowedips, skb); ++ if (unlikely(!peer)) { ++ ret = -ENOKEY; ++ if (skb->protocol == htons(ETH_P_IP)) ++ net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI4\n", ++ dev->name, &ip_hdr(skb)->daddr); ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI6\n", ++ dev->name, &ipv6_hdr(skb)->daddr); ++ goto err; ++ } ++ ++ family = READ_ONCE(peer->endpoint.addr.sa_family); ++ if (unlikely(family != AF_INET && family != AF_INET6)) { ++ ret = -EDESTADDRREQ; ++ net_dbg_ratelimited("%s: No valid endpoint has been configured or discovered for peer %llu\n", ++ dev->name, peer->internal_id); ++ goto err_peer; ++ } ++ ++ mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; ++ ++ __skb_queue_head_init(&packets); ++ if (!skb_is_gso(skb)) { ++ skb_mark_not_on_list(skb); ++ } else { ++ struct sk_buff *segs = skb_gso_segment(skb, 0); ++ ++ if (unlikely(IS_ERR(segs))) { ++ ret = PTR_ERR(segs); ++ goto err_peer; ++ } ++ dev_kfree_skb(skb); ++ skb = segs; ++ } ++ ++ skb_list_walk_safe(skb, skb, next) { ++ skb_mark_not_on_list(skb); ++ ++ skb = skb_share_check(skb, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ continue; ++ ++ /* We only need to keep the original dst around for icmp, ++ * so at this point we're in a position to drop it. ++ */ ++ skb_dst_drop(skb); ++ ++ PACKET_CB(skb)->mtu = mtu; ++ ++ __skb_queue_tail(&packets, skb); ++ } ++ ++ spin_lock_bh(&peer->staged_packet_queue.lock); ++ /* If the queue is getting too big, we start removing the oldest packets ++ * until it's small again. We do this before adding the new packet, so ++ * we don't remove GSO segments that are in excess. ++ */ ++ while (skb_queue_len(&peer->staged_packet_queue) > MAX_STAGED_PACKETS) { ++ dev_kfree_skb(__skb_dequeue(&peer->staged_packet_queue)); ++ ++dev->stats.tx_dropped; ++ } ++ skb_queue_splice_tail(&packets, &peer->staged_packet_queue); ++ spin_unlock_bh(&peer->staged_packet_queue.lock); ++ ++ wg_packet_send_staged_packets(peer); ++ ++ wg_peer_put(peer); ++ return NETDEV_TX_OK; ++ ++err_peer: ++ wg_peer_put(peer); ++err: ++ ++dev->stats.tx_errors; ++ if (skb->protocol == htons(ETH_P_IP)) ++ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); ++ kfree_skb(skb); ++ return ret; ++} ++ ++static const struct net_device_ops netdev_ops = { ++ .ndo_open = wg_open, ++ .ndo_stop = wg_stop, ++ .ndo_start_xmit = wg_xmit, ++ .ndo_get_stats64 = ip_tunnel_get_stats64 ++}; ++ ++static void wg_destruct(struct net_device *dev) ++{ ++ struct wg_device *wg = netdev_priv(dev); ++ ++ rtnl_lock(); ++ list_del(&wg->device_list); ++ rtnl_unlock(); ++ mutex_lock(&wg->device_update_lock); ++ wg->incoming_port = 0; ++ wg_socket_reinit(wg, NULL, NULL); ++ /* The final references are cleared in the below calls to destroy_workqueue. */ ++ wg_peer_remove_all(wg); ++ destroy_workqueue(wg->handshake_receive_wq); ++ destroy_workqueue(wg->handshake_send_wq); ++ destroy_workqueue(wg->packet_crypt_wq); ++ wg_packet_queue_free(&wg->decrypt_queue, true); ++ wg_packet_queue_free(&wg->encrypt_queue, true); ++ rcu_barrier(); /* Wait for all the peers to be actually freed. */ ++ wg_ratelimiter_uninit(); ++ memzero_explicit(&wg->static_identity, sizeof(wg->static_identity)); ++ skb_queue_purge(&wg->incoming_handshakes); ++ free_percpu(dev->tstats); ++ free_percpu(wg->incoming_handshakes_worker); ++ if (wg->have_creating_net_ref) ++ put_net(wg->creating_net); ++ kvfree(wg->index_hashtable); ++ kvfree(wg->peer_hashtable); ++ mutex_unlock(&wg->device_update_lock); ++ ++ pr_debug("%s: Interface deleted\n", dev->name); ++ free_netdev(dev); ++} ++ ++static const struct device_type device_type = { .name = KBUILD_MODNAME }; ++ ++static void wg_setup(struct net_device *dev) ++{ ++ struct wg_device *wg = netdev_priv(dev); ++ enum { WG_NETDEV_FEATURES = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | ++ NETIF_F_SG | NETIF_F_GSO | ++ NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA }; ++ ++ dev->netdev_ops = &netdev_ops; ++ dev->hard_header_len = 0; ++ dev->addr_len = 0; ++ dev->needed_headroom = DATA_PACKET_HEAD_ROOM; ++ dev->needed_tailroom = noise_encrypted_len(MESSAGE_PADDING_MULTIPLE); ++ dev->type = ARPHRD_NONE; ++ dev->flags = IFF_POINTOPOINT | IFF_NOARP; ++ dev->priv_flags |= IFF_NO_QUEUE; ++ dev->features |= NETIF_F_LLTX; ++ dev->features |= WG_NETDEV_FEATURES; ++ dev->hw_features |= WG_NETDEV_FEATURES; ++ dev->hw_enc_features |= WG_NETDEV_FEATURES; ++ dev->mtu = ETH_DATA_LEN - MESSAGE_MINIMUM_LENGTH - ++ sizeof(struct udphdr) - ++ max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); ++ ++ SET_NETDEV_DEVTYPE(dev, &device_type); ++ ++ /* We need to keep the dst around in case of icmp replies. */ ++ netif_keep_dst(dev); ++ ++ memset(wg, 0, sizeof(*wg)); ++ wg->dev = dev; ++} ++ ++static int wg_newlink(struct net *src_net, struct net_device *dev, ++ struct nlattr *tb[], struct nlattr *data[], ++ struct netlink_ext_ack *extack) ++{ ++ struct wg_device *wg = netdev_priv(dev); ++ int ret = -ENOMEM; ++ ++ wg->creating_net = src_net; ++ init_rwsem(&wg->static_identity.lock); ++ mutex_init(&wg->socket_update_lock); ++ mutex_init(&wg->device_update_lock); ++ skb_queue_head_init(&wg->incoming_handshakes); ++ wg_allowedips_init(&wg->peer_allowedips); ++ wg_cookie_checker_init(&wg->cookie_checker, wg); ++ INIT_LIST_HEAD(&wg->peer_list); ++ wg->device_update_gen = 1; ++ ++ wg->peer_hashtable = wg_pubkey_hashtable_alloc(); ++ if (!wg->peer_hashtable) ++ return ret; ++ ++ wg->index_hashtable = wg_index_hashtable_alloc(); ++ if (!wg->index_hashtable) ++ goto err_free_peer_hashtable; ++ ++ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); ++ if (!dev->tstats) ++ goto err_free_index_hashtable; ++ ++ wg->incoming_handshakes_worker = ++ wg_packet_percpu_multicore_worker_alloc( ++ wg_packet_handshake_receive_worker, wg); ++ if (!wg->incoming_handshakes_worker) ++ goto err_free_tstats; ++ ++ wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s", ++ WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name); ++ if (!wg->handshake_receive_wq) ++ goto err_free_incoming_handshakes; ++ ++ wg->handshake_send_wq = alloc_workqueue("wg-kex-%s", ++ WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name); ++ if (!wg->handshake_send_wq) ++ goto err_destroy_handshake_receive; ++ ++ wg->packet_crypt_wq = alloc_workqueue("wg-crypt-%s", ++ WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0, dev->name); ++ if (!wg->packet_crypt_wq) ++ goto err_destroy_handshake_send; ++ ++ ret = wg_packet_queue_init(&wg->encrypt_queue, wg_packet_encrypt_worker, ++ true, MAX_QUEUED_PACKETS); ++ if (ret < 0) ++ goto err_destroy_packet_crypt; ++ ++ ret = wg_packet_queue_init(&wg->decrypt_queue, wg_packet_decrypt_worker, ++ true, MAX_QUEUED_PACKETS); ++ if (ret < 0) ++ goto err_free_encrypt_queue; ++ ++ ret = wg_ratelimiter_init(); ++ if (ret < 0) ++ goto err_free_decrypt_queue; ++ ++ ret = register_netdevice(dev); ++ if (ret < 0) ++ goto err_uninit_ratelimiter; ++ ++ list_add(&wg->device_list, &device_list); ++ ++ /* We wait until the end to assign priv_destructor, so that ++ * register_netdevice doesn't call it for us if it fails. ++ */ ++ dev->priv_destructor = wg_destruct; ++ ++ pr_debug("%s: Interface created\n", dev->name); ++ return ret; ++ ++err_uninit_ratelimiter: ++ wg_ratelimiter_uninit(); ++err_free_decrypt_queue: ++ wg_packet_queue_free(&wg->decrypt_queue, true); ++err_free_encrypt_queue: ++ wg_packet_queue_free(&wg->encrypt_queue, true); ++err_destroy_packet_crypt: ++ destroy_workqueue(wg->packet_crypt_wq); ++err_destroy_handshake_send: ++ destroy_workqueue(wg->handshake_send_wq); ++err_destroy_handshake_receive: ++ destroy_workqueue(wg->handshake_receive_wq); ++err_free_incoming_handshakes: ++ free_percpu(wg->incoming_handshakes_worker); ++err_free_tstats: ++ free_percpu(dev->tstats); ++err_free_index_hashtable: ++ kvfree(wg->index_hashtable); ++err_free_peer_hashtable: ++ kvfree(wg->peer_hashtable); ++ return ret; ++} ++ ++static struct rtnl_link_ops link_ops __read_mostly = { ++ .kind = KBUILD_MODNAME, ++ .priv_size = sizeof(struct wg_device), ++ .setup = wg_setup, ++ .newlink = wg_newlink, ++}; ++ ++static int wg_netdevice_notification(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ struct net_device *dev = ((struct netdev_notifier_info *)data)->dev; ++ struct wg_device *wg = netdev_priv(dev); ++ ++ ASSERT_RTNL(); ++ ++ if (action != NETDEV_REGISTER || dev->netdev_ops != &netdev_ops) ++ return 0; ++ ++ if (dev_net(dev) == wg->creating_net && wg->have_creating_net_ref) { ++ put_net(wg->creating_net); ++ wg->have_creating_net_ref = false; ++ } else if (dev_net(dev) != wg->creating_net && ++ !wg->have_creating_net_ref) { ++ wg->have_creating_net_ref = true; ++ get_net(wg->creating_net); ++ } ++ return 0; ++} ++ ++static struct notifier_block netdevice_notifier = { ++ .notifier_call = wg_netdevice_notification ++}; ++ ++int __init wg_device_init(void) ++{ ++ int ret; ++ ++#ifdef CONFIG_PM_SLEEP ++ ret = register_pm_notifier(&pm_notifier); ++ if (ret) ++ return ret; ++#endif ++ ++ ret = register_netdevice_notifier(&netdevice_notifier); ++ if (ret) ++ goto error_pm; ++ ++ ret = rtnl_link_register(&link_ops); ++ if (ret) ++ goto error_netdevice; ++ ++ return 0; ++ ++error_netdevice: ++ unregister_netdevice_notifier(&netdevice_notifier); ++error_pm: ++#ifdef CONFIG_PM_SLEEP ++ unregister_pm_notifier(&pm_notifier); ++#endif ++ return ret; ++} ++ ++void wg_device_uninit(void) ++{ ++ rtnl_link_unregister(&link_ops); ++ unregister_netdevice_notifier(&netdevice_notifier); ++#ifdef CONFIG_PM_SLEEP ++ unregister_pm_notifier(&pm_notifier); ++#endif ++ rcu_barrier(); ++} +--- /dev/null ++++ b/drivers/net/wireguard/device.h +@@ -0,0 +1,65 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_DEVICE_H ++#define _WG_DEVICE_H ++ ++#include "noise.h" ++#include "allowedips.h" ++#include "peerlookup.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct wg_device; ++ ++struct multicore_worker { ++ void *ptr; ++ struct work_struct work; ++}; ++ ++struct crypt_queue { ++ struct ptr_ring ring; ++ union { ++ struct { ++ struct multicore_worker __percpu *worker; ++ int last_cpu; ++ }; ++ struct work_struct work; ++ }; ++}; ++ ++struct wg_device { ++ struct net_device *dev; ++ struct crypt_queue encrypt_queue, decrypt_queue; ++ struct sock __rcu *sock4, *sock6; ++ struct net *creating_net; ++ struct noise_static_identity static_identity; ++ struct workqueue_struct *handshake_receive_wq, *handshake_send_wq; ++ struct workqueue_struct *packet_crypt_wq; ++ struct sk_buff_head incoming_handshakes; ++ int incoming_handshake_cpu; ++ struct multicore_worker __percpu *incoming_handshakes_worker; ++ struct cookie_checker cookie_checker; ++ struct pubkey_hashtable *peer_hashtable; ++ struct index_hashtable *index_hashtable; ++ struct allowedips peer_allowedips; ++ struct mutex device_update_lock, socket_update_lock; ++ struct list_head device_list, peer_list; ++ unsigned int num_peers, device_update_gen; ++ u32 fwmark; ++ u16 incoming_port; ++ bool have_creating_net_ref; ++}; ++ ++int wg_device_init(void); ++void wg_device_uninit(void); ++ ++#endif /* _WG_DEVICE_H */ +--- /dev/null ++++ b/drivers/net/wireguard/main.c +@@ -0,0 +1,64 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "version.h" ++#include "device.h" ++#include "noise.h" ++#include "queueing.h" ++#include "ratelimiter.h" ++#include "netlink.h" ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int __init mod_init(void) ++{ ++ int ret; ++ ++#ifdef DEBUG ++ if (!wg_allowedips_selftest() || !wg_packet_counter_selftest() || ++ !wg_ratelimiter_selftest()) ++ return -ENOTRECOVERABLE; ++#endif ++ wg_noise_init(); ++ ++ ret = wg_device_init(); ++ if (ret < 0) ++ goto err_device; ++ ++ ret = wg_genetlink_init(); ++ if (ret < 0) ++ goto err_netlink; ++ ++ pr_info("WireGuard " WIREGUARD_VERSION " loaded. See www.wireguard.com for information.\n"); ++ pr_info("Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved.\n"); ++ ++ return 0; ++ ++err_netlink: ++ wg_device_uninit(); ++err_device: ++ return ret; ++} ++ ++static void __exit mod_exit(void) ++{ ++ wg_genetlink_uninit(); ++ wg_device_uninit(); ++} ++ ++module_init(mod_init); ++module_exit(mod_exit); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("WireGuard secure network tunnel"); ++MODULE_AUTHOR("Jason A. Donenfeld "); ++MODULE_VERSION(WIREGUARD_VERSION); ++MODULE_ALIAS_RTNL_LINK(KBUILD_MODNAME); ++MODULE_ALIAS_GENL_FAMILY(WG_GENL_NAME); +--- /dev/null ++++ b/drivers/net/wireguard/messages.h +@@ -0,0 +1,128 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_MESSAGES_H ++#define _WG_MESSAGES_H ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++enum noise_lengths { ++ NOISE_PUBLIC_KEY_LEN = CURVE25519_KEY_SIZE, ++ NOISE_SYMMETRIC_KEY_LEN = CHACHA20POLY1305_KEY_SIZE, ++ NOISE_TIMESTAMP_LEN = sizeof(u64) + sizeof(u32), ++ NOISE_AUTHTAG_LEN = CHACHA20POLY1305_AUTHTAG_SIZE, ++ NOISE_HASH_LEN = BLAKE2S_HASH_SIZE ++}; ++ ++#define noise_encrypted_len(plain_len) ((plain_len) + NOISE_AUTHTAG_LEN) ++ ++enum cookie_values { ++ COOKIE_SECRET_MAX_AGE = 2 * 60, ++ COOKIE_SECRET_LATENCY = 5, ++ COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCE_SIZE, ++ COOKIE_LEN = 16 ++}; ++ ++enum counter_values { ++ COUNTER_BITS_TOTAL = 2048, ++ COUNTER_REDUNDANT_BITS = BITS_PER_LONG, ++ COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS ++}; ++ ++enum limits { ++ REKEY_AFTER_MESSAGES = 1ULL << 60, ++ REJECT_AFTER_MESSAGES = U64_MAX - COUNTER_WINDOW_SIZE - 1, ++ REKEY_TIMEOUT = 5, ++ REKEY_TIMEOUT_JITTER_MAX_JIFFIES = HZ / 3, ++ REKEY_AFTER_TIME = 120, ++ REJECT_AFTER_TIME = 180, ++ INITIATIONS_PER_SECOND = 50, ++ MAX_PEERS_PER_DEVICE = 1U << 20, ++ KEEPALIVE_TIMEOUT = 10, ++ MAX_TIMER_HANDSHAKES = 90 / REKEY_TIMEOUT, ++ MAX_QUEUED_INCOMING_HANDSHAKES = 4096, /* TODO: replace this with DQL */ ++ MAX_STAGED_PACKETS = 128, ++ MAX_QUEUED_PACKETS = 1024 /* TODO: replace this with DQL */ ++}; ++ ++enum message_type { ++ MESSAGE_INVALID = 0, ++ MESSAGE_HANDSHAKE_INITIATION = 1, ++ MESSAGE_HANDSHAKE_RESPONSE = 2, ++ MESSAGE_HANDSHAKE_COOKIE = 3, ++ MESSAGE_DATA = 4 ++}; ++ ++struct message_header { ++ /* The actual layout of this that we want is: ++ * u8 type ++ * u8 reserved_zero[3] ++ * ++ * But it turns out that by encoding this as little endian, ++ * we achieve the same thing, and it makes checking faster. ++ */ ++ __le32 type; ++}; ++ ++struct message_macs { ++ u8 mac1[COOKIE_LEN]; ++ u8 mac2[COOKIE_LEN]; ++}; ++ ++struct message_handshake_initiation { ++ struct message_header header; ++ __le32 sender_index; ++ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ u8 encrypted_static[noise_encrypted_len(NOISE_PUBLIC_KEY_LEN)]; ++ u8 encrypted_timestamp[noise_encrypted_len(NOISE_TIMESTAMP_LEN)]; ++ struct message_macs macs; ++}; ++ ++struct message_handshake_response { ++ struct message_header header; ++ __le32 sender_index; ++ __le32 receiver_index; ++ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ u8 encrypted_nothing[noise_encrypted_len(0)]; ++ struct message_macs macs; ++}; ++ ++struct message_handshake_cookie { ++ struct message_header header; ++ __le32 receiver_index; ++ u8 nonce[COOKIE_NONCE_LEN]; ++ u8 encrypted_cookie[noise_encrypted_len(COOKIE_LEN)]; ++}; ++ ++struct message_data { ++ struct message_header header; ++ __le32 key_idx; ++ __le64 counter; ++ u8 encrypted_data[]; ++}; ++ ++#define message_data_len(plain_len) \ ++ (noise_encrypted_len(plain_len) + sizeof(struct message_data)) ++ ++enum message_alignments { ++ MESSAGE_PADDING_MULTIPLE = 16, ++ MESSAGE_MINIMUM_LENGTH = message_data_len(0) ++}; ++ ++#define SKB_HEADER_LEN \ ++ (max(sizeof(struct iphdr), sizeof(struct ipv6hdr)) + \ ++ sizeof(struct udphdr) + NET_SKB_PAD) ++#define DATA_PACKET_HEAD_ROOM \ ++ ALIGN(sizeof(struct message_data) + SKB_HEADER_LEN, 4) ++ ++enum { HANDSHAKE_DSCP = 0x88 /* AF41, plus 00 ECN */ }; ++ ++#endif /* _WG_MESSAGES_H */ +--- /dev/null ++++ b/drivers/net/wireguard/netlink.c +@@ -0,0 +1,648 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "netlink.h" ++#include "device.h" ++#include "peer.h" ++#include "socket.h" ++#include "queueing.h" ++#include "messages.h" ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++static struct genl_family genl_family; ++ ++static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { ++ [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, ++ [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, ++ [WGDEVICE_A_PRIVATE_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN }, ++ [WGDEVICE_A_PUBLIC_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN }, ++ [WGDEVICE_A_FLAGS] = { .type = NLA_U32 }, ++ [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 }, ++ [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, ++ [WGDEVICE_A_PEERS] = { .type = NLA_NESTED } ++}; ++ ++static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = { ++ [WGPEER_A_PUBLIC_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN }, ++ [WGPEER_A_PRESHARED_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_SYMMETRIC_KEY_LEN }, ++ [WGPEER_A_FLAGS] = { .type = NLA_U32 }, ++ [WGPEER_A_ENDPOINT] = { .type = NLA_MIN_LEN, .len = sizeof(struct sockaddr) }, ++ [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 }, ++ [WGPEER_A_LAST_HANDSHAKE_TIME] = { .type = NLA_EXACT_LEN, .len = sizeof(struct __kernel_timespec) }, ++ [WGPEER_A_RX_BYTES] = { .type = NLA_U64 }, ++ [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, ++ [WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED }, ++ [WGPEER_A_PROTOCOL_VERSION] = { .type = NLA_U32 } ++}; ++ ++static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = { ++ [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, ++ [WGALLOWEDIP_A_IPADDR] = { .type = NLA_MIN_LEN, .len = sizeof(struct in_addr) }, ++ [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 } ++}; ++ ++static struct wg_device *lookup_interface(struct nlattr **attrs, ++ struct sk_buff *skb) ++{ ++ struct net_device *dev = NULL; ++ ++ if (!attrs[WGDEVICE_A_IFINDEX] == !attrs[WGDEVICE_A_IFNAME]) ++ return ERR_PTR(-EBADR); ++ if (attrs[WGDEVICE_A_IFINDEX]) ++ dev = dev_get_by_index(sock_net(skb->sk), ++ nla_get_u32(attrs[WGDEVICE_A_IFINDEX])); ++ else if (attrs[WGDEVICE_A_IFNAME]) ++ dev = dev_get_by_name(sock_net(skb->sk), ++ nla_data(attrs[WGDEVICE_A_IFNAME])); ++ if (!dev) ++ return ERR_PTR(-ENODEV); ++ if (!dev->rtnl_link_ops || !dev->rtnl_link_ops->kind || ++ strcmp(dev->rtnl_link_ops->kind, KBUILD_MODNAME)) { ++ dev_put(dev); ++ return ERR_PTR(-EOPNOTSUPP); ++ } ++ return netdev_priv(dev); ++} ++ ++static int get_allowedips(struct sk_buff *skb, const u8 *ip, u8 cidr, ++ int family) ++{ ++ struct nlattr *allowedip_nest; ++ ++ allowedip_nest = nla_nest_start(skb, 0); ++ if (!allowedip_nest) ++ return -EMSGSIZE; ++ ++ if (nla_put_u8(skb, WGALLOWEDIP_A_CIDR_MASK, cidr) || ++ nla_put_u16(skb, WGALLOWEDIP_A_FAMILY, family) || ++ nla_put(skb, WGALLOWEDIP_A_IPADDR, family == AF_INET6 ? ++ sizeof(struct in6_addr) : sizeof(struct in_addr), ip)) { ++ nla_nest_cancel(skb, allowedip_nest); ++ return -EMSGSIZE; ++ } ++ ++ nla_nest_end(skb, allowedip_nest); ++ return 0; ++} ++ ++struct dump_ctx { ++ struct wg_device *wg; ++ struct wg_peer *next_peer; ++ u64 allowedips_seq; ++ struct allowedips_node *next_allowedip; ++}; ++ ++#define DUMP_CTX(cb) ((struct dump_ctx *)(cb)->args) ++ ++static int ++get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx) ++{ ++ ++ struct nlattr *allowedips_nest, *peer_nest = nla_nest_start(skb, 0); ++ struct allowedips_node *allowedips_node = ctx->next_allowedip; ++ bool fail; ++ ++ if (!peer_nest) ++ return -EMSGSIZE; ++ ++ down_read(&peer->handshake.lock); ++ fail = nla_put(skb, WGPEER_A_PUBLIC_KEY, NOISE_PUBLIC_KEY_LEN, ++ peer->handshake.remote_static); ++ up_read(&peer->handshake.lock); ++ if (fail) ++ goto err; ++ ++ if (!allowedips_node) { ++ const struct __kernel_timespec last_handshake = { ++ .tv_sec = peer->walltime_last_handshake.tv_sec, ++ .tv_nsec = peer->walltime_last_handshake.tv_nsec ++ }; ++ ++ down_read(&peer->handshake.lock); ++ fail = nla_put(skb, WGPEER_A_PRESHARED_KEY, ++ NOISE_SYMMETRIC_KEY_LEN, ++ peer->handshake.preshared_key); ++ up_read(&peer->handshake.lock); ++ if (fail) ++ goto err; ++ ++ if (nla_put(skb, WGPEER_A_LAST_HANDSHAKE_TIME, ++ sizeof(last_handshake), &last_handshake) || ++ nla_put_u16(skb, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, ++ peer->persistent_keepalive_interval) || ++ nla_put_u64_64bit(skb, WGPEER_A_TX_BYTES, peer->tx_bytes, ++ WGPEER_A_UNSPEC) || ++ nla_put_u64_64bit(skb, WGPEER_A_RX_BYTES, peer->rx_bytes, ++ WGPEER_A_UNSPEC) || ++ nla_put_u32(skb, WGPEER_A_PROTOCOL_VERSION, 1)) ++ goto err; ++ ++ read_lock_bh(&peer->endpoint_lock); ++ if (peer->endpoint.addr.sa_family == AF_INET) ++ fail = nla_put(skb, WGPEER_A_ENDPOINT, ++ sizeof(peer->endpoint.addr4), ++ &peer->endpoint.addr4); ++ else if (peer->endpoint.addr.sa_family == AF_INET6) ++ fail = nla_put(skb, WGPEER_A_ENDPOINT, ++ sizeof(peer->endpoint.addr6), ++ &peer->endpoint.addr6); ++ read_unlock_bh(&peer->endpoint_lock); ++ if (fail) ++ goto err; ++ allowedips_node = ++ list_first_entry_or_null(&peer->allowedips_list, ++ struct allowedips_node, peer_list); ++ } ++ if (!allowedips_node) ++ goto no_allowedips; ++ if (!ctx->allowedips_seq) ++ ctx->allowedips_seq = peer->device->peer_allowedips.seq; ++ else if (ctx->allowedips_seq != peer->device->peer_allowedips.seq) ++ goto no_allowedips; ++ ++ allowedips_nest = nla_nest_start(skb, WGPEER_A_ALLOWEDIPS); ++ if (!allowedips_nest) ++ goto err; ++ ++ list_for_each_entry_from(allowedips_node, &peer->allowedips_list, ++ peer_list) { ++ u8 cidr, ip[16] __aligned(__alignof(u64)); ++ int family; ++ ++ family = wg_allowedips_read_node(allowedips_node, ip, &cidr); ++ if (get_allowedips(skb, ip, cidr, family)) { ++ nla_nest_end(skb, allowedips_nest); ++ nla_nest_end(skb, peer_nest); ++ ctx->next_allowedip = allowedips_node; ++ return -EMSGSIZE; ++ } ++ } ++ nla_nest_end(skb, allowedips_nest); ++no_allowedips: ++ nla_nest_end(skb, peer_nest); ++ ctx->next_allowedip = NULL; ++ ctx->allowedips_seq = 0; ++ return 0; ++err: ++ nla_nest_cancel(skb, peer_nest); ++ return -EMSGSIZE; ++} ++ ++static int wg_get_device_start(struct netlink_callback *cb) ++{ ++ struct nlattr **attrs = genl_family_attrbuf(&genl_family); ++ struct wg_device *wg; ++ int ret; ++ ++ ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + genl_family.hdrsize, attrs, ++ genl_family.maxattr, device_policy, NULL); ++ if (ret < 0) ++ return ret; ++ wg = lookup_interface(attrs, cb->skb); ++ if (IS_ERR(wg)) ++ return PTR_ERR(wg); ++ DUMP_CTX(cb)->wg = wg; ++ return 0; ++} ++ ++static int wg_get_device_dump(struct sk_buff *skb, struct netlink_callback *cb) ++{ ++ struct wg_peer *peer, *next_peer_cursor; ++ struct dump_ctx *ctx = DUMP_CTX(cb); ++ struct wg_device *wg = ctx->wg; ++ struct nlattr *peers_nest; ++ int ret = -EMSGSIZE; ++ bool done = true; ++ void *hdr; ++ ++ rtnl_lock(); ++ mutex_lock(&wg->device_update_lock); ++ cb->seq = wg->device_update_gen; ++ next_peer_cursor = ctx->next_peer; ++ ++ hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, ++ &genl_family, NLM_F_MULTI, WG_CMD_GET_DEVICE); ++ if (!hdr) ++ goto out; ++ genl_dump_check_consistent(cb, hdr); ++ ++ if (!ctx->next_peer) { ++ if (nla_put_u16(skb, WGDEVICE_A_LISTEN_PORT, ++ wg->incoming_port) || ++ nla_put_u32(skb, WGDEVICE_A_FWMARK, wg->fwmark) || ++ nla_put_u32(skb, WGDEVICE_A_IFINDEX, wg->dev->ifindex) || ++ nla_put_string(skb, WGDEVICE_A_IFNAME, wg->dev->name)) ++ goto out; ++ ++ down_read(&wg->static_identity.lock); ++ if (wg->static_identity.has_identity) { ++ if (nla_put(skb, WGDEVICE_A_PRIVATE_KEY, ++ NOISE_PUBLIC_KEY_LEN, ++ wg->static_identity.static_private) || ++ nla_put(skb, WGDEVICE_A_PUBLIC_KEY, ++ NOISE_PUBLIC_KEY_LEN, ++ wg->static_identity.static_public)) { ++ up_read(&wg->static_identity.lock); ++ goto out; ++ } ++ } ++ up_read(&wg->static_identity.lock); ++ } ++ ++ peers_nest = nla_nest_start(skb, WGDEVICE_A_PEERS); ++ if (!peers_nest) ++ goto out; ++ ret = 0; ++ /* If the last cursor was removed via list_del_init in peer_remove, then ++ * we just treat this the same as there being no more peers left. The ++ * reason is that seq_nr should indicate to userspace that this isn't a ++ * coherent dump anyway, so they'll try again. ++ */ ++ if (list_empty(&wg->peer_list) || ++ (ctx->next_peer && list_empty(&ctx->next_peer->peer_list))) { ++ nla_nest_cancel(skb, peers_nest); ++ goto out; ++ } ++ lockdep_assert_held(&wg->device_update_lock); ++ peer = list_prepare_entry(ctx->next_peer, &wg->peer_list, peer_list); ++ list_for_each_entry_continue(peer, &wg->peer_list, peer_list) { ++ if (get_peer(peer, skb, ctx)) { ++ done = false; ++ break; ++ } ++ next_peer_cursor = peer; ++ } ++ nla_nest_end(skb, peers_nest); ++ ++out: ++ if (!ret && !done && next_peer_cursor) ++ wg_peer_get(next_peer_cursor); ++ wg_peer_put(ctx->next_peer); ++ mutex_unlock(&wg->device_update_lock); ++ rtnl_unlock(); ++ ++ if (ret) { ++ genlmsg_cancel(skb, hdr); ++ return ret; ++ } ++ genlmsg_end(skb, hdr); ++ if (done) { ++ ctx->next_peer = NULL; ++ return 0; ++ } ++ ctx->next_peer = next_peer_cursor; ++ return skb->len; ++ ++ /* At this point, we can't really deal ourselves with safely zeroing out ++ * the private key material after usage. This will need an additional API ++ * in the kernel for marking skbs as zero_on_free. ++ */ ++} ++ ++static int wg_get_device_done(struct netlink_callback *cb) ++{ ++ struct dump_ctx *ctx = DUMP_CTX(cb); ++ ++ if (ctx->wg) ++ dev_put(ctx->wg->dev); ++ wg_peer_put(ctx->next_peer); ++ return 0; ++} ++ ++static int set_port(struct wg_device *wg, u16 port) ++{ ++ struct wg_peer *peer; ++ ++ if (wg->incoming_port == port) ++ return 0; ++ list_for_each_entry(peer, &wg->peer_list, peer_list) ++ wg_socket_clear_peer_endpoint_src(peer); ++ if (!netif_running(wg->dev)) { ++ wg->incoming_port = port; ++ return 0; ++ } ++ return wg_socket_init(wg, port); ++} ++ ++static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs) ++{ ++ int ret = -EINVAL; ++ u16 family; ++ u8 cidr; ++ ++ if (!attrs[WGALLOWEDIP_A_FAMILY] || !attrs[WGALLOWEDIP_A_IPADDR] || ++ !attrs[WGALLOWEDIP_A_CIDR_MASK]) ++ return ret; ++ family = nla_get_u16(attrs[WGALLOWEDIP_A_FAMILY]); ++ cidr = nla_get_u8(attrs[WGALLOWEDIP_A_CIDR_MASK]); ++ ++ if (family == AF_INET && cidr <= 32 && ++ nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in_addr)) ++ ret = wg_allowedips_insert_v4( ++ &peer->device->peer_allowedips, ++ nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer, ++ &peer->device->device_update_lock); ++ else if (family == AF_INET6 && cidr <= 128 && ++ nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in6_addr)) ++ ret = wg_allowedips_insert_v6( ++ &peer->device->peer_allowedips, ++ nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer, ++ &peer->device->device_update_lock); ++ ++ return ret; ++} ++ ++static int set_peer(struct wg_device *wg, struct nlattr **attrs) ++{ ++ u8 *public_key = NULL, *preshared_key = NULL; ++ struct wg_peer *peer = NULL; ++ u32 flags = 0; ++ int ret; ++ ++ ret = -EINVAL; ++ if (attrs[WGPEER_A_PUBLIC_KEY] && ++ nla_len(attrs[WGPEER_A_PUBLIC_KEY]) == NOISE_PUBLIC_KEY_LEN) ++ public_key = nla_data(attrs[WGPEER_A_PUBLIC_KEY]); ++ else ++ goto out; ++ if (attrs[WGPEER_A_PRESHARED_KEY] && ++ nla_len(attrs[WGPEER_A_PRESHARED_KEY]) == NOISE_SYMMETRIC_KEY_LEN) ++ preshared_key = nla_data(attrs[WGPEER_A_PRESHARED_KEY]); ++ ++ if (attrs[WGPEER_A_FLAGS]) ++ flags = nla_get_u32(attrs[WGPEER_A_FLAGS]); ++ ret = -EOPNOTSUPP; ++ if (flags & ~__WGPEER_F_ALL) ++ goto out; ++ ++ ret = -EPFNOSUPPORT; ++ if (attrs[WGPEER_A_PROTOCOL_VERSION]) { ++ if (nla_get_u32(attrs[WGPEER_A_PROTOCOL_VERSION]) != 1) ++ goto out; ++ } ++ ++ peer = wg_pubkey_hashtable_lookup(wg->peer_hashtable, ++ nla_data(attrs[WGPEER_A_PUBLIC_KEY])); ++ ret = 0; ++ if (!peer) { /* Peer doesn't exist yet. Add a new one. */ ++ if (flags & (WGPEER_F_REMOVE_ME | WGPEER_F_UPDATE_ONLY)) ++ goto out; ++ ++ /* The peer is new, so there aren't allowed IPs to remove. */ ++ flags &= ~WGPEER_F_REPLACE_ALLOWEDIPS; ++ ++ down_read(&wg->static_identity.lock); ++ if (wg->static_identity.has_identity && ++ !memcmp(nla_data(attrs[WGPEER_A_PUBLIC_KEY]), ++ wg->static_identity.static_public, ++ NOISE_PUBLIC_KEY_LEN)) { ++ /* We silently ignore peers that have the same public ++ * key as the device. The reason we do it silently is ++ * that we'd like for people to be able to reuse the ++ * same set of API calls across peers. ++ */ ++ up_read(&wg->static_identity.lock); ++ ret = 0; ++ goto out; ++ } ++ up_read(&wg->static_identity.lock); ++ ++ peer = wg_peer_create(wg, public_key, preshared_key); ++ if (IS_ERR(peer)) { ++ /* Similar to the above, if the key is invalid, we skip ++ * it without fanfare, so that services don't need to ++ * worry about doing key validation themselves. ++ */ ++ ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer); ++ peer = NULL; ++ goto out; ++ } ++ /* Take additional reference, as though we've just been ++ * looked up. ++ */ ++ wg_peer_get(peer); ++ } ++ ++ if (flags & WGPEER_F_REMOVE_ME) { ++ wg_peer_remove(peer); ++ goto out; ++ } ++ ++ if (preshared_key) { ++ down_write(&peer->handshake.lock); ++ memcpy(&peer->handshake.preshared_key, preshared_key, ++ NOISE_SYMMETRIC_KEY_LEN); ++ up_write(&peer->handshake.lock); ++ } ++ ++ if (attrs[WGPEER_A_ENDPOINT]) { ++ struct sockaddr *addr = nla_data(attrs[WGPEER_A_ENDPOINT]); ++ size_t len = nla_len(attrs[WGPEER_A_ENDPOINT]); ++ ++ if ((len == sizeof(struct sockaddr_in) && ++ addr->sa_family == AF_INET) || ++ (len == sizeof(struct sockaddr_in6) && ++ addr->sa_family == AF_INET6)) { ++ struct endpoint endpoint = { { { 0 } } }; ++ ++ memcpy(&endpoint.addr, addr, len); ++ wg_socket_set_peer_endpoint(peer, &endpoint); ++ } ++ } ++ ++ if (flags & WGPEER_F_REPLACE_ALLOWEDIPS) ++ wg_allowedips_remove_by_peer(&wg->peer_allowedips, peer, ++ &wg->device_update_lock); ++ ++ if (attrs[WGPEER_A_ALLOWEDIPS]) { ++ struct nlattr *attr, *allowedip[WGALLOWEDIP_A_MAX + 1]; ++ int rem; ++ ++ nla_for_each_nested(attr, attrs[WGPEER_A_ALLOWEDIPS], rem) { ++ ret = nla_parse_nested(allowedip, WGALLOWEDIP_A_MAX, ++ attr, allowedip_policy, NULL); ++ if (ret < 0) ++ goto out; ++ ret = set_allowedip(peer, allowedip); ++ if (ret < 0) ++ goto out; ++ } ++ } ++ ++ if (attrs[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) { ++ const u16 persistent_keepalive_interval = nla_get_u16( ++ attrs[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); ++ const bool send_keepalive = ++ !peer->persistent_keepalive_interval && ++ persistent_keepalive_interval && ++ netif_running(wg->dev); ++ ++ peer->persistent_keepalive_interval = persistent_keepalive_interval; ++ if (send_keepalive) ++ wg_packet_send_keepalive(peer); ++ } ++ ++ if (netif_running(wg->dev)) ++ wg_packet_send_staged_packets(peer); ++ ++out: ++ wg_peer_put(peer); ++ if (attrs[WGPEER_A_PRESHARED_KEY]) ++ memzero_explicit(nla_data(attrs[WGPEER_A_PRESHARED_KEY]), ++ nla_len(attrs[WGPEER_A_PRESHARED_KEY])); ++ return ret; ++} ++ ++static int wg_set_device(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct wg_device *wg = lookup_interface(info->attrs, skb); ++ u32 flags = 0; ++ int ret; ++ ++ if (IS_ERR(wg)) { ++ ret = PTR_ERR(wg); ++ goto out_nodev; ++ } ++ ++ rtnl_lock(); ++ mutex_lock(&wg->device_update_lock); ++ ++ if (info->attrs[WGDEVICE_A_FLAGS]) ++ flags = nla_get_u32(info->attrs[WGDEVICE_A_FLAGS]); ++ ret = -EOPNOTSUPP; ++ if (flags & ~__WGDEVICE_F_ALL) ++ goto out; ++ ++ ret = -EPERM; ++ if ((info->attrs[WGDEVICE_A_LISTEN_PORT] || ++ info->attrs[WGDEVICE_A_FWMARK]) && ++ !ns_capable(wg->creating_net->user_ns, CAP_NET_ADMIN)) ++ goto out; ++ ++ ++wg->device_update_gen; ++ ++ if (info->attrs[WGDEVICE_A_FWMARK]) { ++ struct wg_peer *peer; ++ ++ wg->fwmark = nla_get_u32(info->attrs[WGDEVICE_A_FWMARK]); ++ list_for_each_entry(peer, &wg->peer_list, peer_list) ++ wg_socket_clear_peer_endpoint_src(peer); ++ } ++ ++ if (info->attrs[WGDEVICE_A_LISTEN_PORT]) { ++ ret = set_port(wg, ++ nla_get_u16(info->attrs[WGDEVICE_A_LISTEN_PORT])); ++ if (ret) ++ goto out; ++ } ++ ++ if (flags & WGDEVICE_F_REPLACE_PEERS) ++ wg_peer_remove_all(wg); ++ ++ if (info->attrs[WGDEVICE_A_PRIVATE_KEY] && ++ nla_len(info->attrs[WGDEVICE_A_PRIVATE_KEY]) == ++ NOISE_PUBLIC_KEY_LEN) { ++ u8 *private_key = nla_data(info->attrs[WGDEVICE_A_PRIVATE_KEY]); ++ u8 public_key[NOISE_PUBLIC_KEY_LEN]; ++ struct wg_peer *peer, *temp; ++ ++ if (!crypto_memneq(wg->static_identity.static_private, ++ private_key, NOISE_PUBLIC_KEY_LEN)) ++ goto skip_set_private_key; ++ ++ /* We remove before setting, to prevent race, which means doing ++ * two 25519-genpub ops. ++ */ ++ if (curve25519_generate_public(public_key, private_key)) { ++ peer = wg_pubkey_hashtable_lookup(wg->peer_hashtable, ++ public_key); ++ if (peer) { ++ wg_peer_put(peer); ++ wg_peer_remove(peer); ++ } ++ } ++ ++ down_write(&wg->static_identity.lock); ++ wg_noise_set_static_identity_private_key(&wg->static_identity, ++ private_key); ++ list_for_each_entry_safe(peer, temp, &wg->peer_list, ++ peer_list) { ++ if (wg_noise_precompute_static_static(peer)) ++ wg_noise_expire_current_peer_keypairs(peer); ++ else ++ wg_peer_remove(peer); ++ } ++ wg_cookie_checker_precompute_device_keys(&wg->cookie_checker); ++ up_write(&wg->static_identity.lock); ++ } ++skip_set_private_key: ++ ++ if (info->attrs[WGDEVICE_A_PEERS]) { ++ struct nlattr *attr, *peer[WGPEER_A_MAX + 1]; ++ int rem; ++ ++ nla_for_each_nested(attr, info->attrs[WGDEVICE_A_PEERS], rem) { ++ ret = nla_parse_nested(peer, WGPEER_A_MAX, attr, ++ peer_policy, NULL); ++ if (ret < 0) ++ goto out; ++ ret = set_peer(wg, peer); ++ if (ret < 0) ++ goto out; ++ } ++ } ++ ret = 0; ++ ++out: ++ mutex_unlock(&wg->device_update_lock); ++ rtnl_unlock(); ++ dev_put(wg->dev); ++out_nodev: ++ if (info->attrs[WGDEVICE_A_PRIVATE_KEY]) ++ memzero_explicit(nla_data(info->attrs[WGDEVICE_A_PRIVATE_KEY]), ++ nla_len(info->attrs[WGDEVICE_A_PRIVATE_KEY])); ++ return ret; ++} ++ ++static const struct genl_ops genl_ops[] = { ++ { ++ .cmd = WG_CMD_GET_DEVICE, ++ .start = wg_get_device_start, ++ .dumpit = wg_get_device_dump, ++ .done = wg_get_device_done, ++ .flags = GENL_UNS_ADMIN_PERM ++ }, { ++ .cmd = WG_CMD_SET_DEVICE, ++ .doit = wg_set_device, ++ .flags = GENL_UNS_ADMIN_PERM ++ } ++}; ++ ++static struct genl_family genl_family __ro_after_init = { ++ .ops = genl_ops, ++ .n_ops = ARRAY_SIZE(genl_ops), ++ .name = WG_GENL_NAME, ++ .version = WG_GENL_VERSION, ++ .maxattr = WGDEVICE_A_MAX, ++ .module = THIS_MODULE, ++ .policy = device_policy, ++ .netnsok = true ++}; ++ ++int __init wg_genetlink_init(void) ++{ ++ return genl_register_family(&genl_family); ++} ++ ++void __exit wg_genetlink_uninit(void) ++{ ++ genl_unregister_family(&genl_family); ++} +--- /dev/null ++++ b/drivers/net/wireguard/netlink.h +@@ -0,0 +1,12 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_NETLINK_H ++#define _WG_NETLINK_H ++ ++int wg_genetlink_init(void); ++void wg_genetlink_uninit(void); ++ ++#endif /* _WG_NETLINK_H */ +--- /dev/null ++++ b/drivers/net/wireguard/noise.c +@@ -0,0 +1,828 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "noise.h" ++#include "device.h" ++#include "peer.h" ++#include "messages.h" ++#include "queueing.h" ++#include "peerlookup.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* This implements Noise_IKpsk2: ++ * ++ * <- s ++ * ****** ++ * -> e, es, s, ss, {t} ++ * <- e, ee, se, psk, {} ++ */ ++ ++static const u8 handshake_name[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; ++static const u8 identifier_name[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; ++static u8 handshake_init_hash[NOISE_HASH_LEN] __ro_after_init; ++static u8 handshake_init_chaining_key[NOISE_HASH_LEN] __ro_after_init; ++static atomic64_t keypair_counter = ATOMIC64_INIT(0); ++ ++void __init wg_noise_init(void) ++{ ++ struct blake2s_state blake; ++ ++ blake2s(handshake_init_chaining_key, handshake_name, NULL, ++ NOISE_HASH_LEN, sizeof(handshake_name), 0); ++ blake2s_init(&blake, NOISE_HASH_LEN); ++ blake2s_update(&blake, handshake_init_chaining_key, NOISE_HASH_LEN); ++ blake2s_update(&blake, identifier_name, sizeof(identifier_name)); ++ blake2s_final(&blake, handshake_init_hash); ++} ++ ++/* Must hold peer->handshake.static_identity->lock */ ++bool wg_noise_precompute_static_static(struct wg_peer *peer) ++{ ++ bool ret = true; ++ ++ down_write(&peer->handshake.lock); ++ if (peer->handshake.static_identity->has_identity) ++ ret = curve25519( ++ peer->handshake.precomputed_static_static, ++ peer->handshake.static_identity->static_private, ++ peer->handshake.remote_static); ++ else ++ memset(peer->handshake.precomputed_static_static, 0, ++ NOISE_PUBLIC_KEY_LEN); ++ up_write(&peer->handshake.lock); ++ return ret; ++} ++ ++bool wg_noise_handshake_init(struct noise_handshake *handshake, ++ struct noise_static_identity *static_identity, ++ const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], ++ const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN], ++ struct wg_peer *peer) ++{ ++ memset(handshake, 0, sizeof(*handshake)); ++ init_rwsem(&handshake->lock); ++ handshake->entry.type = INDEX_HASHTABLE_HANDSHAKE; ++ handshake->entry.peer = peer; ++ memcpy(handshake->remote_static, peer_public_key, NOISE_PUBLIC_KEY_LEN); ++ if (peer_preshared_key) ++ memcpy(handshake->preshared_key, peer_preshared_key, ++ NOISE_SYMMETRIC_KEY_LEN); ++ handshake->static_identity = static_identity; ++ handshake->state = HANDSHAKE_ZEROED; ++ return wg_noise_precompute_static_static(peer); ++} ++ ++static void handshake_zero(struct noise_handshake *handshake) ++{ ++ memset(&handshake->ephemeral_private, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->remote_ephemeral, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->hash, 0, NOISE_HASH_LEN); ++ memset(&handshake->chaining_key, 0, NOISE_HASH_LEN); ++ handshake->remote_index = 0; ++ handshake->state = HANDSHAKE_ZEROED; ++} ++ ++void wg_noise_handshake_clear(struct noise_handshake *handshake) ++{ ++ wg_index_hashtable_remove( ++ handshake->entry.peer->device->index_hashtable, ++ &handshake->entry); ++ down_write(&handshake->lock); ++ handshake_zero(handshake); ++ up_write(&handshake->lock); ++ wg_index_hashtable_remove( ++ handshake->entry.peer->device->index_hashtable, ++ &handshake->entry); ++} ++ ++static struct noise_keypair *keypair_create(struct wg_peer *peer) ++{ ++ struct noise_keypair *keypair = kzalloc(sizeof(*keypair), GFP_KERNEL); ++ ++ if (unlikely(!keypair)) ++ return NULL; ++ keypair->internal_id = atomic64_inc_return(&keypair_counter); ++ keypair->entry.type = INDEX_HASHTABLE_KEYPAIR; ++ keypair->entry.peer = peer; ++ kref_init(&keypair->refcount); ++ return keypair; ++} ++ ++static void keypair_free_rcu(struct rcu_head *rcu) ++{ ++ kzfree(container_of(rcu, struct noise_keypair, rcu)); ++} ++ ++static void keypair_free_kref(struct kref *kref) ++{ ++ struct noise_keypair *keypair = ++ container_of(kref, struct noise_keypair, refcount); ++ ++ net_dbg_ratelimited("%s: Keypair %llu destroyed for peer %llu\n", ++ keypair->entry.peer->device->dev->name, ++ keypair->internal_id, ++ keypair->entry.peer->internal_id); ++ wg_index_hashtable_remove(keypair->entry.peer->device->index_hashtable, ++ &keypair->entry); ++ call_rcu(&keypair->rcu, keypair_free_rcu); ++} ++ ++void wg_noise_keypair_put(struct noise_keypair *keypair, bool unreference_now) ++{ ++ if (unlikely(!keypair)) ++ return; ++ if (unlikely(unreference_now)) ++ wg_index_hashtable_remove( ++ keypair->entry.peer->device->index_hashtable, ++ &keypair->entry); ++ kref_put(&keypair->refcount, keypair_free_kref); ++} ++ ++struct noise_keypair *wg_noise_keypair_get(struct noise_keypair *keypair) ++{ ++ RCU_LOCKDEP_WARN(!rcu_read_lock_bh_held(), ++ "Taking noise keypair reference without holding the RCU BH read lock"); ++ if (unlikely(!keypair || !kref_get_unless_zero(&keypair->refcount))) ++ return NULL; ++ return keypair; ++} ++ ++void wg_noise_keypairs_clear(struct noise_keypairs *keypairs) ++{ ++ struct noise_keypair *old; ++ ++ spin_lock_bh(&keypairs->keypair_update_lock); ++ ++ /* We zero the next_keypair before zeroing the others, so that ++ * wg_noise_received_with_keypair returns early before subsequent ones ++ * are zeroed. ++ */ ++ old = rcu_dereference_protected(keypairs->next_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)); ++ RCU_INIT_POINTER(keypairs->next_keypair, NULL); ++ wg_noise_keypair_put(old, true); ++ ++ old = rcu_dereference_protected(keypairs->previous_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)); ++ RCU_INIT_POINTER(keypairs->previous_keypair, NULL); ++ wg_noise_keypair_put(old, true); ++ ++ old = rcu_dereference_protected(keypairs->current_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)); ++ RCU_INIT_POINTER(keypairs->current_keypair, NULL); ++ wg_noise_keypair_put(old, true); ++ ++ spin_unlock_bh(&keypairs->keypair_update_lock); ++} ++ ++void wg_noise_expire_current_peer_keypairs(struct wg_peer *peer) ++{ ++ struct noise_keypair *keypair; ++ ++ wg_noise_handshake_clear(&peer->handshake); ++ wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake); ++ ++ spin_lock_bh(&peer->keypairs.keypair_update_lock); ++ keypair = rcu_dereference_protected(peer->keypairs.next_keypair, ++ lockdep_is_held(&peer->keypairs.keypair_update_lock)); ++ if (keypair) ++ keypair->sending.is_valid = false; ++ keypair = rcu_dereference_protected(peer->keypairs.current_keypair, ++ lockdep_is_held(&peer->keypairs.keypair_update_lock)); ++ if (keypair) ++ keypair->sending.is_valid = false; ++ spin_unlock_bh(&peer->keypairs.keypair_update_lock); ++} ++ ++static void add_new_keypair(struct noise_keypairs *keypairs, ++ struct noise_keypair *new_keypair) ++{ ++ struct noise_keypair *previous_keypair, *next_keypair, *current_keypair; ++ ++ spin_lock_bh(&keypairs->keypair_update_lock); ++ previous_keypair = rcu_dereference_protected(keypairs->previous_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)); ++ next_keypair = rcu_dereference_protected(keypairs->next_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)); ++ current_keypair = rcu_dereference_protected(keypairs->current_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)); ++ if (new_keypair->i_am_the_initiator) { ++ /* If we're the initiator, it means we've sent a handshake, and ++ * received a confirmation response, which means this new ++ * keypair can now be used. ++ */ ++ if (next_keypair) { ++ /* If there already was a next keypair pending, we ++ * demote it to be the previous keypair, and free the ++ * existing current. Note that this means KCI can result ++ * in this transition. It would perhaps be more sound to ++ * always just get rid of the unused next keypair ++ * instead of putting it in the previous slot, but this ++ * might be a bit less robust. Something to think about ++ * for the future. ++ */ ++ RCU_INIT_POINTER(keypairs->next_keypair, NULL); ++ rcu_assign_pointer(keypairs->previous_keypair, ++ next_keypair); ++ wg_noise_keypair_put(current_keypair, true); ++ } else /* If there wasn't an existing next keypair, we replace ++ * the previous with the current one. ++ */ ++ rcu_assign_pointer(keypairs->previous_keypair, ++ current_keypair); ++ /* At this point we can get rid of the old previous keypair, and ++ * set up the new keypair. ++ */ ++ wg_noise_keypair_put(previous_keypair, true); ++ rcu_assign_pointer(keypairs->current_keypair, new_keypair); ++ } else { ++ /* If we're the responder, it means we can't use the new keypair ++ * until we receive confirmation via the first data packet, so ++ * we get rid of the existing previous one, the possibly ++ * existing next one, and slide in the new next one. ++ */ ++ rcu_assign_pointer(keypairs->next_keypair, new_keypair); ++ wg_noise_keypair_put(next_keypair, true); ++ RCU_INIT_POINTER(keypairs->previous_keypair, NULL); ++ wg_noise_keypair_put(previous_keypair, true); ++ } ++ spin_unlock_bh(&keypairs->keypair_update_lock); ++} ++ ++bool wg_noise_received_with_keypair(struct noise_keypairs *keypairs, ++ struct noise_keypair *received_keypair) ++{ ++ struct noise_keypair *old_keypair; ++ bool key_is_new; ++ ++ /* We first check without taking the spinlock. */ ++ key_is_new = received_keypair == ++ rcu_access_pointer(keypairs->next_keypair); ++ if (likely(!key_is_new)) ++ return false; ++ ++ spin_lock_bh(&keypairs->keypair_update_lock); ++ /* After locking, we double check that things didn't change from ++ * beneath us. ++ */ ++ if (unlikely(received_keypair != ++ rcu_dereference_protected(keypairs->next_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)))) { ++ spin_unlock_bh(&keypairs->keypair_update_lock); ++ return false; ++ } ++ ++ /* When we've finally received the confirmation, we slide the next ++ * into the current, the current into the previous, and get rid of ++ * the old previous. ++ */ ++ old_keypair = rcu_dereference_protected(keypairs->previous_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock)); ++ rcu_assign_pointer(keypairs->previous_keypair, ++ rcu_dereference_protected(keypairs->current_keypair, ++ lockdep_is_held(&keypairs->keypair_update_lock))); ++ wg_noise_keypair_put(old_keypair, true); ++ rcu_assign_pointer(keypairs->current_keypair, received_keypair); ++ RCU_INIT_POINTER(keypairs->next_keypair, NULL); ++ ++ spin_unlock_bh(&keypairs->keypair_update_lock); ++ return true; ++} ++ ++/* Must hold static_identity->lock */ ++void wg_noise_set_static_identity_private_key( ++ struct noise_static_identity *static_identity, ++ const u8 private_key[NOISE_PUBLIC_KEY_LEN]) ++{ ++ memcpy(static_identity->static_private, private_key, ++ NOISE_PUBLIC_KEY_LEN); ++ curve25519_clamp_secret(static_identity->static_private); ++ static_identity->has_identity = curve25519_generate_public( ++ static_identity->static_public, private_key); ++} ++ ++/* This is Hugo Krawczyk's HKDF: ++ * - https://eprint.iacr.org/2010/264.pdf ++ * - https://tools.ietf.org/html/rfc5869 ++ */ ++static void kdf(u8 *first_dst, u8 *second_dst, u8 *third_dst, const u8 *data, ++ size_t first_len, size_t second_len, size_t third_len, ++ size_t data_len, const u8 chaining_key[NOISE_HASH_LEN]) ++{ ++ u8 output[BLAKE2S_HASH_SIZE + 1]; ++ u8 secret[BLAKE2S_HASH_SIZE]; ++ ++ WARN_ON(IS_ENABLED(DEBUG) && ++ (first_len > BLAKE2S_HASH_SIZE || ++ second_len > BLAKE2S_HASH_SIZE || ++ third_len > BLAKE2S_HASH_SIZE || ++ ((second_len || second_dst || third_len || third_dst) && ++ (!first_len || !first_dst)) || ++ ((third_len || third_dst) && (!second_len || !second_dst)))); ++ ++ /* Extract entropy from data into secret */ ++ blake2s256_hmac(secret, data, chaining_key, data_len, NOISE_HASH_LEN); ++ ++ if (!first_dst || !first_len) ++ goto out; ++ ++ /* Expand first key: key = secret, data = 0x1 */ ++ output[0] = 1; ++ blake2s256_hmac(output, output, secret, 1, BLAKE2S_HASH_SIZE); ++ memcpy(first_dst, output, first_len); ++ ++ if (!second_dst || !second_len) ++ goto out; ++ ++ /* Expand second key: key = secret, data = first-key || 0x2 */ ++ output[BLAKE2S_HASH_SIZE] = 2; ++ blake2s256_hmac(output, output, secret, BLAKE2S_HASH_SIZE + 1, ++ BLAKE2S_HASH_SIZE); ++ memcpy(second_dst, output, second_len); ++ ++ if (!third_dst || !third_len) ++ goto out; ++ ++ /* Expand third key: key = secret, data = second-key || 0x3 */ ++ output[BLAKE2S_HASH_SIZE] = 3; ++ blake2s256_hmac(output, output, secret, BLAKE2S_HASH_SIZE + 1, ++ BLAKE2S_HASH_SIZE); ++ memcpy(third_dst, output, third_len); ++ ++out: ++ /* Clear sensitive data from stack */ ++ memzero_explicit(secret, BLAKE2S_HASH_SIZE); ++ memzero_explicit(output, BLAKE2S_HASH_SIZE + 1); ++} ++ ++static void symmetric_key_init(struct noise_symmetric_key *key) ++{ ++ spin_lock_init(&key->counter.receive.lock); ++ atomic64_set(&key->counter.counter, 0); ++ memset(key->counter.receive.backtrack, 0, ++ sizeof(key->counter.receive.backtrack)); ++ key->birthdate = ktime_get_coarse_boottime_ns(); ++ key->is_valid = true; ++} ++ ++static void derive_keys(struct noise_symmetric_key *first_dst, ++ struct noise_symmetric_key *second_dst, ++ const u8 chaining_key[NOISE_HASH_LEN]) ++{ ++ kdf(first_dst->key, second_dst->key, NULL, NULL, ++ NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0, ++ chaining_key); ++ symmetric_key_init(first_dst); ++ symmetric_key_init(second_dst); ++} ++ ++static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN], ++ u8 key[NOISE_SYMMETRIC_KEY_LEN], ++ const u8 private[NOISE_PUBLIC_KEY_LEN], ++ const u8 public[NOISE_PUBLIC_KEY_LEN]) ++{ ++ u8 dh_calculation[NOISE_PUBLIC_KEY_LEN]; ++ ++ if (unlikely(!curve25519(dh_calculation, private, public))) ++ return false; ++ kdf(chaining_key, key, NULL, dh_calculation, NOISE_HASH_LEN, ++ NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, chaining_key); ++ memzero_explicit(dh_calculation, NOISE_PUBLIC_KEY_LEN); ++ return true; ++} ++ ++static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len) ++{ ++ struct blake2s_state blake; ++ ++ blake2s_init(&blake, NOISE_HASH_LEN); ++ blake2s_update(&blake, hash, NOISE_HASH_LEN); ++ blake2s_update(&blake, src, src_len); ++ blake2s_final(&blake, hash); ++} ++ ++static void mix_psk(u8 chaining_key[NOISE_HASH_LEN], u8 hash[NOISE_HASH_LEN], ++ u8 key[NOISE_SYMMETRIC_KEY_LEN], ++ const u8 psk[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ u8 temp_hash[NOISE_HASH_LEN]; ++ ++ kdf(chaining_key, temp_hash, key, psk, NOISE_HASH_LEN, NOISE_HASH_LEN, ++ NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, chaining_key); ++ mix_hash(hash, temp_hash, NOISE_HASH_LEN); ++ memzero_explicit(temp_hash, NOISE_HASH_LEN); ++} ++ ++static void handshake_init(u8 chaining_key[NOISE_HASH_LEN], ++ u8 hash[NOISE_HASH_LEN], ++ const u8 remote_static[NOISE_PUBLIC_KEY_LEN]) ++{ ++ memcpy(hash, handshake_init_hash, NOISE_HASH_LEN); ++ memcpy(chaining_key, handshake_init_chaining_key, NOISE_HASH_LEN); ++ mix_hash(hash, remote_static, NOISE_PUBLIC_KEY_LEN); ++} ++ ++static void message_encrypt(u8 *dst_ciphertext, const u8 *src_plaintext, ++ size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], ++ u8 hash[NOISE_HASH_LEN]) ++{ ++ chacha20poly1305_encrypt(dst_ciphertext, src_plaintext, src_len, hash, ++ NOISE_HASH_LEN, ++ 0 /* Always zero for Noise_IK */, key); ++ mix_hash(hash, dst_ciphertext, noise_encrypted_len(src_len)); ++} ++ ++static bool message_decrypt(u8 *dst_plaintext, const u8 *src_ciphertext, ++ size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], ++ u8 hash[NOISE_HASH_LEN]) ++{ ++ if (!chacha20poly1305_decrypt(dst_plaintext, src_ciphertext, src_len, ++ hash, NOISE_HASH_LEN, ++ 0 /* Always zero for Noise_IK */, key)) ++ return false; ++ mix_hash(hash, src_ciphertext, src_len); ++ return true; ++} ++ ++static void message_ephemeral(u8 ephemeral_dst[NOISE_PUBLIC_KEY_LEN], ++ const u8 ephemeral_src[NOISE_PUBLIC_KEY_LEN], ++ u8 chaining_key[NOISE_HASH_LEN], ++ u8 hash[NOISE_HASH_LEN]) ++{ ++ if (ephemeral_dst != ephemeral_src) ++ memcpy(ephemeral_dst, ephemeral_src, NOISE_PUBLIC_KEY_LEN); ++ mix_hash(hash, ephemeral_src, NOISE_PUBLIC_KEY_LEN); ++ kdf(chaining_key, NULL, NULL, ephemeral_src, NOISE_HASH_LEN, 0, 0, ++ NOISE_PUBLIC_KEY_LEN, chaining_key); ++} ++ ++static void tai64n_now(u8 output[NOISE_TIMESTAMP_LEN]) ++{ ++ struct timespec64 now; ++ ++ ktime_get_real_ts64(&now); ++ ++ /* In order to prevent some sort of infoleak from precise timers, we ++ * round down the nanoseconds part to the closest rounded-down power of ++ * two to the maximum initiations per second allowed anyway by the ++ * implementation. ++ */ ++ now.tv_nsec = ALIGN_DOWN(now.tv_nsec, ++ rounddown_pow_of_two(NSEC_PER_SEC / INITIATIONS_PER_SECOND)); ++ ++ /* https://cr.yp.to/libtai/tai64.html */ ++ *(__be64 *)output = cpu_to_be64(0x400000000000000aULL + now.tv_sec); ++ *(__be32 *)(output + sizeof(__be64)) = cpu_to_be32(now.tv_nsec); ++} ++ ++bool ++wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst, ++ struct noise_handshake *handshake) ++{ ++ u8 timestamp[NOISE_TIMESTAMP_LEN]; ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ bool ret = false; ++ ++ /* We need to wait for crng _before_ taking any locks, since ++ * curve25519_generate_secret uses get_random_bytes_wait. ++ */ ++ wait_for_random_bytes(); ++ ++ down_read(&handshake->static_identity->lock); ++ down_write(&handshake->lock); ++ ++ if (unlikely(!handshake->static_identity->has_identity)) ++ goto out; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION); ++ ++ handshake_init(handshake->chaining_key, handshake->hash, ++ handshake->remote_static); ++ ++ /* e */ ++ curve25519_generate_secret(handshake->ephemeral_private); ++ if (!curve25519_generate_public(dst->unencrypted_ephemeral, ++ handshake->ephemeral_private)) ++ goto out; ++ message_ephemeral(dst->unencrypted_ephemeral, ++ dst->unencrypted_ephemeral, handshake->chaining_key, ++ handshake->hash); ++ ++ /* es */ ++ if (!mix_dh(handshake->chaining_key, key, handshake->ephemeral_private, ++ handshake->remote_static)) ++ goto out; ++ ++ /* s */ ++ message_encrypt(dst->encrypted_static, ++ handshake->static_identity->static_public, ++ NOISE_PUBLIC_KEY_LEN, key, handshake->hash); ++ ++ /* ss */ ++ kdf(handshake->chaining_key, key, NULL, ++ handshake->precomputed_static_static, NOISE_HASH_LEN, ++ NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, ++ handshake->chaining_key); ++ ++ /* {t} */ ++ tai64n_now(timestamp); ++ message_encrypt(dst->encrypted_timestamp, timestamp, ++ NOISE_TIMESTAMP_LEN, key, handshake->hash); ++ ++ dst->sender_index = wg_index_hashtable_insert( ++ handshake->entry.peer->device->index_hashtable, ++ &handshake->entry); ++ ++ handshake->state = HANDSHAKE_CREATED_INITIATION; ++ ret = true; ++ ++out: ++ up_write(&handshake->lock); ++ up_read(&handshake->static_identity->lock); ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ return ret; ++} ++ ++struct wg_peer * ++wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src, ++ struct wg_device *wg) ++{ ++ struct wg_peer *peer = NULL, *ret_peer = NULL; ++ struct noise_handshake *handshake; ++ bool replay_attack, flood_attack; ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 s[NOISE_PUBLIC_KEY_LEN]; ++ u8 e[NOISE_PUBLIC_KEY_LEN]; ++ u8 t[NOISE_TIMESTAMP_LEN]; ++ u64 initiation_consumption; ++ ++ down_read(&wg->static_identity.lock); ++ if (unlikely(!wg->static_identity.has_identity)) ++ goto out; ++ ++ handshake_init(chaining_key, hash, wg->static_identity.static_public); ++ ++ /* e */ ++ message_ephemeral(e, src->unencrypted_ephemeral, chaining_key, hash); ++ ++ /* es */ ++ if (!mix_dh(chaining_key, key, wg->static_identity.static_private, e)) ++ goto out; ++ ++ /* s */ ++ if (!message_decrypt(s, src->encrypted_static, ++ sizeof(src->encrypted_static), key, hash)) ++ goto out; ++ ++ /* Lookup which peer we're actually talking to */ ++ peer = wg_pubkey_hashtable_lookup(wg->peer_hashtable, s); ++ if (!peer) ++ goto out; ++ handshake = &peer->handshake; ++ ++ /* ss */ ++ kdf(chaining_key, key, NULL, handshake->precomputed_static_static, ++ NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, ++ chaining_key); ++ ++ /* {t} */ ++ if (!message_decrypt(t, src->encrypted_timestamp, ++ sizeof(src->encrypted_timestamp), key, hash)) ++ goto out; ++ ++ down_read(&handshake->lock); ++ replay_attack = memcmp(t, handshake->latest_timestamp, ++ NOISE_TIMESTAMP_LEN) <= 0; ++ flood_attack = (s64)handshake->last_initiation_consumption + ++ NSEC_PER_SEC / INITIATIONS_PER_SECOND > ++ (s64)ktime_get_coarse_boottime_ns(); ++ up_read(&handshake->lock); ++ if (replay_attack || flood_attack) ++ goto out; ++ ++ /* Success! Copy everything to peer */ ++ down_write(&handshake->lock); ++ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN); ++ if (memcmp(t, handshake->latest_timestamp, NOISE_TIMESTAMP_LEN) > 0) ++ memcpy(handshake->latest_timestamp, t, NOISE_TIMESTAMP_LEN); ++ memcpy(handshake->hash, hash, NOISE_HASH_LEN); ++ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN); ++ handshake->remote_index = src->sender_index; ++ if ((s64)(handshake->last_initiation_consumption - ++ (initiation_consumption = ktime_get_coarse_boottime_ns())) < 0) ++ handshake->last_initiation_consumption = initiation_consumption; ++ handshake->state = HANDSHAKE_CONSUMED_INITIATION; ++ up_write(&handshake->lock); ++ ret_peer = peer; ++ ++out: ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ memzero_explicit(hash, NOISE_HASH_LEN); ++ memzero_explicit(chaining_key, NOISE_HASH_LEN); ++ up_read(&wg->static_identity.lock); ++ if (!ret_peer) ++ wg_peer_put(peer); ++ return ret_peer; ++} ++ ++bool wg_noise_handshake_create_response(struct message_handshake_response *dst, ++ struct noise_handshake *handshake) ++{ ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ bool ret = false; ++ ++ /* We need to wait for crng _before_ taking any locks, since ++ * curve25519_generate_secret uses get_random_bytes_wait. ++ */ ++ wait_for_random_bytes(); ++ ++ down_read(&handshake->static_identity->lock); ++ down_write(&handshake->lock); ++ ++ if (handshake->state != HANDSHAKE_CONSUMED_INITIATION) ++ goto out; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE); ++ dst->receiver_index = handshake->remote_index; ++ ++ /* e */ ++ curve25519_generate_secret(handshake->ephemeral_private); ++ if (!curve25519_generate_public(dst->unencrypted_ephemeral, ++ handshake->ephemeral_private)) ++ goto out; ++ message_ephemeral(dst->unencrypted_ephemeral, ++ dst->unencrypted_ephemeral, handshake->chaining_key, ++ handshake->hash); ++ ++ /* ee */ ++ if (!mix_dh(handshake->chaining_key, NULL, handshake->ephemeral_private, ++ handshake->remote_ephemeral)) ++ goto out; ++ ++ /* se */ ++ if (!mix_dh(handshake->chaining_key, NULL, handshake->ephemeral_private, ++ handshake->remote_static)) ++ goto out; ++ ++ /* psk */ ++ mix_psk(handshake->chaining_key, handshake->hash, key, ++ handshake->preshared_key); ++ ++ /* {} */ ++ message_encrypt(dst->encrypted_nothing, NULL, 0, key, handshake->hash); ++ ++ dst->sender_index = wg_index_hashtable_insert( ++ handshake->entry.peer->device->index_hashtable, ++ &handshake->entry); ++ ++ handshake->state = HANDSHAKE_CREATED_RESPONSE; ++ ret = true; ++ ++out: ++ up_write(&handshake->lock); ++ up_read(&handshake->static_identity->lock); ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ return ret; ++} ++ ++struct wg_peer * ++wg_noise_handshake_consume_response(struct message_handshake_response *src, ++ struct wg_device *wg) ++{ ++ enum noise_handshake_state state = HANDSHAKE_ZEROED; ++ struct wg_peer *peer = NULL, *ret_peer = NULL; ++ struct noise_handshake *handshake; ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ u8 e[NOISE_PUBLIC_KEY_LEN]; ++ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; ++ u8 static_private[NOISE_PUBLIC_KEY_LEN]; ++ ++ down_read(&wg->static_identity.lock); ++ ++ if (unlikely(!wg->static_identity.has_identity)) ++ goto out; ++ ++ handshake = (struct noise_handshake *)wg_index_hashtable_lookup( ++ wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE, ++ src->receiver_index, &peer); ++ if (unlikely(!handshake)) ++ goto out; ++ ++ down_read(&handshake->lock); ++ state = handshake->state; ++ memcpy(hash, handshake->hash, NOISE_HASH_LEN); ++ memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN); ++ memcpy(ephemeral_private, handshake->ephemeral_private, ++ NOISE_PUBLIC_KEY_LEN); ++ up_read(&handshake->lock); ++ ++ if (state != HANDSHAKE_CREATED_INITIATION) ++ goto fail; ++ ++ /* e */ ++ message_ephemeral(e, src->unencrypted_ephemeral, chaining_key, hash); ++ ++ /* ee */ ++ if (!mix_dh(chaining_key, NULL, ephemeral_private, e)) ++ goto fail; ++ ++ /* se */ ++ if (!mix_dh(chaining_key, NULL, wg->static_identity.static_private, e)) ++ goto fail; ++ ++ /* psk */ ++ mix_psk(chaining_key, hash, key, handshake->preshared_key); ++ ++ /* {} */ ++ if (!message_decrypt(NULL, src->encrypted_nothing, ++ sizeof(src->encrypted_nothing), key, hash)) ++ goto fail; ++ ++ /* Success! Copy everything to peer */ ++ down_write(&handshake->lock); ++ /* It's important to check that the state is still the same, while we ++ * have an exclusive lock. ++ */ ++ if (handshake->state != state) { ++ up_write(&handshake->lock); ++ goto fail; ++ } ++ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN); ++ memcpy(handshake->hash, hash, NOISE_HASH_LEN); ++ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN); ++ handshake->remote_index = src->sender_index; ++ handshake->state = HANDSHAKE_CONSUMED_RESPONSE; ++ up_write(&handshake->lock); ++ ret_peer = peer; ++ goto out; ++ ++fail: ++ wg_peer_put(peer); ++out: ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ memzero_explicit(hash, NOISE_HASH_LEN); ++ memzero_explicit(chaining_key, NOISE_HASH_LEN); ++ memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN); ++ memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN); ++ up_read(&wg->static_identity.lock); ++ return ret_peer; ++} ++ ++bool wg_noise_handshake_begin_session(struct noise_handshake *handshake, ++ struct noise_keypairs *keypairs) ++{ ++ struct noise_keypair *new_keypair; ++ bool ret = false; ++ ++ down_write(&handshake->lock); ++ if (handshake->state != HANDSHAKE_CREATED_RESPONSE && ++ handshake->state != HANDSHAKE_CONSUMED_RESPONSE) ++ goto out; ++ ++ new_keypair = keypair_create(handshake->entry.peer); ++ if (!new_keypair) ++ goto out; ++ new_keypair->i_am_the_initiator = handshake->state == ++ HANDSHAKE_CONSUMED_RESPONSE; ++ new_keypair->remote_index = handshake->remote_index; ++ ++ if (new_keypair->i_am_the_initiator) ++ derive_keys(&new_keypair->sending, &new_keypair->receiving, ++ handshake->chaining_key); ++ else ++ derive_keys(&new_keypair->receiving, &new_keypair->sending, ++ handshake->chaining_key); ++ ++ handshake_zero(handshake); ++ rcu_read_lock_bh(); ++ if (likely(!READ_ONCE(container_of(handshake, struct wg_peer, ++ handshake)->is_dead))) { ++ add_new_keypair(keypairs, new_keypair); ++ net_dbg_ratelimited("%s: Keypair %llu created for peer %llu\n", ++ handshake->entry.peer->device->dev->name, ++ new_keypair->internal_id, ++ handshake->entry.peer->internal_id); ++ ret = wg_index_hashtable_replace( ++ handshake->entry.peer->device->index_hashtable, ++ &handshake->entry, &new_keypair->entry); ++ } else { ++ kzfree(new_keypair); ++ } ++ rcu_read_unlock_bh(); ++ ++out: ++ up_write(&handshake->lock); ++ return ret; ++} +--- /dev/null ++++ b/drivers/net/wireguard/noise.h +@@ -0,0 +1,137 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++#ifndef _WG_NOISE_H ++#define _WG_NOISE_H ++ ++#include "messages.h" ++#include "peerlookup.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++union noise_counter { ++ struct { ++ u64 counter; ++ unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG]; ++ spinlock_t lock; ++ } receive; ++ atomic64_t counter; ++}; ++ ++struct noise_symmetric_key { ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ union noise_counter counter; ++ u64 birthdate; ++ bool is_valid; ++}; ++ ++struct noise_keypair { ++ struct index_hashtable_entry entry; ++ struct noise_symmetric_key sending; ++ struct noise_symmetric_key receiving; ++ __le32 remote_index; ++ bool i_am_the_initiator; ++ struct kref refcount; ++ struct rcu_head rcu; ++ u64 internal_id; ++}; ++ ++struct noise_keypairs { ++ struct noise_keypair __rcu *current_keypair; ++ struct noise_keypair __rcu *previous_keypair; ++ struct noise_keypair __rcu *next_keypair; ++ spinlock_t keypair_update_lock; ++}; ++ ++struct noise_static_identity { ++ u8 static_public[NOISE_PUBLIC_KEY_LEN]; ++ u8 static_private[NOISE_PUBLIC_KEY_LEN]; ++ struct rw_semaphore lock; ++ bool has_identity; ++}; ++ ++enum noise_handshake_state { ++ HANDSHAKE_ZEROED, ++ HANDSHAKE_CREATED_INITIATION, ++ HANDSHAKE_CONSUMED_INITIATION, ++ HANDSHAKE_CREATED_RESPONSE, ++ HANDSHAKE_CONSUMED_RESPONSE ++}; ++ ++struct noise_handshake { ++ struct index_hashtable_entry entry; ++ ++ enum noise_handshake_state state; ++ u64 last_initiation_consumption; ++ ++ struct noise_static_identity *static_identity; ++ ++ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; ++ u8 remote_static[NOISE_PUBLIC_KEY_LEN]; ++ u8 remote_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ u8 precomputed_static_static[NOISE_PUBLIC_KEY_LEN]; ++ ++ u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]; ++ ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ ++ u8 latest_timestamp[NOISE_TIMESTAMP_LEN]; ++ __le32 remote_index; ++ ++ /* Protects all members except the immutable (after noise_handshake_ ++ * init): remote_static, precomputed_static_static, static_identity. ++ */ ++ struct rw_semaphore lock; ++}; ++ ++struct wg_device; ++ ++void wg_noise_init(void); ++bool wg_noise_handshake_init(struct noise_handshake *handshake, ++ struct noise_static_identity *static_identity, ++ const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], ++ const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN], ++ struct wg_peer *peer); ++void wg_noise_handshake_clear(struct noise_handshake *handshake); ++static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns) ++{ ++ atomic64_set(handshake_ns, ktime_get_coarse_boottime_ns() - ++ (u64)(REKEY_TIMEOUT + 1) * NSEC_PER_SEC); ++} ++ ++void wg_noise_keypair_put(struct noise_keypair *keypair, bool unreference_now); ++struct noise_keypair *wg_noise_keypair_get(struct noise_keypair *keypair); ++void wg_noise_keypairs_clear(struct noise_keypairs *keypairs); ++bool wg_noise_received_with_keypair(struct noise_keypairs *keypairs, ++ struct noise_keypair *received_keypair); ++void wg_noise_expire_current_peer_keypairs(struct wg_peer *peer); ++ ++void wg_noise_set_static_identity_private_key( ++ struct noise_static_identity *static_identity, ++ const u8 private_key[NOISE_PUBLIC_KEY_LEN]); ++bool wg_noise_precompute_static_static(struct wg_peer *peer); ++ ++bool ++wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst, ++ struct noise_handshake *handshake); ++struct wg_peer * ++wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src, ++ struct wg_device *wg); ++ ++bool wg_noise_handshake_create_response(struct message_handshake_response *dst, ++ struct noise_handshake *handshake); ++struct wg_peer * ++wg_noise_handshake_consume_response(struct message_handshake_response *src, ++ struct wg_device *wg); ++ ++bool wg_noise_handshake_begin_session(struct noise_handshake *handshake, ++ struct noise_keypairs *keypairs); ++ ++#endif /* _WG_NOISE_H */ +--- /dev/null ++++ b/drivers/net/wireguard/peer.c +@@ -0,0 +1,240 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "peer.h" ++#include "device.h" ++#include "queueing.h" ++#include "timers.h" ++#include "peerlookup.h" ++#include "noise.h" ++ ++#include ++#include ++#include ++#include ++ ++static atomic64_t peer_counter = ATOMIC64_INIT(0); ++ ++struct wg_peer *wg_peer_create(struct wg_device *wg, ++ const u8 public_key[NOISE_PUBLIC_KEY_LEN], ++ const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ struct wg_peer *peer; ++ int ret = -ENOMEM; ++ ++ lockdep_assert_held(&wg->device_update_lock); ++ ++ if (wg->num_peers >= MAX_PEERS_PER_DEVICE) ++ return ERR_PTR(ret); ++ ++ peer = kzalloc(sizeof(*peer), GFP_KERNEL); ++ if (unlikely(!peer)) ++ return ERR_PTR(ret); ++ peer->device = wg; ++ ++ if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity, ++ public_key, preshared_key, peer)) { ++ ret = -EKEYREJECTED; ++ goto err_1; ++ } ++ if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) ++ goto err_1; ++ if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false, ++ MAX_QUEUED_PACKETS)) ++ goto err_2; ++ if (wg_packet_queue_init(&peer->rx_queue, NULL, false, ++ MAX_QUEUED_PACKETS)) ++ goto err_3; ++ ++ peer->internal_id = atomic64_inc_return(&peer_counter); ++ peer->serial_work_cpu = nr_cpumask_bits; ++ wg_cookie_init(&peer->latest_cookie); ++ wg_timers_init(peer); ++ wg_cookie_checker_precompute_peer_keys(peer); ++ spin_lock_init(&peer->keypairs.keypair_update_lock); ++ INIT_WORK(&peer->transmit_handshake_work, ++ wg_packet_handshake_send_worker); ++ rwlock_init(&peer->endpoint_lock); ++ kref_init(&peer->refcount); ++ skb_queue_head_init(&peer->staged_packet_queue); ++ wg_noise_reset_last_sent_handshake(&peer->last_sent_handshake); ++ set_bit(NAPI_STATE_NO_BUSY_POLL, &peer->napi.state); ++ netif_napi_add(wg->dev, &peer->napi, wg_packet_rx_poll, ++ NAPI_POLL_WEIGHT); ++ napi_enable(&peer->napi); ++ list_add_tail(&peer->peer_list, &wg->peer_list); ++ INIT_LIST_HEAD(&peer->allowedips_list); ++ wg_pubkey_hashtable_add(wg->peer_hashtable, peer); ++ ++wg->num_peers; ++ pr_debug("%s: Peer %llu created\n", wg->dev->name, peer->internal_id); ++ return peer; ++ ++err_3: ++ wg_packet_queue_free(&peer->tx_queue, false); ++err_2: ++ dst_cache_destroy(&peer->endpoint_cache); ++err_1: ++ kfree(peer); ++ return ERR_PTR(ret); ++} ++ ++struct wg_peer *wg_peer_get_maybe_zero(struct wg_peer *peer) ++{ ++ RCU_LOCKDEP_WARN(!rcu_read_lock_bh_held(), ++ "Taking peer reference without holding the RCU read lock"); ++ if (unlikely(!peer || !kref_get_unless_zero(&peer->refcount))) ++ return NULL; ++ return peer; ++} ++ ++static void peer_make_dead(struct wg_peer *peer) ++{ ++ /* Remove from configuration-time lookup structures. */ ++ list_del_init(&peer->peer_list); ++ wg_allowedips_remove_by_peer(&peer->device->peer_allowedips, peer, ++ &peer->device->device_update_lock); ++ wg_pubkey_hashtable_remove(peer->device->peer_hashtable, peer); ++ ++ /* Mark as dead, so that we don't allow jumping contexts after. */ ++ WRITE_ONCE(peer->is_dead, true); ++ ++ /* The caller must now synchronize_rcu() for this to take effect. */ ++} ++ ++static void peer_remove_after_dead(struct wg_peer *peer) ++{ ++ WARN_ON(!peer->is_dead); ++ ++ /* No more keypairs can be created for this peer, since is_dead protects ++ * add_new_keypair, so we can now destroy existing ones. ++ */ ++ wg_noise_keypairs_clear(&peer->keypairs); ++ ++ /* Destroy all ongoing timers that were in-flight at the beginning of ++ * this function. ++ */ ++ wg_timers_stop(peer); ++ ++ /* The transition between packet encryption/decryption queues isn't ++ * guarded by is_dead, but each reference's life is strictly bounded by ++ * two generations: once for parallel crypto and once for serial ++ * ingestion, so we can simply flush twice, and be sure that we no ++ * longer have references inside these queues. ++ */ ++ ++ /* a) For encrypt/decrypt. */ ++ flush_workqueue(peer->device->packet_crypt_wq); ++ /* b.1) For send (but not receive, since that's napi). */ ++ flush_workqueue(peer->device->packet_crypt_wq); ++ /* b.2.1) For receive (but not send, since that's wq). */ ++ napi_disable(&peer->napi); ++ /* b.2.1) It's now safe to remove the napi struct, which must be done ++ * here from process context. ++ */ ++ netif_napi_del(&peer->napi); ++ ++ /* Ensure any workstructs we own (like transmit_handshake_work or ++ * clear_peer_work) no longer are in use. ++ */ ++ flush_workqueue(peer->device->handshake_send_wq); ++ ++ /* After the above flushes, a peer might still be active in a few ++ * different contexts: 1) from xmit(), before hitting is_dead and ++ * returning, 2) from wg_packet_consume_data(), before hitting is_dead ++ * and returning, 3) from wg_receive_handshake_packet() after a point ++ * where it has processed an incoming handshake packet, but where ++ * all calls to pass it off to timers fails because of is_dead. We won't ++ * have new references in (1) eventually, because we're removed from ++ * allowedips; we won't have new references in (2) eventually, because ++ * wg_index_hashtable_lookup will always return NULL, since we removed ++ * all existing keypairs and no more can be created; we won't have new ++ * references in (3) eventually, because we're removed from the pubkey ++ * hash table, which allows for a maximum of one handshake response, ++ * via the still-uncleared index hashtable entry, but not more than one, ++ * and in wg_cookie_message_consume, the lookup eventually gets a peer ++ * with a refcount of zero, so no new reference is taken. ++ */ ++ ++ --peer->device->num_peers; ++ wg_peer_put(peer); ++} ++ ++/* We have a separate "remove" function make sure that all active places where ++ * a peer is currently operating will eventually come to an end and not pass ++ * their reference onto another context. ++ */ ++void wg_peer_remove(struct wg_peer *peer) ++{ ++ if (unlikely(!peer)) ++ return; ++ lockdep_assert_held(&peer->device->device_update_lock); ++ ++ peer_make_dead(peer); ++ synchronize_rcu(); ++ peer_remove_after_dead(peer); ++} ++ ++void wg_peer_remove_all(struct wg_device *wg) ++{ ++ struct wg_peer *peer, *temp; ++ LIST_HEAD(dead_peers); ++ ++ lockdep_assert_held(&wg->device_update_lock); ++ ++ /* Avoid having to traverse individually for each one. */ ++ wg_allowedips_free(&wg->peer_allowedips, &wg->device_update_lock); ++ ++ list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) { ++ peer_make_dead(peer); ++ list_add_tail(&peer->peer_list, &dead_peers); ++ } ++ synchronize_rcu(); ++ list_for_each_entry_safe(peer, temp, &dead_peers, peer_list) ++ peer_remove_after_dead(peer); ++} ++ ++static void rcu_release(struct rcu_head *rcu) ++{ ++ struct wg_peer *peer = container_of(rcu, struct wg_peer, rcu); ++ ++ dst_cache_destroy(&peer->endpoint_cache); ++ wg_packet_queue_free(&peer->rx_queue, false); ++ wg_packet_queue_free(&peer->tx_queue, false); ++ ++ /* The final zeroing takes care of clearing any remaining handshake key ++ * material and other potentially sensitive information. ++ */ ++ kzfree(peer); ++} ++ ++static void kref_release(struct kref *refcount) ++{ ++ struct wg_peer *peer = container_of(refcount, struct wg_peer, refcount); ++ ++ pr_debug("%s: Peer %llu (%pISpfsc) destroyed\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ ++ /* Remove ourself from dynamic runtime lookup structures, now that the ++ * last reference is gone. ++ */ ++ wg_index_hashtable_remove(peer->device->index_hashtable, ++ &peer->handshake.entry); ++ ++ /* Remove any lingering packets that didn't have a chance to be ++ * transmitted. ++ */ ++ wg_packet_purge_staged_packets(peer); ++ ++ /* Free the memory used. */ ++ call_rcu(&peer->rcu, rcu_release); ++} ++ ++void wg_peer_put(struct wg_peer *peer) ++{ ++ if (unlikely(!peer)) ++ return; ++ kref_put(&peer->refcount, kref_release); ++} +--- /dev/null ++++ b/drivers/net/wireguard/peer.h +@@ -0,0 +1,83 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_PEER_H ++#define _WG_PEER_H ++ ++#include "device.h" ++#include "noise.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct wg_device; ++ ++struct endpoint { ++ union { ++ struct sockaddr addr; ++ struct sockaddr_in addr4; ++ struct sockaddr_in6 addr6; ++ }; ++ union { ++ struct { ++ struct in_addr src4; ++ /* Essentially the same as addr6->scope_id */ ++ int src_if4; ++ }; ++ struct in6_addr src6; ++ }; ++}; ++ ++struct wg_peer { ++ struct wg_device *device; ++ struct crypt_queue tx_queue, rx_queue; ++ struct sk_buff_head staged_packet_queue; ++ int serial_work_cpu; ++ struct noise_keypairs keypairs; ++ struct endpoint endpoint; ++ struct dst_cache endpoint_cache; ++ rwlock_t endpoint_lock; ++ struct noise_handshake handshake; ++ atomic64_t last_sent_handshake; ++ struct work_struct transmit_handshake_work, clear_peer_work; ++ struct cookie latest_cookie; ++ struct hlist_node pubkey_hash; ++ u64 rx_bytes, tx_bytes; ++ struct timer_list timer_retransmit_handshake, timer_send_keepalive; ++ struct timer_list timer_new_handshake, timer_zero_key_material; ++ struct timer_list timer_persistent_keepalive; ++ unsigned int timer_handshake_attempts; ++ u16 persistent_keepalive_interval; ++ bool timer_need_another_keepalive; ++ bool sent_lastminute_handshake; ++ struct timespec64 walltime_last_handshake; ++ struct kref refcount; ++ struct rcu_head rcu; ++ struct list_head peer_list; ++ struct list_head allowedips_list; ++ u64 internal_id; ++ struct napi_struct napi; ++ bool is_dead; ++}; ++ ++struct wg_peer *wg_peer_create(struct wg_device *wg, ++ const u8 public_key[NOISE_PUBLIC_KEY_LEN], ++ const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]); ++ ++struct wg_peer *__must_check wg_peer_get_maybe_zero(struct wg_peer *peer); ++static inline struct wg_peer *wg_peer_get(struct wg_peer *peer) ++{ ++ kref_get(&peer->refcount); ++ return peer; ++} ++void wg_peer_put(struct wg_peer *peer); ++void wg_peer_remove(struct wg_peer *peer); ++void wg_peer_remove_all(struct wg_device *wg); ++ ++#endif /* _WG_PEER_H */ +--- /dev/null ++++ b/drivers/net/wireguard/peerlookup.c +@@ -0,0 +1,221 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "peerlookup.h" ++#include "peer.h" ++#include "noise.h" ++ ++static struct hlist_head *pubkey_bucket(struct pubkey_hashtable *table, ++ const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) ++{ ++ /* siphash gives us a secure 64bit number based on a random key. Since ++ * the bits are uniformly distributed, we can then mask off to get the ++ * bits we need. ++ */ ++ const u64 hash = siphash(pubkey, NOISE_PUBLIC_KEY_LEN, &table->key); ++ ++ return &table->hashtable[hash & (HASH_SIZE(table->hashtable) - 1)]; ++} ++ ++struct pubkey_hashtable *wg_pubkey_hashtable_alloc(void) ++{ ++ struct pubkey_hashtable *table = kvmalloc(sizeof(*table), GFP_KERNEL); ++ ++ if (!table) ++ return NULL; ++ ++ get_random_bytes(&table->key, sizeof(table->key)); ++ hash_init(table->hashtable); ++ mutex_init(&table->lock); ++ return table; ++} ++ ++void wg_pubkey_hashtable_add(struct pubkey_hashtable *table, ++ struct wg_peer *peer) ++{ ++ mutex_lock(&table->lock); ++ hlist_add_head_rcu(&peer->pubkey_hash, ++ pubkey_bucket(table, peer->handshake.remote_static)); ++ mutex_unlock(&table->lock); ++} ++ ++void wg_pubkey_hashtable_remove(struct pubkey_hashtable *table, ++ struct wg_peer *peer) ++{ ++ mutex_lock(&table->lock); ++ hlist_del_init_rcu(&peer->pubkey_hash); ++ mutex_unlock(&table->lock); ++} ++ ++/* Returns a strong reference to a peer */ ++struct wg_peer * ++wg_pubkey_hashtable_lookup(struct pubkey_hashtable *table, ++ const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) ++{ ++ struct wg_peer *iter_peer, *peer = NULL; ++ ++ rcu_read_lock_bh(); ++ hlist_for_each_entry_rcu_bh(iter_peer, pubkey_bucket(table, pubkey), ++ pubkey_hash) { ++ if (!memcmp(pubkey, iter_peer->handshake.remote_static, ++ NOISE_PUBLIC_KEY_LEN)) { ++ peer = iter_peer; ++ break; ++ } ++ } ++ peer = wg_peer_get_maybe_zero(peer); ++ rcu_read_unlock_bh(); ++ return peer; ++} ++ ++static struct hlist_head *index_bucket(struct index_hashtable *table, ++ const __le32 index) ++{ ++ /* Since the indices are random and thus all bits are uniformly ++ * distributed, we can find its bucket simply by masking. ++ */ ++ return &table->hashtable[(__force u32)index & ++ (HASH_SIZE(table->hashtable) - 1)]; ++} ++ ++struct index_hashtable *wg_index_hashtable_alloc(void) ++{ ++ struct index_hashtable *table = kvmalloc(sizeof(*table), GFP_KERNEL); ++ ++ if (!table) ++ return NULL; ++ ++ hash_init(table->hashtable); ++ spin_lock_init(&table->lock); ++ return table; ++} ++ ++/* At the moment, we limit ourselves to 2^20 total peers, which generally might ++ * amount to 2^20*3 items in this hashtable. The algorithm below works by ++ * picking a random number and testing it. We can see that these limits mean we ++ * usually succeed pretty quickly: ++ * ++ * >>> def calculation(tries, size): ++ * ... return (size / 2**32)**(tries - 1) * (1 - (size / 2**32)) ++ * ... ++ * >>> calculation(1, 2**20 * 3) ++ * 0.999267578125 ++ * >>> calculation(2, 2**20 * 3) ++ * 0.0007318854331970215 ++ * >>> calculation(3, 2**20 * 3) ++ * 5.360489012673497e-07 ++ * >>> calculation(4, 2**20 * 3) ++ * 3.9261394135792216e-10 ++ * ++ * At the moment, we don't do any masking, so this algorithm isn't exactly ++ * constant time in either the random guessing or in the hash list lookup. We ++ * could require a minimum of 3 tries, which would successfully mask the ++ * guessing. this would not, however, help with the growing hash lengths, which ++ * is another thing to consider moving forward. ++ */ ++ ++__le32 wg_index_hashtable_insert(struct index_hashtable *table, ++ struct index_hashtable_entry *entry) ++{ ++ struct index_hashtable_entry *existing_entry; ++ ++ spin_lock_bh(&table->lock); ++ hlist_del_init_rcu(&entry->index_hash); ++ spin_unlock_bh(&table->lock); ++ ++ rcu_read_lock_bh(); ++ ++search_unused_slot: ++ /* First we try to find an unused slot, randomly, while unlocked. */ ++ entry->index = (__force __le32)get_random_u32(); ++ hlist_for_each_entry_rcu_bh(existing_entry, ++ index_bucket(table, entry->index), ++ index_hash) { ++ if (existing_entry->index == entry->index) ++ /* If it's already in use, we continue searching. */ ++ goto search_unused_slot; ++ } ++ ++ /* Once we've found an unused slot, we lock it, and then double-check ++ * that nobody else stole it from us. ++ */ ++ spin_lock_bh(&table->lock); ++ hlist_for_each_entry_rcu_bh(existing_entry, ++ index_bucket(table, entry->index), ++ index_hash) { ++ if (existing_entry->index == entry->index) { ++ spin_unlock_bh(&table->lock); ++ /* If it was stolen, we start over. */ ++ goto search_unused_slot; ++ } ++ } ++ /* Otherwise, we know we have it exclusively (since we're locked), ++ * so we insert. ++ */ ++ hlist_add_head_rcu(&entry->index_hash, ++ index_bucket(table, entry->index)); ++ spin_unlock_bh(&table->lock); ++ ++ rcu_read_unlock_bh(); ++ ++ return entry->index; ++} ++ ++bool wg_index_hashtable_replace(struct index_hashtable *table, ++ struct index_hashtable_entry *old, ++ struct index_hashtable_entry *new) ++{ ++ if (unlikely(hlist_unhashed(&old->index_hash))) ++ return false; ++ spin_lock_bh(&table->lock); ++ new->index = old->index; ++ hlist_replace_rcu(&old->index_hash, &new->index_hash); ++ ++ /* Calling init here NULLs out index_hash, and in fact after this ++ * function returns, it's theoretically possible for this to get ++ * reinserted elsewhere. That means the RCU lookup below might either ++ * terminate early or jump between buckets, in which case the packet ++ * simply gets dropped, which isn't terrible. ++ */ ++ INIT_HLIST_NODE(&old->index_hash); ++ spin_unlock_bh(&table->lock); ++ return true; ++} ++ ++void wg_index_hashtable_remove(struct index_hashtable *table, ++ struct index_hashtable_entry *entry) ++{ ++ spin_lock_bh(&table->lock); ++ hlist_del_init_rcu(&entry->index_hash); ++ spin_unlock_bh(&table->lock); ++} ++ ++/* Returns a strong reference to a entry->peer */ ++struct index_hashtable_entry * ++wg_index_hashtable_lookup(struct index_hashtable *table, ++ const enum index_hashtable_type type_mask, ++ const __le32 index, struct wg_peer **peer) ++{ ++ struct index_hashtable_entry *iter_entry, *entry = NULL; ++ ++ rcu_read_lock_bh(); ++ hlist_for_each_entry_rcu_bh(iter_entry, index_bucket(table, index), ++ index_hash) { ++ if (iter_entry->index == index) { ++ if (likely(iter_entry->type & type_mask)) ++ entry = iter_entry; ++ break; ++ } ++ } ++ if (likely(entry)) { ++ entry->peer = wg_peer_get_maybe_zero(entry->peer); ++ if (likely(entry->peer)) ++ *peer = entry->peer; ++ else ++ entry = NULL; ++ } ++ rcu_read_unlock_bh(); ++ return entry; ++} +--- /dev/null ++++ b/drivers/net/wireguard/peerlookup.h +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_PEERLOOKUP_H ++#define _WG_PEERLOOKUP_H ++ ++#include "messages.h" ++ ++#include ++#include ++#include ++ ++struct wg_peer; ++ ++struct pubkey_hashtable { ++ /* TODO: move to rhashtable */ ++ DECLARE_HASHTABLE(hashtable, 11); ++ siphash_key_t key; ++ struct mutex lock; ++}; ++ ++struct pubkey_hashtable *wg_pubkey_hashtable_alloc(void); ++void wg_pubkey_hashtable_add(struct pubkey_hashtable *table, ++ struct wg_peer *peer); ++void wg_pubkey_hashtable_remove(struct pubkey_hashtable *table, ++ struct wg_peer *peer); ++struct wg_peer * ++wg_pubkey_hashtable_lookup(struct pubkey_hashtable *table, ++ const u8 pubkey[NOISE_PUBLIC_KEY_LEN]); ++ ++struct index_hashtable { ++ /* TODO: move to rhashtable */ ++ DECLARE_HASHTABLE(hashtable, 13); ++ spinlock_t lock; ++}; ++ ++enum index_hashtable_type { ++ INDEX_HASHTABLE_HANDSHAKE = 1U << 0, ++ INDEX_HASHTABLE_KEYPAIR = 1U << 1 ++}; ++ ++struct index_hashtable_entry { ++ struct wg_peer *peer; ++ struct hlist_node index_hash; ++ enum index_hashtable_type type; ++ __le32 index; ++}; ++ ++struct index_hashtable *wg_index_hashtable_alloc(void); ++__le32 wg_index_hashtable_insert(struct index_hashtable *table, ++ struct index_hashtable_entry *entry); ++bool wg_index_hashtable_replace(struct index_hashtable *table, ++ struct index_hashtable_entry *old, ++ struct index_hashtable_entry *new); ++void wg_index_hashtable_remove(struct index_hashtable *table, ++ struct index_hashtable_entry *entry); ++struct index_hashtable_entry * ++wg_index_hashtable_lookup(struct index_hashtable *table, ++ const enum index_hashtable_type type_mask, ++ const __le32 index, struct wg_peer **peer); ++ ++#endif /* _WG_PEERLOOKUP_H */ +--- /dev/null ++++ b/drivers/net/wireguard/queueing.c +@@ -0,0 +1,53 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "queueing.h" ++ ++struct multicore_worker __percpu * ++wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr) ++{ ++ int cpu; ++ struct multicore_worker __percpu *worker = ++ alloc_percpu(struct multicore_worker); ++ ++ if (!worker) ++ return NULL; ++ ++ for_each_possible_cpu(cpu) { ++ per_cpu_ptr(worker, cpu)->ptr = ptr; ++ INIT_WORK(&per_cpu_ptr(worker, cpu)->work, function); ++ } ++ return worker; ++} ++ ++int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function, ++ bool multicore, unsigned int len) ++{ ++ int ret; ++ ++ memset(queue, 0, sizeof(*queue)); ++ ret = ptr_ring_init(&queue->ring, len, GFP_KERNEL); ++ if (ret) ++ return ret; ++ if (function) { ++ if (multicore) { ++ queue->worker = wg_packet_percpu_multicore_worker_alloc( ++ function, queue); ++ if (!queue->worker) ++ return -ENOMEM; ++ } else { ++ INIT_WORK(&queue->work, function); ++ } ++ } ++ return 0; ++} ++ ++void wg_packet_queue_free(struct crypt_queue *queue, bool multicore) ++{ ++ if (multicore) ++ free_percpu(queue->worker); ++ WARN_ON(!__ptr_ring_empty(&queue->ring)); ++ ptr_ring_cleanup(&queue->ring, NULL); ++} +--- /dev/null ++++ b/drivers/net/wireguard/queueing.h +@@ -0,0 +1,197 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_QUEUEING_H ++#define _WG_QUEUEING_H ++ ++#include "peer.h" ++#include ++#include ++#include ++#include ++ ++struct wg_device; ++struct wg_peer; ++struct multicore_worker; ++struct crypt_queue; ++struct sk_buff; ++ ++/* queueing.c APIs: */ ++int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function, ++ bool multicore, unsigned int len); ++void wg_packet_queue_free(struct crypt_queue *queue, bool multicore); ++struct multicore_worker __percpu * ++wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr); ++ ++/* receive.c APIs: */ ++void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb); ++void wg_packet_handshake_receive_worker(struct work_struct *work); ++/* NAPI poll function: */ ++int wg_packet_rx_poll(struct napi_struct *napi, int budget); ++/* Workqueue worker: */ ++void wg_packet_decrypt_worker(struct work_struct *work); ++ ++/* send.c APIs: */ ++void wg_packet_send_queued_handshake_initiation(struct wg_peer *peer, ++ bool is_retry); ++void wg_packet_send_handshake_response(struct wg_peer *peer); ++void wg_packet_send_handshake_cookie(struct wg_device *wg, ++ struct sk_buff *initiating_skb, ++ __le32 sender_index); ++void wg_packet_send_keepalive(struct wg_peer *peer); ++void wg_packet_purge_staged_packets(struct wg_peer *peer); ++void wg_packet_send_staged_packets(struct wg_peer *peer); ++/* Workqueue workers: */ ++void wg_packet_handshake_send_worker(struct work_struct *work); ++void wg_packet_tx_worker(struct work_struct *work); ++void wg_packet_encrypt_worker(struct work_struct *work); ++ ++enum packet_state { ++ PACKET_STATE_UNCRYPTED, ++ PACKET_STATE_CRYPTED, ++ PACKET_STATE_DEAD ++}; ++ ++struct packet_cb { ++ u64 nonce; ++ struct noise_keypair *keypair; ++ atomic_t state; ++ u32 mtu; ++ u8 ds; ++}; ++ ++#define PACKET_CB(skb) ((struct packet_cb *)((skb)->cb)) ++#define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer) ++ ++/* Returns either the correct skb->protocol value, or 0 if invalid. */ ++static inline __be16 wg_skb_examine_untrusted_ip_hdr(struct sk_buff *skb) ++{ ++ if (skb_network_header(skb) >= skb->head && ++ (skb_network_header(skb) + sizeof(struct iphdr)) <= ++ skb_tail_pointer(skb) && ++ ip_hdr(skb)->version == 4) ++ return htons(ETH_P_IP); ++ if (skb_network_header(skb) >= skb->head && ++ (skb_network_header(skb) + sizeof(struct ipv6hdr)) <= ++ skb_tail_pointer(skb) && ++ ipv6_hdr(skb)->version == 6) ++ return htons(ETH_P_IPV6); ++ return 0; ++} ++ ++static inline void wg_reset_packet(struct sk_buff *skb) ++{ ++ const int pfmemalloc = skb->pfmemalloc; ++ ++ skb_scrub_packet(skb, true); ++ memset(&skb->headers_start, 0, ++ offsetof(struct sk_buff, headers_end) - ++ offsetof(struct sk_buff, headers_start)); ++ skb->pfmemalloc = pfmemalloc; ++ skb->queue_mapping = 0; ++ skb->nohdr = 0; ++ skb->peeked = 0; ++ skb->mac_len = 0; ++ skb->dev = NULL; ++#ifdef CONFIG_NET_SCHED ++ skb->tc_index = 0; ++#endif ++ skb_reset_redirect(skb); ++ skb->hdr_len = skb_headroom(skb); ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ skb_reset_transport_header(skb); ++ skb_probe_transport_header(skb); ++ skb_reset_inner_headers(skb); ++} ++ ++static inline int wg_cpumask_choose_online(int *stored_cpu, unsigned int id) ++{ ++ unsigned int cpu = *stored_cpu, cpu_index, i; ++ ++ if (unlikely(cpu == nr_cpumask_bits || ++ !cpumask_test_cpu(cpu, cpu_online_mask))) { ++ cpu_index = id % cpumask_weight(cpu_online_mask); ++ cpu = cpumask_first(cpu_online_mask); ++ for (i = 0; i < cpu_index; ++i) ++ cpu = cpumask_next(cpu, cpu_online_mask); ++ *stored_cpu = cpu; ++ } ++ return cpu; ++} ++ ++/* This function is racy, in the sense that next is unlocked, so it could return ++ * the same CPU twice. A race-free version of this would be to instead store an ++ * atomic sequence number, do an increment-and-return, and then iterate through ++ * every possible CPU until we get to that index -- choose_cpu. However that's ++ * a bit slower, and it doesn't seem like this potential race actually ++ * introduces any performance loss, so we live with it. ++ */ ++static inline int wg_cpumask_next_online(int *next) ++{ ++ int cpu = *next; ++ ++ while (unlikely(!cpumask_test_cpu(cpu, cpu_online_mask))) ++ cpu = cpumask_next(cpu, cpu_online_mask) % nr_cpumask_bits; ++ *next = cpumask_next(cpu, cpu_online_mask) % nr_cpumask_bits; ++ return cpu; ++} ++ ++static inline int wg_queue_enqueue_per_device_and_peer( ++ struct crypt_queue *device_queue, struct crypt_queue *peer_queue, ++ struct sk_buff *skb, struct workqueue_struct *wq, int *next_cpu) ++{ ++ int cpu; ++ ++ atomic_set_release(&PACKET_CB(skb)->state, PACKET_STATE_UNCRYPTED); ++ /* We first queue this up for the peer ingestion, but the consumer ++ * will wait for the state to change to CRYPTED or DEAD before. ++ */ ++ if (unlikely(ptr_ring_produce_bh(&peer_queue->ring, skb))) ++ return -ENOSPC; ++ /* Then we queue it up in the device queue, which consumes the ++ * packet as soon as it can. ++ */ ++ cpu = wg_cpumask_next_online(next_cpu); ++ if (unlikely(ptr_ring_produce_bh(&device_queue->ring, skb))) ++ return -EPIPE; ++ queue_work_on(cpu, wq, &per_cpu_ptr(device_queue->worker, cpu)->work); ++ return 0; ++} ++ ++static inline void wg_queue_enqueue_per_peer(struct crypt_queue *queue, ++ struct sk_buff *skb, ++ enum packet_state state) ++{ ++ /* We take a reference, because as soon as we call atomic_set, the ++ * peer can be freed from below us. ++ */ ++ struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb)); ++ ++ atomic_set_release(&PACKET_CB(skb)->state, state); ++ queue_work_on(wg_cpumask_choose_online(&peer->serial_work_cpu, ++ peer->internal_id), ++ peer->device->packet_crypt_wq, &queue->work); ++ wg_peer_put(peer); ++} ++ ++static inline void wg_queue_enqueue_per_peer_napi(struct sk_buff *skb, ++ enum packet_state state) ++{ ++ /* We take a reference, because as soon as we call atomic_set, the ++ * peer can be freed from below us. ++ */ ++ struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb)); ++ ++ atomic_set_release(&PACKET_CB(skb)->state, state); ++ napi_schedule(&peer->napi); ++ wg_peer_put(peer); ++} ++ ++#ifdef DEBUG ++bool wg_packet_counter_selftest(void); ++#endif ++ ++#endif /* _WG_QUEUEING_H */ +--- /dev/null ++++ b/drivers/net/wireguard/ratelimiter.c +@@ -0,0 +1,223 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "ratelimiter.h" ++#include ++#include ++#include ++#include ++ ++static struct kmem_cache *entry_cache; ++static hsiphash_key_t key; ++static spinlock_t table_lock = __SPIN_LOCK_UNLOCKED("ratelimiter_table_lock"); ++static DEFINE_MUTEX(init_lock); ++static u64 init_refcnt; /* Protected by init_lock, hence not atomic. */ ++static atomic_t total_entries = ATOMIC_INIT(0); ++static unsigned int max_entries, table_size; ++static void wg_ratelimiter_gc_entries(struct work_struct *); ++static DECLARE_DEFERRABLE_WORK(gc_work, wg_ratelimiter_gc_entries); ++static struct hlist_head *table_v4; ++#if IS_ENABLED(CONFIG_IPV6) ++static struct hlist_head *table_v6; ++#endif ++ ++struct ratelimiter_entry { ++ u64 last_time_ns, tokens, ip; ++ void *net; ++ spinlock_t lock; ++ struct hlist_node hash; ++ struct rcu_head rcu; ++}; ++ ++enum { ++ PACKETS_PER_SECOND = 20, ++ PACKETS_BURSTABLE = 5, ++ PACKET_COST = NSEC_PER_SEC / PACKETS_PER_SECOND, ++ TOKEN_MAX = PACKET_COST * PACKETS_BURSTABLE ++}; ++ ++static void entry_free(struct rcu_head *rcu) ++{ ++ kmem_cache_free(entry_cache, ++ container_of(rcu, struct ratelimiter_entry, rcu)); ++ atomic_dec(&total_entries); ++} ++ ++static void entry_uninit(struct ratelimiter_entry *entry) ++{ ++ hlist_del_rcu(&entry->hash); ++ call_rcu(&entry->rcu, entry_free); ++} ++ ++/* Calling this function with a NULL work uninits all entries. */ ++static void wg_ratelimiter_gc_entries(struct work_struct *work) ++{ ++ const u64 now = ktime_get_coarse_boottime_ns(); ++ struct ratelimiter_entry *entry; ++ struct hlist_node *temp; ++ unsigned int i; ++ ++ for (i = 0; i < table_size; ++i) { ++ spin_lock(&table_lock); ++ hlist_for_each_entry_safe(entry, temp, &table_v4[i], hash) { ++ if (unlikely(!work) || ++ now - entry->last_time_ns > NSEC_PER_SEC) ++ entry_uninit(entry); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ hlist_for_each_entry_safe(entry, temp, &table_v6[i], hash) { ++ if (unlikely(!work) || ++ now - entry->last_time_ns > NSEC_PER_SEC) ++ entry_uninit(entry); ++ } ++#endif ++ spin_unlock(&table_lock); ++ if (likely(work)) ++ cond_resched(); ++ } ++ if (likely(work)) ++ queue_delayed_work(system_power_efficient_wq, &gc_work, HZ); ++} ++ ++bool wg_ratelimiter_allow(struct sk_buff *skb, struct net *net) ++{ ++ /* We only take the bottom half of the net pointer, so that we can hash ++ * 3 words in the end. This way, siphash's len param fits into the final ++ * u32, and we don't incur an extra round. ++ */ ++ const u32 net_word = (unsigned long)net; ++ struct ratelimiter_entry *entry; ++ struct hlist_head *bucket; ++ u64 ip; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { ++ ip = (u64 __force)ip_hdr(skb)->saddr; ++ bucket = &table_v4[hsiphash_2u32(net_word, ip, &key) & ++ (table_size - 1)]; ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (skb->protocol == htons(ETH_P_IPV6)) { ++ /* Only use 64 bits, so as to ratelimit the whole /64. */ ++ memcpy(&ip, &ipv6_hdr(skb)->saddr, sizeof(ip)); ++ bucket = &table_v6[hsiphash_3u32(net_word, ip >> 32, ip, &key) & ++ (table_size - 1)]; ++ } ++#endif ++ else ++ return false; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(entry, bucket, hash) { ++ if (entry->net == net && entry->ip == ip) { ++ u64 now, tokens; ++ bool ret; ++ /* Quasi-inspired by nft_limit.c, but this is actually a ++ * slightly different algorithm. Namely, we incorporate ++ * the burst as part of the maximum tokens, rather than ++ * as part of the rate. ++ */ ++ spin_lock(&entry->lock); ++ now = ktime_get_coarse_boottime_ns(); ++ tokens = min_t(u64, TOKEN_MAX, ++ entry->tokens + now - ++ entry->last_time_ns); ++ entry->last_time_ns = now; ++ ret = tokens >= PACKET_COST; ++ entry->tokens = ret ? tokens - PACKET_COST : tokens; ++ spin_unlock(&entry->lock); ++ rcu_read_unlock(); ++ return ret; ++ } ++ } ++ rcu_read_unlock(); ++ ++ if (atomic_inc_return(&total_entries) > max_entries) ++ goto err_oom; ++ ++ entry = kmem_cache_alloc(entry_cache, GFP_KERNEL); ++ if (unlikely(!entry)) ++ goto err_oom; ++ ++ entry->net = net; ++ entry->ip = ip; ++ INIT_HLIST_NODE(&entry->hash); ++ spin_lock_init(&entry->lock); ++ entry->last_time_ns = ktime_get_coarse_boottime_ns(); ++ entry->tokens = TOKEN_MAX - PACKET_COST; ++ spin_lock(&table_lock); ++ hlist_add_head_rcu(&entry->hash, bucket); ++ spin_unlock(&table_lock); ++ return true; ++ ++err_oom: ++ atomic_dec(&total_entries); ++ return false; ++} ++ ++int wg_ratelimiter_init(void) ++{ ++ mutex_lock(&init_lock); ++ if (++init_refcnt != 1) ++ goto out; ++ ++ entry_cache = KMEM_CACHE(ratelimiter_entry, 0); ++ if (!entry_cache) ++ goto err; ++ ++ /* xt_hashlimit.c uses a slightly different algorithm for ratelimiting, ++ * but what it shares in common is that it uses a massive hashtable. So, ++ * we borrow their wisdom about good table sizes on different systems ++ * dependent on RAM. This calculation here comes from there. ++ */ ++ table_size = (totalram_pages() > (1U << 30) / PAGE_SIZE) ? 8192 : ++ max_t(unsigned long, 16, roundup_pow_of_two( ++ (totalram_pages() << PAGE_SHIFT) / ++ (1U << 14) / sizeof(struct hlist_head))); ++ max_entries = table_size * 8; ++ ++ table_v4 = kvzalloc(table_size * sizeof(*table_v4), GFP_KERNEL); ++ if (unlikely(!table_v4)) ++ goto err_kmemcache; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ table_v6 = kvzalloc(table_size * sizeof(*table_v6), GFP_KERNEL); ++ if (unlikely(!table_v6)) { ++ kvfree(table_v4); ++ goto err_kmemcache; ++ } ++#endif ++ ++ queue_delayed_work(system_power_efficient_wq, &gc_work, HZ); ++ get_random_bytes(&key, sizeof(key)); ++out: ++ mutex_unlock(&init_lock); ++ return 0; ++ ++err_kmemcache: ++ kmem_cache_destroy(entry_cache); ++err: ++ --init_refcnt; ++ mutex_unlock(&init_lock); ++ return -ENOMEM; ++} ++ ++void wg_ratelimiter_uninit(void) ++{ ++ mutex_lock(&init_lock); ++ if (!init_refcnt || --init_refcnt) ++ goto out; ++ ++ cancel_delayed_work_sync(&gc_work); ++ wg_ratelimiter_gc_entries(NULL); ++ rcu_barrier(); ++ kvfree(table_v4); ++#if IS_ENABLED(CONFIG_IPV6) ++ kvfree(table_v6); ++#endif ++ kmem_cache_destroy(entry_cache); ++out: ++ mutex_unlock(&init_lock); ++} ++ ++#include "selftest/ratelimiter.c" +--- /dev/null ++++ b/drivers/net/wireguard/ratelimiter.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_RATELIMITER_H ++#define _WG_RATELIMITER_H ++ ++#include ++ ++int wg_ratelimiter_init(void); ++void wg_ratelimiter_uninit(void); ++bool wg_ratelimiter_allow(struct sk_buff *skb, struct net *net); ++ ++#ifdef DEBUG ++bool wg_ratelimiter_selftest(void); ++#endif ++ ++#endif /* _WG_RATELIMITER_H */ +--- /dev/null ++++ b/drivers/net/wireguard/receive.c +@@ -0,0 +1,595 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "queueing.h" ++#include "device.h" ++#include "peer.h" ++#include "timers.h" ++#include "messages.h" ++#include "cookie.h" ++#include "socket.h" ++ ++#include ++#include ++#include ++#include ++ ++/* Must be called with bh disabled. */ ++static void update_rx_stats(struct wg_peer *peer, size_t len) ++{ ++ struct pcpu_sw_netstats *tstats = ++ get_cpu_ptr(peer->device->dev->tstats); ++ ++ u64_stats_update_begin(&tstats->syncp); ++ ++tstats->rx_packets; ++ tstats->rx_bytes += len; ++ peer->rx_bytes += len; ++ u64_stats_update_end(&tstats->syncp); ++ put_cpu_ptr(tstats); ++} ++ ++#define SKB_TYPE_LE32(skb) (((struct message_header *)(skb)->data)->type) ++ ++static size_t validate_header_len(struct sk_buff *skb) ++{ ++ if (unlikely(skb->len < sizeof(struct message_header))) ++ return 0; ++ if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_DATA) && ++ skb->len >= MESSAGE_MINIMUM_LENGTH) ++ return sizeof(struct message_data); ++ if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION) && ++ skb->len == sizeof(struct message_handshake_initiation)) ++ return sizeof(struct message_handshake_initiation); ++ if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE) && ++ skb->len == sizeof(struct message_handshake_response)) ++ return sizeof(struct message_handshake_response); ++ if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE) && ++ skb->len == sizeof(struct message_handshake_cookie)) ++ return sizeof(struct message_handshake_cookie); ++ return 0; ++} ++ ++static int prepare_skb_header(struct sk_buff *skb, struct wg_device *wg) ++{ ++ size_t data_offset, data_len, header_len; ++ struct udphdr *udp; ++ ++ if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol || ++ skb_transport_header(skb) < skb->head || ++ (skb_transport_header(skb) + sizeof(struct udphdr)) > ++ skb_tail_pointer(skb))) ++ return -EINVAL; /* Bogus IP header */ ++ udp = udp_hdr(skb); ++ data_offset = (u8 *)udp - skb->data; ++ if (unlikely(data_offset > U16_MAX || ++ data_offset + sizeof(struct udphdr) > skb->len)) ++ /* Packet has offset at impossible location or isn't big enough ++ * to have UDP fields. ++ */ ++ return -EINVAL; ++ data_len = ntohs(udp->len); ++ if (unlikely(data_len < sizeof(struct udphdr) || ++ data_len > skb->len - data_offset)) ++ /* UDP packet is reporting too small of a size or lying about ++ * its size. ++ */ ++ return -EINVAL; ++ data_len -= sizeof(struct udphdr); ++ data_offset = (u8 *)udp + sizeof(struct udphdr) - skb->data; ++ if (unlikely(!pskb_may_pull(skb, ++ data_offset + sizeof(struct message_header)) || ++ pskb_trim(skb, data_len + data_offset) < 0)) ++ return -EINVAL; ++ skb_pull(skb, data_offset); ++ if (unlikely(skb->len != data_len)) ++ /* Final len does not agree with calculated len */ ++ return -EINVAL; ++ header_len = validate_header_len(skb); ++ if (unlikely(!header_len)) ++ return -EINVAL; ++ __skb_push(skb, data_offset); ++ if (unlikely(!pskb_may_pull(skb, data_offset + header_len))) ++ return -EINVAL; ++ __skb_pull(skb, data_offset); ++ return 0; ++} ++ ++static void wg_receive_handshake_packet(struct wg_device *wg, ++ struct sk_buff *skb) ++{ ++ enum cookie_mac_state mac_state; ++ struct wg_peer *peer = NULL; ++ /* This is global, so that our load calculation applies to the whole ++ * system. We don't care about races with it at all. ++ */ ++ static u64 last_under_load; ++ bool packet_needs_cookie; ++ bool under_load; ++ ++ if (SKB_TYPE_LE32(skb) == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE)) { ++ net_dbg_skb_ratelimited("%s: Receiving cookie response from %pISpfsc\n", ++ wg->dev->name, skb); ++ wg_cookie_message_consume( ++ (struct message_handshake_cookie *)skb->data, wg); ++ return; ++ } ++ ++ under_load = skb_queue_len(&wg->incoming_handshakes) >= ++ MAX_QUEUED_INCOMING_HANDSHAKES / 8; ++ if (under_load) ++ last_under_load = ktime_get_coarse_boottime_ns(); ++ else if (last_under_load) ++ under_load = !wg_birthdate_has_expired(last_under_load, 1); ++ mac_state = wg_cookie_validate_packet(&wg->cookie_checker, skb, ++ under_load); ++ if ((under_load && mac_state == VALID_MAC_WITH_COOKIE) || ++ (!under_load && mac_state == VALID_MAC_BUT_NO_COOKIE)) { ++ packet_needs_cookie = false; ++ } else if (under_load && mac_state == VALID_MAC_BUT_NO_COOKIE) { ++ packet_needs_cookie = true; ++ } else { ++ net_dbg_skb_ratelimited("%s: Invalid MAC of handshake, dropping packet from %pISpfsc\n", ++ wg->dev->name, skb); ++ return; ++ } ++ ++ switch (SKB_TYPE_LE32(skb)) { ++ case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION): { ++ struct message_handshake_initiation *message = ++ (struct message_handshake_initiation *)skb->data; ++ ++ if (packet_needs_cookie) { ++ wg_packet_send_handshake_cookie(wg, skb, ++ message->sender_index); ++ return; ++ } ++ peer = wg_noise_handshake_consume_initiation(message, wg); ++ if (unlikely(!peer)) { ++ net_dbg_skb_ratelimited("%s: Invalid handshake initiation from %pISpfsc\n", ++ wg->dev->name, skb); ++ return; ++ } ++ wg_socket_set_peer_endpoint_from_skb(peer, skb); ++ net_dbg_ratelimited("%s: Receiving handshake initiation from peer %llu (%pISpfsc)\n", ++ wg->dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ wg_packet_send_handshake_response(peer); ++ break; ++ } ++ case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE): { ++ struct message_handshake_response *message = ++ (struct message_handshake_response *)skb->data; ++ ++ if (packet_needs_cookie) { ++ wg_packet_send_handshake_cookie(wg, skb, ++ message->sender_index); ++ return; ++ } ++ peer = wg_noise_handshake_consume_response(message, wg); ++ if (unlikely(!peer)) { ++ net_dbg_skb_ratelimited("%s: Invalid handshake response from %pISpfsc\n", ++ wg->dev->name, skb); ++ return; ++ } ++ wg_socket_set_peer_endpoint_from_skb(peer, skb); ++ net_dbg_ratelimited("%s: Receiving handshake response from peer %llu (%pISpfsc)\n", ++ wg->dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ if (wg_noise_handshake_begin_session(&peer->handshake, ++ &peer->keypairs)) { ++ wg_timers_session_derived(peer); ++ wg_timers_handshake_complete(peer); ++ /* Calling this function will either send any existing ++ * packets in the queue and not send a keepalive, which ++ * is the best case, Or, if there's nothing in the ++ * queue, it will send a keepalive, in order to give ++ * immediate confirmation of the session. ++ */ ++ wg_packet_send_keepalive(peer); ++ } ++ break; ++ } ++ } ++ ++ if (unlikely(!peer)) { ++ WARN(1, "Somehow a wrong type of packet wound up in the handshake queue!\n"); ++ return; ++ } ++ ++ local_bh_disable(); ++ update_rx_stats(peer, skb->len); ++ local_bh_enable(); ++ ++ wg_timers_any_authenticated_packet_received(peer); ++ wg_timers_any_authenticated_packet_traversal(peer); ++ wg_peer_put(peer); ++} ++ ++void wg_packet_handshake_receive_worker(struct work_struct *work) ++{ ++ struct wg_device *wg = container_of(work, struct multicore_worker, ++ work)->ptr; ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(&wg->incoming_handshakes)) != NULL) { ++ wg_receive_handshake_packet(wg, skb); ++ dev_kfree_skb(skb); ++ cond_resched(); ++ } ++} ++ ++static void keep_key_fresh(struct wg_peer *peer) ++{ ++ struct noise_keypair *keypair; ++ bool send = false; ++ ++ if (peer->sent_lastminute_handshake) ++ return; ++ ++ rcu_read_lock_bh(); ++ keypair = rcu_dereference_bh(peer->keypairs.current_keypair); ++ if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) && ++ keypair->i_am_the_initiator && ++ unlikely(wg_birthdate_has_expired(keypair->sending.birthdate, ++ REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT))) ++ send = true; ++ rcu_read_unlock_bh(); ++ ++ if (send) { ++ peer->sent_lastminute_handshake = true; ++ wg_packet_send_queued_handshake_initiation(peer, false); ++ } ++} ++ ++static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key) ++{ ++ struct scatterlist sg[MAX_SKB_FRAGS + 8]; ++ struct sk_buff *trailer; ++ unsigned int offset; ++ int num_frags; ++ ++ if (unlikely(!key)) ++ return false; ++ ++ if (unlikely(!READ_ONCE(key->is_valid) || ++ wg_birthdate_has_expired(key->birthdate, REJECT_AFTER_TIME) || ++ key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) { ++ WRITE_ONCE(key->is_valid, false); ++ return false; ++ } ++ ++ PACKET_CB(skb)->nonce = ++ le64_to_cpu(((struct message_data *)skb->data)->counter); ++ ++ /* We ensure that the network header is part of the packet before we ++ * call skb_cow_data, so that there's no chance that data is removed ++ * from the skb, so that later we can extract the original endpoint. ++ */ ++ offset = skb->data - skb_network_header(skb); ++ skb_push(skb, offset); ++ num_frags = skb_cow_data(skb, 0, &trailer); ++ offset += sizeof(struct message_data); ++ skb_pull(skb, offset); ++ if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg))) ++ return false; ++ ++ sg_init_table(sg, num_frags); ++ if (skb_to_sgvec(skb, sg, 0, skb->len) <= 0) ++ return false; ++ ++ if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0, ++ PACKET_CB(skb)->nonce, ++ key->key)) ++ return false; ++ ++ /* Another ugly situation of pushing and pulling the header so as to ++ * keep endpoint information intact. ++ */ ++ skb_push(skb, offset); ++ if (pskb_trim(skb, skb->len - noise_encrypted_len(0))) ++ return false; ++ skb_pull(skb, offset); ++ ++ return true; ++} ++ ++/* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */ ++static bool counter_validate(union noise_counter *counter, u64 their_counter) ++{ ++ unsigned long index, index_current, top, i; ++ bool ret = false; ++ ++ spin_lock_bh(&counter->receive.lock); ++ ++ if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 || ++ their_counter >= REJECT_AFTER_MESSAGES)) ++ goto out; ++ ++ ++their_counter; ++ ++ if (unlikely((COUNTER_WINDOW_SIZE + their_counter) < ++ counter->receive.counter)) ++ goto out; ++ ++ index = their_counter >> ilog2(BITS_PER_LONG); ++ ++ if (likely(their_counter > counter->receive.counter)) { ++ index_current = counter->receive.counter >> ilog2(BITS_PER_LONG); ++ top = min_t(unsigned long, index - index_current, ++ COUNTER_BITS_TOTAL / BITS_PER_LONG); ++ for (i = 1; i <= top; ++i) ++ counter->receive.backtrack[(i + index_current) & ++ ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0; ++ counter->receive.counter = their_counter; ++ } ++ ++ index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1; ++ ret = !test_and_set_bit(their_counter & (BITS_PER_LONG - 1), ++ &counter->receive.backtrack[index]); ++ ++out: ++ spin_unlock_bh(&counter->receive.lock); ++ return ret; ++} ++ ++#include "selftest/counter.c" ++ ++static void wg_packet_consume_data_done(struct wg_peer *peer, ++ struct sk_buff *skb, ++ struct endpoint *endpoint) ++{ ++ struct net_device *dev = peer->device->dev; ++ unsigned int len, len_before_trim; ++ struct wg_peer *routed_peer; ++ ++ wg_socket_set_peer_endpoint(peer, endpoint); ++ ++ if (unlikely(wg_noise_received_with_keypair(&peer->keypairs, ++ PACKET_CB(skb)->keypair))) { ++ wg_timers_handshake_complete(peer); ++ wg_packet_send_staged_packets(peer); ++ } ++ ++ keep_key_fresh(peer); ++ ++ wg_timers_any_authenticated_packet_received(peer); ++ wg_timers_any_authenticated_packet_traversal(peer); ++ ++ /* A packet with length 0 is a keepalive packet */ ++ if (unlikely(!skb->len)) { ++ update_rx_stats(peer, message_data_len(0)); ++ net_dbg_ratelimited("%s: Receiving keepalive packet from peer %llu (%pISpfsc)\n", ++ dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ wg_timers_data_received(peer); ++ ++ if (unlikely(skb_network_header(skb) < skb->head)) ++ goto dishonest_packet_size; ++ if (unlikely(!(pskb_network_may_pull(skb, sizeof(struct iphdr)) && ++ (ip_hdr(skb)->version == 4 || ++ (ip_hdr(skb)->version == 6 && ++ pskb_network_may_pull(skb, sizeof(struct ipv6hdr))))))) ++ goto dishonest_packet_type; ++ ++ skb->dev = dev; ++ /* We've already verified the Poly1305 auth tag, which means this packet ++ * was not modified in transit. We can therefore tell the networking ++ * stack that all checksums of every layer of encapsulation have already ++ * been checked "by the hardware" and therefore is unneccessary to check ++ * again in software. ++ */ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ skb->csum_level = ~0; /* All levels */ ++ skb->protocol = wg_skb_examine_untrusted_ip_hdr(skb); ++ if (skb->protocol == htons(ETH_P_IP)) { ++ len = ntohs(ip_hdr(skb)->tot_len); ++ if (unlikely(len < sizeof(struct iphdr))) ++ goto dishonest_packet_size; ++ if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) ++ IP_ECN_set_ce(ip_hdr(skb)); ++ } else if (skb->protocol == htons(ETH_P_IPV6)) { ++ len = ntohs(ipv6_hdr(skb)->payload_len) + ++ sizeof(struct ipv6hdr); ++ if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) ++ IP6_ECN_set_ce(skb, ipv6_hdr(skb)); ++ } else { ++ goto dishonest_packet_type; ++ } ++ ++ if (unlikely(len > skb->len)) ++ goto dishonest_packet_size; ++ len_before_trim = skb->len; ++ if (unlikely(pskb_trim(skb, len))) ++ goto packet_processed; ++ ++ routed_peer = wg_allowedips_lookup_src(&peer->device->peer_allowedips, ++ skb); ++ wg_peer_put(routed_peer); /* We don't need the extra reference. */ ++ ++ if (unlikely(routed_peer != peer)) ++ goto dishonest_packet_peer; ++ ++ if (unlikely(napi_gro_receive(&peer->napi, skb) == GRO_DROP)) { ++ ++dev->stats.rx_dropped; ++ net_dbg_ratelimited("%s: Failed to give packet to userspace from peer %llu (%pISpfsc)\n", ++ dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ } else { ++ update_rx_stats(peer, message_data_len(len_before_trim)); ++ } ++ return; ++ ++dishonest_packet_peer: ++ net_dbg_skb_ratelimited("%s: Packet has unallowed src IP (%pISc) from peer %llu (%pISpfsc)\n", ++ dev->name, skb, peer->internal_id, ++ &peer->endpoint.addr); ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_frame_errors; ++ goto packet_processed; ++dishonest_packet_type: ++ net_dbg_ratelimited("%s: Packet is neither ipv4 nor ipv6 from peer %llu (%pISpfsc)\n", ++ dev->name, peer->internal_id, &peer->endpoint.addr); ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_frame_errors; ++ goto packet_processed; ++dishonest_packet_size: ++ net_dbg_ratelimited("%s: Packet has incorrect size from peer %llu (%pISpfsc)\n", ++ dev->name, peer->internal_id, &peer->endpoint.addr); ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_length_errors; ++ goto packet_processed; ++packet_processed: ++ dev_kfree_skb(skb); ++} ++ ++int wg_packet_rx_poll(struct napi_struct *napi, int budget) ++{ ++ struct wg_peer *peer = container_of(napi, struct wg_peer, napi); ++ struct crypt_queue *queue = &peer->rx_queue; ++ struct noise_keypair *keypair; ++ struct endpoint endpoint; ++ enum packet_state state; ++ struct sk_buff *skb; ++ int work_done = 0; ++ bool free; ++ ++ if (unlikely(budget <= 0)) ++ return 0; ++ ++ while ((skb = __ptr_ring_peek(&queue->ring)) != NULL && ++ (state = atomic_read_acquire(&PACKET_CB(skb)->state)) != ++ PACKET_STATE_UNCRYPTED) { ++ __ptr_ring_discard_one(&queue->ring); ++ peer = PACKET_PEER(skb); ++ keypair = PACKET_CB(skb)->keypair; ++ free = true; ++ ++ if (unlikely(state != PACKET_STATE_CRYPTED)) ++ goto next; ++ ++ if (unlikely(!counter_validate(&keypair->receiving.counter, ++ PACKET_CB(skb)->nonce))) { ++ net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n", ++ peer->device->dev->name, ++ PACKET_CB(skb)->nonce, ++ keypair->receiving.counter.receive.counter); ++ goto next; ++ } ++ ++ if (unlikely(wg_socket_endpoint_from_skb(&endpoint, skb))) ++ goto next; ++ ++ wg_reset_packet(skb); ++ wg_packet_consume_data_done(peer, skb, &endpoint); ++ free = false; ++ ++next: ++ wg_noise_keypair_put(keypair, false); ++ wg_peer_put(peer); ++ if (unlikely(free)) ++ dev_kfree_skb(skb); ++ ++ if (++work_done >= budget) ++ break; ++ } ++ ++ if (work_done < budget) ++ napi_complete_done(napi, work_done); ++ ++ return work_done; ++} ++ ++void wg_packet_decrypt_worker(struct work_struct *work) ++{ ++ struct crypt_queue *queue = container_of(work, struct multicore_worker, ++ work)->ptr; ++ struct sk_buff *skb; ++ ++ while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) { ++ enum packet_state state = likely(decrypt_packet(skb, ++ &PACKET_CB(skb)->keypair->receiving)) ? ++ PACKET_STATE_CRYPTED : PACKET_STATE_DEAD; ++ wg_queue_enqueue_per_peer_napi(skb, state); ++ } ++} ++ ++static void wg_packet_consume_data(struct wg_device *wg, struct sk_buff *skb) ++{ ++ __le32 idx = ((struct message_data *)skb->data)->key_idx; ++ struct wg_peer *peer = NULL; ++ int ret; ++ ++ rcu_read_lock_bh(); ++ PACKET_CB(skb)->keypair = ++ (struct noise_keypair *)wg_index_hashtable_lookup( ++ wg->index_hashtable, INDEX_HASHTABLE_KEYPAIR, idx, ++ &peer); ++ if (unlikely(!wg_noise_keypair_get(PACKET_CB(skb)->keypair))) ++ goto err_keypair; ++ ++ if (unlikely(READ_ONCE(peer->is_dead))) ++ goto err; ++ ++ ret = wg_queue_enqueue_per_device_and_peer(&wg->decrypt_queue, ++ &peer->rx_queue, skb, ++ wg->packet_crypt_wq, ++ &wg->decrypt_queue.last_cpu); ++ if (unlikely(ret == -EPIPE)) ++ wg_queue_enqueue_per_peer_napi(skb, PACKET_STATE_DEAD); ++ if (likely(!ret || ret == -EPIPE)) { ++ rcu_read_unlock_bh(); ++ return; ++ } ++err: ++ wg_noise_keypair_put(PACKET_CB(skb)->keypair, false); ++err_keypair: ++ rcu_read_unlock_bh(); ++ wg_peer_put(peer); ++ dev_kfree_skb(skb); ++} ++ ++void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb) ++{ ++ if (unlikely(prepare_skb_header(skb, wg) < 0)) ++ goto err; ++ switch (SKB_TYPE_LE32(skb)) { ++ case cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION): ++ case cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE): ++ case cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE): { ++ int cpu; ++ ++ if (skb_queue_len(&wg->incoming_handshakes) > ++ MAX_QUEUED_INCOMING_HANDSHAKES || ++ unlikely(!rng_is_initialized())) { ++ net_dbg_skb_ratelimited("%s: Dropping handshake packet from %pISpfsc\n", ++ wg->dev->name, skb); ++ goto err; ++ } ++ skb_queue_tail(&wg->incoming_handshakes, skb); ++ /* Queues up a call to packet_process_queued_handshake_ ++ * packets(skb): ++ */ ++ cpu = wg_cpumask_next_online(&wg->incoming_handshake_cpu); ++ queue_work_on(cpu, wg->handshake_receive_wq, ++ &per_cpu_ptr(wg->incoming_handshakes_worker, cpu)->work); ++ break; ++ } ++ case cpu_to_le32(MESSAGE_DATA): ++ PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb); ++ wg_packet_consume_data(wg, skb); ++ break; ++ default: ++ net_dbg_skb_ratelimited("%s: Invalid packet from %pISpfsc\n", ++ wg->dev->name, skb); ++ goto err; ++ } ++ return; ++ ++err: ++ dev_kfree_skb(skb); ++} +--- /dev/null ++++ b/drivers/net/wireguard/selftest/allowedips.c +@@ -0,0 +1,683 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This contains some basic static unit tests for the allowedips data structure. ++ * It also has two additional modes that are disabled and meant to be used by ++ * folks directly playing with this file. If you define the macro ++ * DEBUG_PRINT_TRIE_GRAPHVIZ to be 1, then every time there's a full tree in ++ * memory, it will be printed out as KERN_DEBUG in a format that can be passed ++ * to graphviz (the dot command) to visualize it. If you define the macro ++ * DEBUG_RANDOM_TRIE to be 1, then there will be an extremely costly set of ++ * randomized tests done against a trivial implementation, which may take ++ * upwards of a half-hour to complete. There's no set of users who should be ++ * enabling these, and the only developers that should go anywhere near these ++ * nobs are the ones who are reading this comment. ++ */ ++ ++#ifdef DEBUG ++ ++#include ++ ++static __init void swap_endian_and_apply_cidr(u8 *dst, const u8 *src, u8 bits, ++ u8 cidr) ++{ ++ swap_endian(dst, src, bits); ++ memset(dst + (cidr + 7) / 8, 0, bits / 8 - (cidr + 7) / 8); ++ if (cidr) ++ dst[(cidr + 7) / 8 - 1] &= ~0U << ((8 - (cidr % 8)) % 8); ++} ++ ++static __init void print_node(struct allowedips_node *node, u8 bits) ++{ ++ char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n"; ++ char *fmt_declaration = KERN_DEBUG ++ "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n"; ++ char *style = "dotted"; ++ u8 ip1[16], ip2[16]; ++ u32 color = 0; ++ ++ if (bits == 32) { ++ fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n"; ++ fmt_declaration = KERN_DEBUG ++ "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n"; ++ } else if (bits == 128) { ++ fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n"; ++ fmt_declaration = KERN_DEBUG ++ "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n"; ++ } ++ if (node->peer) { ++ hsiphash_key_t key = { { 0 } }; ++ ++ memcpy(&key, &node->peer, sizeof(node->peer)); ++ color = hsiphash_1u32(0xdeadbeef, &key) % 200 << 16 | ++ hsiphash_1u32(0xbabecafe, &key) % 200 << 8 | ++ hsiphash_1u32(0xabad1dea, &key) % 200; ++ style = "bold"; ++ } ++ swap_endian_and_apply_cidr(ip1, node->bits, bits, node->cidr); ++ printk(fmt_declaration, ip1, node->cidr, style, color); ++ if (node->bit[0]) { ++ swap_endian_and_apply_cidr(ip2, ++ rcu_dereference_raw(node->bit[0])->bits, bits, ++ node->cidr); ++ printk(fmt_connection, ip1, node->cidr, ip2, ++ rcu_dereference_raw(node->bit[0])->cidr); ++ print_node(rcu_dereference_raw(node->bit[0]), bits); ++ } ++ if (node->bit[1]) { ++ swap_endian_and_apply_cidr(ip2, ++ rcu_dereference_raw(node->bit[1])->bits, ++ bits, node->cidr); ++ printk(fmt_connection, ip1, node->cidr, ip2, ++ rcu_dereference_raw(node->bit[1])->cidr); ++ print_node(rcu_dereference_raw(node->bit[1]), bits); ++ } ++} ++ ++static __init void print_tree(struct allowedips_node __rcu *top, u8 bits) ++{ ++ printk(KERN_DEBUG "digraph trie {\n"); ++ print_node(rcu_dereference_raw(top), bits); ++ printk(KERN_DEBUG "}\n"); ++} ++ ++enum { ++ NUM_PEERS = 2000, ++ NUM_RAND_ROUTES = 400, ++ NUM_MUTATED_ROUTES = 100, ++ NUM_QUERIES = NUM_RAND_ROUTES * NUM_MUTATED_ROUTES * 30 ++}; ++ ++struct horrible_allowedips { ++ struct hlist_head head; ++}; ++ ++struct horrible_allowedips_node { ++ struct hlist_node table; ++ union nf_inet_addr ip; ++ union nf_inet_addr mask; ++ u8 ip_version; ++ void *value; ++}; ++ ++static __init void horrible_allowedips_init(struct horrible_allowedips *table) ++{ ++ INIT_HLIST_HEAD(&table->head); ++} ++ ++static __init void horrible_allowedips_free(struct horrible_allowedips *table) ++{ ++ struct horrible_allowedips_node *node; ++ struct hlist_node *h; ++ ++ hlist_for_each_entry_safe(node, h, &table->head, table) { ++ hlist_del(&node->table); ++ kfree(node); ++ } ++} ++ ++static __init inline union nf_inet_addr horrible_cidr_to_mask(u8 cidr) ++{ ++ union nf_inet_addr mask; ++ ++ memset(&mask, 0x00, 128 / 8); ++ memset(&mask, 0xff, cidr / 8); ++ if (cidr % 32) ++ mask.all[cidr / 32] = (__force u32)htonl( ++ (0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL); ++ return mask; ++} ++ ++static __init inline u8 horrible_mask_to_cidr(union nf_inet_addr subnet) ++{ ++ return hweight32(subnet.all[0]) + hweight32(subnet.all[1]) + ++ hweight32(subnet.all[2]) + hweight32(subnet.all[3]); ++} ++ ++static __init inline void ++horrible_mask_self(struct horrible_allowedips_node *node) ++{ ++ if (node->ip_version == 4) { ++ node->ip.ip &= node->mask.ip; ++ } else if (node->ip_version == 6) { ++ node->ip.ip6[0] &= node->mask.ip6[0]; ++ node->ip.ip6[1] &= node->mask.ip6[1]; ++ node->ip.ip6[2] &= node->mask.ip6[2]; ++ node->ip.ip6[3] &= node->mask.ip6[3]; ++ } ++} ++ ++static __init inline bool ++horrible_match_v4(const struct horrible_allowedips_node *node, ++ struct in_addr *ip) ++{ ++ return (ip->s_addr & node->mask.ip) == node->ip.ip; ++} ++ ++static __init inline bool ++horrible_match_v6(const struct horrible_allowedips_node *node, ++ struct in6_addr *ip) ++{ ++ return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == ++ node->ip.ip6[0] && ++ (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == ++ node->ip.ip6[1] && ++ (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == ++ node->ip.ip6[2] && ++ (ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3]; ++} ++ ++static __init void ++horrible_insert_ordered(struct horrible_allowedips *table, ++ struct horrible_allowedips_node *node) ++{ ++ struct horrible_allowedips_node *other = NULL, *where = NULL; ++ u8 my_cidr = horrible_mask_to_cidr(node->mask); ++ ++ hlist_for_each_entry(other, &table->head, table) { ++ if (!memcmp(&other->mask, &node->mask, ++ sizeof(union nf_inet_addr)) && ++ !memcmp(&other->ip, &node->ip, ++ sizeof(union nf_inet_addr)) && ++ other->ip_version == node->ip_version) { ++ other->value = node->value; ++ kfree(node); ++ return; ++ } ++ where = other; ++ if (horrible_mask_to_cidr(other->mask) <= my_cidr) ++ break; ++ } ++ if (!other && !where) ++ hlist_add_head(&node->table, &table->head); ++ else if (!other) ++ hlist_add_behind(&node->table, &where->table); ++ else ++ hlist_add_before(&node->table, &where->table); ++} ++ ++static __init int ++horrible_allowedips_insert_v4(struct horrible_allowedips *table, ++ struct in_addr *ip, u8 cidr, void *value) ++{ ++ struct horrible_allowedips_node *node = kzalloc(sizeof(*node), ++ GFP_KERNEL); ++ ++ if (unlikely(!node)) ++ return -ENOMEM; ++ node->ip.in = *ip; ++ node->mask = horrible_cidr_to_mask(cidr); ++ node->ip_version = 4; ++ node->value = value; ++ horrible_mask_self(node); ++ horrible_insert_ordered(table, node); ++ return 0; ++} ++ ++static __init int ++horrible_allowedips_insert_v6(struct horrible_allowedips *table, ++ struct in6_addr *ip, u8 cidr, void *value) ++{ ++ struct horrible_allowedips_node *node = kzalloc(sizeof(*node), ++ GFP_KERNEL); ++ ++ if (unlikely(!node)) ++ return -ENOMEM; ++ node->ip.in6 = *ip; ++ node->mask = horrible_cidr_to_mask(cidr); ++ node->ip_version = 6; ++ node->value = value; ++ horrible_mask_self(node); ++ horrible_insert_ordered(table, node); ++ return 0; ++} ++ ++static __init void * ++horrible_allowedips_lookup_v4(struct horrible_allowedips *table, ++ struct in_addr *ip) ++{ ++ struct horrible_allowedips_node *node; ++ void *ret = NULL; ++ ++ hlist_for_each_entry(node, &table->head, table) { ++ if (node->ip_version != 4) ++ continue; ++ if (horrible_match_v4(node, ip)) { ++ ret = node->value; ++ break; ++ } ++ } ++ return ret; ++} ++ ++static __init void * ++horrible_allowedips_lookup_v6(struct horrible_allowedips *table, ++ struct in6_addr *ip) ++{ ++ struct horrible_allowedips_node *node; ++ void *ret = NULL; ++ ++ hlist_for_each_entry(node, &table->head, table) { ++ if (node->ip_version != 6) ++ continue; ++ if (horrible_match_v6(node, ip)) { ++ ret = node->value; ++ break; ++ } ++ } ++ return ret; ++} ++ ++static __init bool randomized_test(void) ++{ ++ unsigned int i, j, k, mutate_amount, cidr; ++ u8 ip[16], mutate_mask[16], mutated[16]; ++ struct wg_peer **peers, *peer; ++ struct horrible_allowedips h; ++ DEFINE_MUTEX(mutex); ++ struct allowedips t; ++ bool ret = false; ++ ++ mutex_init(&mutex); ++ ++ wg_allowedips_init(&t); ++ horrible_allowedips_init(&h); ++ ++ peers = kcalloc(NUM_PEERS, sizeof(*peers), GFP_KERNEL); ++ if (unlikely(!peers)) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free; ++ } ++ for (i = 0; i < NUM_PEERS; ++i) { ++ peers[i] = kzalloc(sizeof(*peers[i]), GFP_KERNEL); ++ if (unlikely(!peers[i])) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free; ++ } ++ kref_init(&peers[i]->refcount); ++ } ++ ++ mutex_lock(&mutex); ++ ++ for (i = 0; i < NUM_RAND_ROUTES; ++i) { ++ prandom_bytes(ip, 4); ++ cidr = prandom_u32_max(32) + 1; ++ peer = peers[prandom_u32_max(NUM_PEERS)]; ++ if (wg_allowedips_insert_v4(&t, (struct in_addr *)ip, cidr, ++ peer, &mutex) < 0) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free_locked; ++ } ++ if (horrible_allowedips_insert_v4(&h, (struct in_addr *)ip, ++ cidr, peer) < 0) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free_locked; ++ } ++ for (j = 0; j < NUM_MUTATED_ROUTES; ++j) { ++ memcpy(mutated, ip, 4); ++ prandom_bytes(mutate_mask, 4); ++ mutate_amount = prandom_u32_max(32); ++ for (k = 0; k < mutate_amount / 8; ++k) ++ mutate_mask[k] = 0xff; ++ mutate_mask[k] = 0xff ++ << ((8 - (mutate_amount % 8)) % 8); ++ for (; k < 4; ++k) ++ mutate_mask[k] = 0; ++ for (k = 0; k < 4; ++k) ++ mutated[k] = (mutated[k] & mutate_mask[k]) | ++ (~mutate_mask[k] & ++ prandom_u32_max(256)); ++ cidr = prandom_u32_max(32) + 1; ++ peer = peers[prandom_u32_max(NUM_PEERS)]; ++ if (wg_allowedips_insert_v4(&t, ++ (struct in_addr *)mutated, ++ cidr, peer, &mutex) < 0) { ++ pr_err("allowedips random malloc: FAIL\n"); ++ goto free_locked; ++ } ++ if (horrible_allowedips_insert_v4(&h, ++ (struct in_addr *)mutated, cidr, peer)) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free_locked; ++ } ++ } ++ } ++ ++ for (i = 0; i < NUM_RAND_ROUTES; ++i) { ++ prandom_bytes(ip, 16); ++ cidr = prandom_u32_max(128) + 1; ++ peer = peers[prandom_u32_max(NUM_PEERS)]; ++ if (wg_allowedips_insert_v6(&t, (struct in6_addr *)ip, cidr, ++ peer, &mutex) < 0) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free_locked; ++ } ++ if (horrible_allowedips_insert_v6(&h, (struct in6_addr *)ip, ++ cidr, peer) < 0) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free_locked; ++ } ++ for (j = 0; j < NUM_MUTATED_ROUTES; ++j) { ++ memcpy(mutated, ip, 16); ++ prandom_bytes(mutate_mask, 16); ++ mutate_amount = prandom_u32_max(128); ++ for (k = 0; k < mutate_amount / 8; ++k) ++ mutate_mask[k] = 0xff; ++ mutate_mask[k] = 0xff ++ << ((8 - (mutate_amount % 8)) % 8); ++ for (; k < 4; ++k) ++ mutate_mask[k] = 0; ++ for (k = 0; k < 4; ++k) ++ mutated[k] = (mutated[k] & mutate_mask[k]) | ++ (~mutate_mask[k] & ++ prandom_u32_max(256)); ++ cidr = prandom_u32_max(128) + 1; ++ peer = peers[prandom_u32_max(NUM_PEERS)]; ++ if (wg_allowedips_insert_v6(&t, ++ (struct in6_addr *)mutated, ++ cidr, peer, &mutex) < 0) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free_locked; ++ } ++ if (horrible_allowedips_insert_v6( ++ &h, (struct in6_addr *)mutated, cidr, ++ peer)) { ++ pr_err("allowedips random self-test malloc: FAIL\n"); ++ goto free_locked; ++ } ++ } ++ } ++ ++ mutex_unlock(&mutex); ++ ++ if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) { ++ print_tree(t.root4, 32); ++ print_tree(t.root6, 128); ++ } ++ ++ for (i = 0; i < NUM_QUERIES; ++i) { ++ prandom_bytes(ip, 4); ++ if (lookup(t.root4, 32, ip) != ++ horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) { ++ pr_err("allowedips random self-test: FAIL\n"); ++ goto free; ++ } ++ } ++ ++ for (i = 0; i < NUM_QUERIES; ++i) { ++ prandom_bytes(ip, 16); ++ if (lookup(t.root6, 128, ip) != ++ horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) { ++ pr_err("allowedips random self-test: FAIL\n"); ++ goto free; ++ } ++ } ++ ret = true; ++ ++free: ++ mutex_lock(&mutex); ++free_locked: ++ wg_allowedips_free(&t, &mutex); ++ mutex_unlock(&mutex); ++ horrible_allowedips_free(&h); ++ if (peers) { ++ for (i = 0; i < NUM_PEERS; ++i) ++ kfree(peers[i]); ++ } ++ kfree(peers); ++ return ret; ++} ++ ++static __init inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d) ++{ ++ static struct in_addr ip; ++ u8 *split = (u8 *)&ip; ++ ++ split[0] = a; ++ split[1] = b; ++ split[2] = c; ++ split[3] = d; ++ return &ip; ++} ++ ++static __init inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d) ++{ ++ static struct in6_addr ip; ++ __be32 *split = (__be32 *)&ip; ++ ++ split[0] = cpu_to_be32(a); ++ split[1] = cpu_to_be32(b); ++ split[2] = cpu_to_be32(c); ++ split[3] = cpu_to_be32(d); ++ return &ip; ++} ++ ++static __init struct wg_peer *init_peer(void) ++{ ++ struct wg_peer *peer = kzalloc(sizeof(*peer), GFP_KERNEL); ++ ++ if (!peer) ++ return NULL; ++ kref_init(&peer->refcount); ++ INIT_LIST_HEAD(&peer->allowedips_list); ++ return peer; ++} ++ ++#define insert(version, mem, ipa, ipb, ipc, ipd, cidr) \ ++ wg_allowedips_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), \ ++ cidr, mem, &mutex) ++ ++#define maybe_fail() do { \ ++ ++i; \ ++ if (!_s) { \ ++ pr_info("allowedips self-test %zu: FAIL\n", i); \ ++ success = false; \ ++ } \ ++ } while (0) ++ ++#define test(version, mem, ipa, ipb, ipc, ipd) do { \ ++ bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \ ++ ip##version(ipa, ipb, ipc, ipd)) == (mem); \ ++ maybe_fail(); \ ++ } while (0) ++ ++#define test_negative(version, mem, ipa, ipb, ipc, ipd) do { \ ++ bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \ ++ ip##version(ipa, ipb, ipc, ipd)) != (mem); \ ++ maybe_fail(); \ ++ } while (0) ++ ++#define test_boolean(cond) do { \ ++ bool _s = (cond); \ ++ maybe_fail(); \ ++ } while (0) ++ ++bool __init wg_allowedips_selftest(void) ++{ ++ bool found_a = false, found_b = false, found_c = false, found_d = false, ++ found_e = false, found_other = false; ++ struct wg_peer *a = init_peer(), *b = init_peer(), *c = init_peer(), ++ *d = init_peer(), *e = init_peer(), *f = init_peer(), ++ *g = init_peer(), *h = init_peer(); ++ struct allowedips_node *iter_node; ++ bool success = false; ++ struct allowedips t; ++ DEFINE_MUTEX(mutex); ++ struct in6_addr ip; ++ size_t i = 0, count = 0; ++ __be64 part; ++ ++ mutex_init(&mutex); ++ mutex_lock(&mutex); ++ wg_allowedips_init(&t); ++ ++ if (!a || !b || !c || !d || !e || !f || !g || !h) { ++ pr_err("allowedips self-test malloc: FAIL\n"); ++ goto free; ++ } ++ ++ insert(4, a, 192, 168, 4, 0, 24); ++ insert(4, b, 192, 168, 4, 4, 32); ++ insert(4, c, 192, 168, 0, 0, 16); ++ insert(4, d, 192, 95, 5, 64, 27); ++ /* replaces previous entry, and maskself is required */ ++ insert(4, c, 192, 95, 5, 65, 27); ++ insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128); ++ insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64); ++ insert(4, e, 0, 0, 0, 0, 0); ++ insert(6, e, 0, 0, 0, 0, 0); ++ /* replaces previous entry */ ++ insert(6, f, 0, 0, 0, 0, 0); ++ insert(6, g, 0x24046800, 0, 0, 0, 32); ++ /* maskself is required */ ++ insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64); ++ insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128); ++ insert(6, c, 0x24446800, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128); ++ insert(6, b, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98); ++ insert(4, g, 64, 15, 112, 0, 20); ++ /* maskself is required */ ++ insert(4, h, 64, 15, 123, 211, 25); ++ insert(4, a, 10, 0, 0, 0, 25); ++ insert(4, b, 10, 0, 0, 128, 25); ++ insert(4, a, 10, 1, 0, 0, 30); ++ insert(4, b, 10, 1, 0, 4, 30); ++ insert(4, c, 10, 1, 0, 8, 29); ++ insert(4, d, 10, 1, 0, 16, 29); ++ ++ if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) { ++ print_tree(t.root4, 32); ++ print_tree(t.root6, 128); ++ } ++ ++ success = true; ++ ++ test(4, a, 192, 168, 4, 20); ++ test(4, a, 192, 168, 4, 0); ++ test(4, b, 192, 168, 4, 4); ++ test(4, c, 192, 168, 200, 182); ++ test(4, c, 192, 95, 5, 68); ++ test(4, e, 192, 95, 5, 96); ++ test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543); ++ test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee); ++ test(6, f, 0x26075300, 0x60006b01, 0, 0); ++ test(6, g, 0x24046800, 0x40040806, 0, 0x1006); ++ test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678); ++ test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678); ++ test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678); ++ test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678); ++ test(6, h, 0x24046800, 0x40040800, 0, 0); ++ test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010); ++ test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef); ++ test(4, g, 64, 15, 116, 26); ++ test(4, g, 64, 15, 127, 3); ++ test(4, g, 64, 15, 123, 1); ++ test(4, h, 64, 15, 123, 128); ++ test(4, h, 64, 15, 123, 129); ++ test(4, a, 10, 0, 0, 52); ++ test(4, b, 10, 0, 0, 220); ++ test(4, a, 10, 1, 0, 2); ++ test(4, b, 10, 1, 0, 6); ++ test(4, c, 10, 1, 0, 10); ++ test(4, d, 10, 1, 0, 20); ++ ++ insert(4, a, 1, 0, 0, 0, 32); ++ insert(4, a, 64, 0, 0, 0, 32); ++ insert(4, a, 128, 0, 0, 0, 32); ++ insert(4, a, 192, 0, 0, 0, 32); ++ insert(4, a, 255, 0, 0, 0, 32); ++ wg_allowedips_remove_by_peer(&t, a, &mutex); ++ test_negative(4, a, 1, 0, 0, 0); ++ test_negative(4, a, 64, 0, 0, 0); ++ test_negative(4, a, 128, 0, 0, 0); ++ test_negative(4, a, 192, 0, 0, 0); ++ test_negative(4, a, 255, 0, 0, 0); ++ ++ wg_allowedips_free(&t, &mutex); ++ wg_allowedips_init(&t); ++ insert(4, a, 192, 168, 0, 0, 16); ++ insert(4, a, 192, 168, 0, 0, 24); ++ wg_allowedips_remove_by_peer(&t, a, &mutex); ++ test_negative(4, a, 192, 168, 0, 1); ++ ++ /* These will hit the WARN_ON(len >= 128) in free_node if something ++ * goes wrong. ++ */ ++ for (i = 0; i < 128; ++i) { ++ part = cpu_to_be64(~(1LLU << (i % 64))); ++ memset(&ip, 0xff, 16); ++ memcpy((u8 *)&ip + (i < 64) * 8, &part, 8); ++ wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex); ++ } ++ ++ wg_allowedips_free(&t, &mutex); ++ ++ wg_allowedips_init(&t); ++ insert(4, a, 192, 95, 5, 93, 27); ++ insert(6, a, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128); ++ insert(4, a, 10, 1, 0, 20, 29); ++ insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 83); ++ insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 21); ++ list_for_each_entry(iter_node, &a->allowedips_list, peer_list) { ++ u8 cidr, ip[16] __aligned(__alignof(u64)); ++ int family = wg_allowedips_read_node(iter_node, ip, &cidr); ++ ++ count++; ++ ++ if (cidr == 27 && family == AF_INET && ++ !memcmp(ip, ip4(192, 95, 5, 64), sizeof(struct in_addr))) ++ found_a = true; ++ else if (cidr == 128 && family == AF_INET6 && ++ !memcmp(ip, ip6(0x26075300, 0x60006b00, 0, 0xc05f0543), ++ sizeof(struct in6_addr))) ++ found_b = true; ++ else if (cidr == 29 && family == AF_INET && ++ !memcmp(ip, ip4(10, 1, 0, 16), sizeof(struct in_addr))) ++ found_c = true; ++ else if (cidr == 83 && family == AF_INET6 && ++ !memcmp(ip, ip6(0x26075300, 0x6d8a6bf8, 0xdab1e000, 0), ++ sizeof(struct in6_addr))) ++ found_d = true; ++ else if (cidr == 21 && family == AF_INET6 && ++ !memcmp(ip, ip6(0x26075000, 0, 0, 0), ++ sizeof(struct in6_addr))) ++ found_e = true; ++ else ++ found_other = true; ++ } ++ test_boolean(count == 5); ++ test_boolean(found_a); ++ test_boolean(found_b); ++ test_boolean(found_c); ++ test_boolean(found_d); ++ test_boolean(found_e); ++ test_boolean(!found_other); ++ ++ if (IS_ENABLED(DEBUG_RANDOM_TRIE) && success) ++ success = randomized_test(); ++ ++ if (success) ++ pr_info("allowedips self-tests: pass\n"); ++ ++free: ++ wg_allowedips_free(&t, &mutex); ++ kfree(a); ++ kfree(b); ++ kfree(c); ++ kfree(d); ++ kfree(e); ++ kfree(f); ++ kfree(g); ++ kfree(h); ++ mutex_unlock(&mutex); ++ ++ return success; ++} ++ ++#undef test_negative ++#undef test ++#undef remove ++#undef insert ++#undef init_peer ++ ++#endif +--- /dev/null ++++ b/drivers/net/wireguard/selftest/counter.c +@@ -0,0 +1,104 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifdef DEBUG ++bool __init wg_packet_counter_selftest(void) ++{ ++ unsigned int test_num = 0, i; ++ union noise_counter counter; ++ bool success = true; ++ ++#define T_INIT do { \ ++ memset(&counter, 0, sizeof(union noise_counter)); \ ++ spin_lock_init(&counter.receive.lock); \ ++ } while (0) ++#define T_LIM (COUNTER_WINDOW_SIZE + 1) ++#define T(n, v) do { \ ++ ++test_num; \ ++ if (counter_validate(&counter, n) != (v)) { \ ++ pr_err("nonce counter self-test %u: FAIL\n", \ ++ test_num); \ ++ success = false; \ ++ } \ ++ } while (0) ++ ++ T_INIT; ++ /* 1 */ T(0, true); ++ /* 2 */ T(1, true); ++ /* 3 */ T(1, false); ++ /* 4 */ T(9, true); ++ /* 5 */ T(8, true); ++ /* 6 */ T(7, true); ++ /* 7 */ T(7, false); ++ /* 8 */ T(T_LIM, true); ++ /* 9 */ T(T_LIM - 1, true); ++ /* 10 */ T(T_LIM - 1, false); ++ /* 11 */ T(T_LIM - 2, true); ++ /* 12 */ T(2, true); ++ /* 13 */ T(2, false); ++ /* 14 */ T(T_LIM + 16, true); ++ /* 15 */ T(3, false); ++ /* 16 */ T(T_LIM + 16, false); ++ /* 17 */ T(T_LIM * 4, true); ++ /* 18 */ T(T_LIM * 4 - (T_LIM - 1), true); ++ /* 19 */ T(10, false); ++ /* 20 */ T(T_LIM * 4 - T_LIM, false); ++ /* 21 */ T(T_LIM * 4 - (T_LIM + 1), false); ++ /* 22 */ T(T_LIM * 4 - (T_LIM - 2), true); ++ /* 23 */ T(T_LIM * 4 + 1 - T_LIM, false); ++ /* 24 */ T(0, false); ++ /* 25 */ T(REJECT_AFTER_MESSAGES, false); ++ /* 26 */ T(REJECT_AFTER_MESSAGES - 1, true); ++ /* 27 */ T(REJECT_AFTER_MESSAGES, false); ++ /* 28 */ T(REJECT_AFTER_MESSAGES - 1, false); ++ /* 29 */ T(REJECT_AFTER_MESSAGES - 2, true); ++ /* 30 */ T(REJECT_AFTER_MESSAGES + 1, false); ++ /* 31 */ T(REJECT_AFTER_MESSAGES + 2, false); ++ /* 32 */ T(REJECT_AFTER_MESSAGES - 2, false); ++ /* 33 */ T(REJECT_AFTER_MESSAGES - 3, true); ++ /* 34 */ T(0, false); ++ ++ T_INIT; ++ for (i = 1; i <= COUNTER_WINDOW_SIZE; ++i) ++ T(i, true); ++ T(0, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = 2; i <= COUNTER_WINDOW_SIZE + 1; ++i) ++ T(i, true); ++ T(1, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 0;) ++ T(i, true); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 2; i-- > 1;) ++ T(i, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;) ++ T(i, true); ++ T(COUNTER_WINDOW_SIZE + 1, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;) ++ T(i, true); ++ T(0, true); ++ T(COUNTER_WINDOW_SIZE + 1, true); ++ ++#undef T ++#undef T_LIM ++#undef T_INIT ++ ++ if (success) ++ pr_info("nonce counter self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null ++++ b/drivers/net/wireguard/selftest/ratelimiter.c +@@ -0,0 +1,226 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifdef DEBUG ++ ++#include ++ ++static const struct { ++ bool result; ++ unsigned int msec_to_sleep_before; ++} expected_results[] __initconst = { ++ [0 ... PACKETS_BURSTABLE - 1] = { true, 0 }, ++ [PACKETS_BURSTABLE] = { false, 0 }, ++ [PACKETS_BURSTABLE + 1] = { true, MSEC_PER_SEC / PACKETS_PER_SECOND }, ++ [PACKETS_BURSTABLE + 2] = { false, 0 }, ++ [PACKETS_BURSTABLE + 3] = { true, (MSEC_PER_SEC / PACKETS_PER_SECOND) * 2 }, ++ [PACKETS_BURSTABLE + 4] = { true, 0 }, ++ [PACKETS_BURSTABLE + 5] = { false, 0 } ++}; ++ ++static __init unsigned int maximum_jiffies_at_index(int index) ++{ ++ unsigned int total_msecs = 2 * MSEC_PER_SEC / PACKETS_PER_SECOND / 3; ++ int i; ++ ++ for (i = 0; i <= index; ++i) ++ total_msecs += expected_results[i].msec_to_sleep_before; ++ return msecs_to_jiffies(total_msecs); ++} ++ ++static __init int timings_test(struct sk_buff *skb4, struct iphdr *hdr4, ++ struct sk_buff *skb6, struct ipv6hdr *hdr6, ++ int *test) ++{ ++ unsigned long loop_start_time; ++ int i; ++ ++ wg_ratelimiter_gc_entries(NULL); ++ rcu_barrier(); ++ loop_start_time = jiffies; ++ ++ for (i = 0; i < ARRAY_SIZE(expected_results); ++i) { ++ if (expected_results[i].msec_to_sleep_before) ++ msleep(expected_results[i].msec_to_sleep_before); ++ ++ if (time_is_before_jiffies(loop_start_time + ++ maximum_jiffies_at_index(i))) ++ return -ETIMEDOUT; ++ if (wg_ratelimiter_allow(skb4, &init_net) != ++ expected_results[i].result) ++ return -EXFULL; ++ ++(*test); ++ ++ hdr4->saddr = htonl(ntohl(hdr4->saddr) + i + 1); ++ if (time_is_before_jiffies(loop_start_time + ++ maximum_jiffies_at_index(i))) ++ return -ETIMEDOUT; ++ if (!wg_ratelimiter_allow(skb4, &init_net)) ++ return -EXFULL; ++ ++(*test); ++ ++ hdr4->saddr = htonl(ntohl(hdr4->saddr) - i - 1); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ hdr6->saddr.in6_u.u6_addr32[2] = htonl(i); ++ hdr6->saddr.in6_u.u6_addr32[3] = htonl(i); ++ if (time_is_before_jiffies(loop_start_time + ++ maximum_jiffies_at_index(i))) ++ return -ETIMEDOUT; ++ if (wg_ratelimiter_allow(skb6, &init_net) != ++ expected_results[i].result) ++ return -EXFULL; ++ ++(*test); ++ ++ hdr6->saddr.in6_u.u6_addr32[0] = ++ htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) + i + 1); ++ if (time_is_before_jiffies(loop_start_time + ++ maximum_jiffies_at_index(i))) ++ return -ETIMEDOUT; ++ if (!wg_ratelimiter_allow(skb6, &init_net)) ++ return -EXFULL; ++ ++(*test); ++ ++ hdr6->saddr.in6_u.u6_addr32[0] = ++ htonl(ntohl(hdr6->saddr.in6_u.u6_addr32[0]) - i - 1); ++ ++ if (time_is_before_jiffies(loop_start_time + ++ maximum_jiffies_at_index(i))) ++ return -ETIMEDOUT; ++#endif ++ } ++ return 0; ++} ++ ++static __init int capacity_test(struct sk_buff *skb4, struct iphdr *hdr4, ++ int *test) ++{ ++ int i; ++ ++ wg_ratelimiter_gc_entries(NULL); ++ rcu_barrier(); ++ ++ if (atomic_read(&total_entries)) ++ return -EXFULL; ++ ++(*test); ++ ++ for (i = 0; i <= max_entries; ++i) { ++ hdr4->saddr = htonl(i); ++ if (wg_ratelimiter_allow(skb4, &init_net) != (i != max_entries)) ++ return -EXFULL; ++ ++(*test); ++ } ++ return 0; ++} ++ ++bool __init wg_ratelimiter_selftest(void) ++{ ++ enum { TRIALS_BEFORE_GIVING_UP = 5000 }; ++ bool success = false; ++ int test = 0, trials; ++ struct sk_buff *skb4, *skb6; ++ struct iphdr *hdr4; ++ struct ipv6hdr *hdr6; ++ ++ if (IS_ENABLED(CONFIG_KASAN) || IS_ENABLED(CONFIG_UBSAN)) ++ return true; ++ ++ BUILD_BUG_ON(MSEC_PER_SEC % PACKETS_PER_SECOND != 0); ++ ++ if (wg_ratelimiter_init()) ++ goto out; ++ ++test; ++ if (wg_ratelimiter_init()) { ++ wg_ratelimiter_uninit(); ++ goto out; ++ } ++ ++test; ++ if (wg_ratelimiter_init()) { ++ wg_ratelimiter_uninit(); ++ wg_ratelimiter_uninit(); ++ goto out; ++ } ++ ++test; ++ ++ skb4 = alloc_skb(sizeof(struct iphdr), GFP_KERNEL); ++ if (unlikely(!skb4)) ++ goto err_nofree; ++ skb4->protocol = htons(ETH_P_IP); ++ hdr4 = (struct iphdr *)skb_put(skb4, sizeof(*hdr4)); ++ hdr4->saddr = htonl(8182); ++ skb_reset_network_header(skb4); ++ ++test; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ skb6 = alloc_skb(sizeof(struct ipv6hdr), GFP_KERNEL); ++ if (unlikely(!skb6)) { ++ kfree_skb(skb4); ++ goto err_nofree; ++ } ++ skb6->protocol = htons(ETH_P_IPV6); ++ hdr6 = (struct ipv6hdr *)skb_put(skb6, sizeof(*hdr6)); ++ hdr6->saddr.in6_u.u6_addr32[0] = htonl(1212); ++ hdr6->saddr.in6_u.u6_addr32[1] = htonl(289188); ++ skb_reset_network_header(skb6); ++ ++test; ++#endif ++ ++ for (trials = TRIALS_BEFORE_GIVING_UP;;) { ++ int test_count = 0, ret; ++ ++ ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count); ++ if (ret == -ETIMEDOUT) { ++ if (!trials--) { ++ test += test_count; ++ goto err; ++ } ++ msleep(500); ++ continue; ++ } else if (ret < 0) { ++ test += test_count; ++ goto err; ++ } else { ++ test += test_count; ++ break; ++ } ++ } ++ ++ for (trials = TRIALS_BEFORE_GIVING_UP;;) { ++ int test_count = 0; ++ ++ if (capacity_test(skb4, hdr4, &test_count) < 0) { ++ if (!trials--) { ++ test += test_count; ++ goto err; ++ } ++ msleep(50); ++ continue; ++ } ++ test += test_count; ++ break; ++ } ++ ++ success = true; ++ ++err: ++ kfree_skb(skb4); ++#if IS_ENABLED(CONFIG_IPV6) ++ kfree_skb(skb6); ++#endif ++err_nofree: ++ wg_ratelimiter_uninit(); ++ wg_ratelimiter_uninit(); ++ wg_ratelimiter_uninit(); ++ /* Uninit one extra time to check underflow detection. */ ++ wg_ratelimiter_uninit(); ++out: ++ if (success) ++ pr_info("ratelimiter self-tests: pass\n"); ++ else ++ pr_err("ratelimiter self-test %d: FAIL\n", test); ++ ++ return success; ++} ++#endif +--- /dev/null ++++ b/drivers/net/wireguard/send.c +@@ -0,0 +1,413 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "queueing.h" ++#include "timers.h" ++#include "device.h" ++#include "peer.h" ++#include "socket.h" ++#include "messages.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void wg_packet_send_handshake_initiation(struct wg_peer *peer) ++{ ++ struct message_handshake_initiation packet; ++ ++ if (!wg_birthdate_has_expired(atomic64_read(&peer->last_sent_handshake), ++ REKEY_TIMEOUT)) ++ return; /* This function is rate limited. */ ++ ++ atomic64_set(&peer->last_sent_handshake, ktime_get_coarse_boottime_ns()); ++ net_dbg_ratelimited("%s: Sending handshake initiation to peer %llu (%pISpfsc)\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ ++ if (wg_noise_handshake_create_initiation(&packet, &peer->handshake)) { ++ wg_cookie_add_mac_to_packet(&packet, sizeof(packet), peer); ++ wg_timers_any_authenticated_packet_traversal(peer); ++ wg_timers_any_authenticated_packet_sent(peer); ++ atomic64_set(&peer->last_sent_handshake, ++ ktime_get_coarse_boottime_ns()); ++ wg_socket_send_buffer_to_peer(peer, &packet, sizeof(packet), ++ HANDSHAKE_DSCP); ++ wg_timers_handshake_initiated(peer); ++ } ++} ++ ++void wg_packet_handshake_send_worker(struct work_struct *work) ++{ ++ struct wg_peer *peer = container_of(work, struct wg_peer, ++ transmit_handshake_work); ++ ++ wg_packet_send_handshake_initiation(peer); ++ wg_peer_put(peer); ++} ++ ++void wg_packet_send_queued_handshake_initiation(struct wg_peer *peer, ++ bool is_retry) ++{ ++ if (!is_retry) ++ peer->timer_handshake_attempts = 0; ++ ++ rcu_read_lock_bh(); ++ /* We check last_sent_handshake here in addition to the actual function ++ * we're queueing up, so that we don't queue things if not strictly ++ * necessary: ++ */ ++ if (!wg_birthdate_has_expired(atomic64_read(&peer->last_sent_handshake), ++ REKEY_TIMEOUT) || ++ unlikely(READ_ONCE(peer->is_dead))) ++ goto out; ++ ++ wg_peer_get(peer); ++ /* Queues up calling packet_send_queued_handshakes(peer), where we do a ++ * peer_put(peer) after: ++ */ ++ if (!queue_work(peer->device->handshake_send_wq, ++ &peer->transmit_handshake_work)) ++ /* If the work was already queued, we want to drop the ++ * extra reference: ++ */ ++ wg_peer_put(peer); ++out: ++ rcu_read_unlock_bh(); ++} ++ ++void wg_packet_send_handshake_response(struct wg_peer *peer) ++{ ++ struct message_handshake_response packet; ++ ++ atomic64_set(&peer->last_sent_handshake, ktime_get_coarse_boottime_ns()); ++ net_dbg_ratelimited("%s: Sending handshake response to peer %llu (%pISpfsc)\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ ++ if (wg_noise_handshake_create_response(&packet, &peer->handshake)) { ++ wg_cookie_add_mac_to_packet(&packet, sizeof(packet), peer); ++ if (wg_noise_handshake_begin_session(&peer->handshake, ++ &peer->keypairs)) { ++ wg_timers_session_derived(peer); ++ wg_timers_any_authenticated_packet_traversal(peer); ++ wg_timers_any_authenticated_packet_sent(peer); ++ atomic64_set(&peer->last_sent_handshake, ++ ktime_get_coarse_boottime_ns()); ++ wg_socket_send_buffer_to_peer(peer, &packet, ++ sizeof(packet), ++ HANDSHAKE_DSCP); ++ } ++ } ++} ++ ++void wg_packet_send_handshake_cookie(struct wg_device *wg, ++ struct sk_buff *initiating_skb, ++ __le32 sender_index) ++{ ++ struct message_handshake_cookie packet; ++ ++ net_dbg_skb_ratelimited("%s: Sending cookie response for denied handshake message for %pISpfsc\n", ++ wg->dev->name, initiating_skb); ++ wg_cookie_message_create(&packet, initiating_skb, sender_index, ++ &wg->cookie_checker); ++ wg_socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet, ++ sizeof(packet)); ++} ++ ++static void keep_key_fresh(struct wg_peer *peer) ++{ ++ struct noise_keypair *keypair; ++ bool send = false; ++ ++ rcu_read_lock_bh(); ++ keypair = rcu_dereference_bh(peer->keypairs.current_keypair); ++ if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) && ++ (unlikely(atomic64_read(&keypair->sending.counter.counter) > ++ REKEY_AFTER_MESSAGES) || ++ (keypair->i_am_the_initiator && ++ unlikely(wg_birthdate_has_expired(keypair->sending.birthdate, ++ REKEY_AFTER_TIME))))) ++ send = true; ++ rcu_read_unlock_bh(); ++ ++ if (send) ++ wg_packet_send_queued_handshake_initiation(peer, false); ++} ++ ++static unsigned int calculate_skb_padding(struct sk_buff *skb) ++{ ++ /* We do this modulo business with the MTU, just in case the networking ++ * layer gives us a packet that's bigger than the MTU. In that case, we ++ * wouldn't want the final subtraction to overflow in the case of the ++ * padded_size being clamped. ++ */ ++ unsigned int last_unit = skb->len % PACKET_CB(skb)->mtu; ++ unsigned int padded_size = ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE); ++ ++ if (padded_size > PACKET_CB(skb)->mtu) ++ padded_size = PACKET_CB(skb)->mtu; ++ return padded_size - last_unit; ++} ++ ++static bool encrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) ++{ ++ unsigned int padding_len, plaintext_len, trailer_len; ++ struct scatterlist sg[MAX_SKB_FRAGS + 8]; ++ struct message_data *header; ++ struct sk_buff *trailer; ++ int num_frags; ++ ++ /* Calculate lengths. */ ++ padding_len = calculate_skb_padding(skb); ++ trailer_len = padding_len + noise_encrypted_len(0); ++ plaintext_len = skb->len + padding_len; ++ ++ /* Expand data section to have room for padding and auth tag. */ ++ num_frags = skb_cow_data(skb, trailer_len, &trailer); ++ if (unlikely(num_frags < 0 || num_frags > ARRAY_SIZE(sg))) ++ return false; ++ ++ /* Set the padding to zeros, and make sure it and the auth tag are part ++ * of the skb. ++ */ ++ memset(skb_tail_pointer(trailer), 0, padding_len); ++ ++ /* Expand head section to have room for our header and the network ++ * stack's headers. ++ */ ++ if (unlikely(skb_cow_head(skb, DATA_PACKET_HEAD_ROOM) < 0)) ++ return false; ++ ++ /* Finalize checksum calculation for the inner packet, if required. */ ++ if (unlikely(skb->ip_summed == CHECKSUM_PARTIAL && ++ skb_checksum_help(skb))) ++ return false; ++ ++ /* Only after checksumming can we safely add on the padding at the end ++ * and the header. ++ */ ++ skb_set_inner_network_header(skb, 0); ++ header = (struct message_data *)skb_push(skb, sizeof(*header)); ++ header->header.type = cpu_to_le32(MESSAGE_DATA); ++ header->key_idx = keypair->remote_index; ++ header->counter = cpu_to_le64(PACKET_CB(skb)->nonce); ++ pskb_put(skb, trailer, trailer_len); ++ ++ /* Now we can encrypt the scattergather segments */ ++ sg_init_table(sg, num_frags); ++ if (skb_to_sgvec(skb, sg, sizeof(struct message_data), ++ noise_encrypted_len(plaintext_len)) <= 0) ++ return false; ++ return chacha20poly1305_encrypt_sg_inplace(sg, plaintext_len, NULL, 0, ++ PACKET_CB(skb)->nonce, ++ keypair->sending.key); ++} ++ ++void wg_packet_send_keepalive(struct wg_peer *peer) ++{ ++ struct sk_buff *skb; ++ ++ if (skb_queue_empty(&peer->staged_packet_queue)) { ++ skb = alloc_skb(DATA_PACKET_HEAD_ROOM + MESSAGE_MINIMUM_LENGTH, ++ GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return; ++ skb_reserve(skb, DATA_PACKET_HEAD_ROOM); ++ skb->dev = peer->device->dev; ++ PACKET_CB(skb)->mtu = skb->dev->mtu; ++ skb_queue_tail(&peer->staged_packet_queue, skb); ++ net_dbg_ratelimited("%s: Sending keepalive packet to peer %llu (%pISpfsc)\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr); ++ } ++ ++ wg_packet_send_staged_packets(peer); ++} ++ ++static void wg_packet_create_data_done(struct sk_buff *first, ++ struct wg_peer *peer) ++{ ++ struct sk_buff *skb, *next; ++ bool is_keepalive, data_sent = false; ++ ++ wg_timers_any_authenticated_packet_traversal(peer); ++ wg_timers_any_authenticated_packet_sent(peer); ++ skb_list_walk_safe(first, skb, next) { ++ is_keepalive = skb->len == message_data_len(0); ++ if (likely(!wg_socket_send_skb_to_peer(peer, skb, ++ PACKET_CB(skb)->ds) && !is_keepalive)) ++ data_sent = true; ++ } ++ ++ if (likely(data_sent)) ++ wg_timers_data_sent(peer); ++ ++ keep_key_fresh(peer); ++} ++ ++void wg_packet_tx_worker(struct work_struct *work) ++{ ++ struct crypt_queue *queue = container_of(work, struct crypt_queue, ++ work); ++ struct noise_keypair *keypair; ++ enum packet_state state; ++ struct sk_buff *first; ++ struct wg_peer *peer; ++ ++ while ((first = __ptr_ring_peek(&queue->ring)) != NULL && ++ (state = atomic_read_acquire(&PACKET_CB(first)->state)) != ++ PACKET_STATE_UNCRYPTED) { ++ __ptr_ring_discard_one(&queue->ring); ++ peer = PACKET_PEER(first); ++ keypair = PACKET_CB(first)->keypair; ++ ++ if (likely(state == PACKET_STATE_CRYPTED)) ++ wg_packet_create_data_done(first, peer); ++ else ++ kfree_skb_list(first); ++ ++ wg_noise_keypair_put(keypair, false); ++ wg_peer_put(peer); ++ } ++} ++ ++void wg_packet_encrypt_worker(struct work_struct *work) ++{ ++ struct crypt_queue *queue = container_of(work, struct multicore_worker, ++ work)->ptr; ++ struct sk_buff *first, *skb, *next; ++ ++ while ((first = ptr_ring_consume_bh(&queue->ring)) != NULL) { ++ enum packet_state state = PACKET_STATE_CRYPTED; ++ ++ skb_list_walk_safe(first, skb, next) { ++ if (likely(encrypt_packet(skb, ++ PACKET_CB(first)->keypair))) { ++ wg_reset_packet(skb); ++ } else { ++ state = PACKET_STATE_DEAD; ++ break; ++ } ++ } ++ wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first, ++ state); ++ ++ } ++} ++ ++static void wg_packet_create_data(struct sk_buff *first) ++{ ++ struct wg_peer *peer = PACKET_PEER(first); ++ struct wg_device *wg = peer->device; ++ int ret = -EINVAL; ++ ++ rcu_read_lock_bh(); ++ if (unlikely(READ_ONCE(peer->is_dead))) ++ goto err; ++ ++ ret = wg_queue_enqueue_per_device_and_peer(&wg->encrypt_queue, ++ &peer->tx_queue, first, ++ wg->packet_crypt_wq, ++ &wg->encrypt_queue.last_cpu); ++ if (unlikely(ret == -EPIPE)) ++ wg_queue_enqueue_per_peer(&peer->tx_queue, first, ++ PACKET_STATE_DEAD); ++err: ++ rcu_read_unlock_bh(); ++ if (likely(!ret || ret == -EPIPE)) ++ return; ++ wg_noise_keypair_put(PACKET_CB(first)->keypair, false); ++ wg_peer_put(peer); ++ kfree_skb_list(first); ++} ++ ++void wg_packet_purge_staged_packets(struct wg_peer *peer) ++{ ++ spin_lock_bh(&peer->staged_packet_queue.lock); ++ peer->device->dev->stats.tx_dropped += peer->staged_packet_queue.qlen; ++ __skb_queue_purge(&peer->staged_packet_queue); ++ spin_unlock_bh(&peer->staged_packet_queue.lock); ++} ++ ++void wg_packet_send_staged_packets(struct wg_peer *peer) ++{ ++ struct noise_symmetric_key *key; ++ struct noise_keypair *keypair; ++ struct sk_buff_head packets; ++ struct sk_buff *skb; ++ ++ /* Steal the current queue into our local one. */ ++ __skb_queue_head_init(&packets); ++ spin_lock_bh(&peer->staged_packet_queue.lock); ++ skb_queue_splice_init(&peer->staged_packet_queue, &packets); ++ spin_unlock_bh(&peer->staged_packet_queue.lock); ++ if (unlikely(skb_queue_empty(&packets))) ++ return; ++ ++ /* First we make sure we have a valid reference to a valid key. */ ++ rcu_read_lock_bh(); ++ keypair = wg_noise_keypair_get( ++ rcu_dereference_bh(peer->keypairs.current_keypair)); ++ rcu_read_unlock_bh(); ++ if (unlikely(!keypair)) ++ goto out_nokey; ++ key = &keypair->sending; ++ if (unlikely(!READ_ONCE(key->is_valid))) ++ goto out_nokey; ++ if (unlikely(wg_birthdate_has_expired(key->birthdate, ++ REJECT_AFTER_TIME))) ++ goto out_invalid; ++ ++ /* After we know we have a somewhat valid key, we now try to assign ++ * nonces to all of the packets in the queue. If we can't assign nonces ++ * for all of them, we just consider it a failure and wait for the next ++ * handshake. ++ */ ++ skb_queue_walk(&packets, skb) { ++ /* 0 for no outer TOS: no leak. TODO: at some later point, we ++ * might consider using flowi->tos as outer instead. ++ */ ++ PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb); ++ PACKET_CB(skb)->nonce = ++ atomic64_inc_return(&key->counter.counter) - 1; ++ if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES)) ++ goto out_invalid; ++ } ++ ++ packets.prev->next = NULL; ++ wg_peer_get(keypair->entry.peer); ++ PACKET_CB(packets.next)->keypair = keypair; ++ wg_packet_create_data(packets.next); ++ return; ++ ++out_invalid: ++ WRITE_ONCE(key->is_valid, false); ++out_nokey: ++ wg_noise_keypair_put(keypair, false); ++ ++ /* We orphan the packets if we're waiting on a handshake, so that they ++ * don't block a socket's pool. ++ */ ++ skb_queue_walk(&packets, skb) ++ skb_orphan(skb); ++ /* Then we put them back on the top of the queue. We're not too ++ * concerned about accidentally getting things a little out of order if ++ * packets are being added really fast, because this queue is for before ++ * packets can even be sent and it's small anyway. ++ */ ++ spin_lock_bh(&peer->staged_packet_queue.lock); ++ skb_queue_splice(&packets, &peer->staged_packet_queue); ++ spin_unlock_bh(&peer->staged_packet_queue.lock); ++ ++ /* If we're exiting because there's something wrong with the key, it ++ * means we should initiate a new handshake. ++ */ ++ wg_packet_send_queued_handshake_initiation(peer, false); ++} +--- /dev/null ++++ b/drivers/net/wireguard/socket.c +@@ -0,0 +1,437 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "device.h" ++#include "peer.h" ++#include "socket.h" ++#include "queueing.h" ++#include "messages.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int send4(struct wg_device *wg, struct sk_buff *skb, ++ struct endpoint *endpoint, u8 ds, struct dst_cache *cache) ++{ ++ struct flowi4 fl = { ++ .saddr = endpoint->src4.s_addr, ++ .daddr = endpoint->addr4.sin_addr.s_addr, ++ .fl4_dport = endpoint->addr4.sin_port, ++ .flowi4_mark = wg->fwmark, ++ .flowi4_proto = IPPROTO_UDP ++ }; ++ struct rtable *rt = NULL; ++ struct sock *sock; ++ int ret = 0; ++ ++ skb_mark_not_on_list(skb); ++ skb->dev = wg->dev; ++ skb->mark = wg->fwmark; ++ ++ rcu_read_lock_bh(); ++ sock = rcu_dereference_bh(wg->sock4); ++ ++ if (unlikely(!sock)) { ++ ret = -ENONET; ++ goto err; ++ } ++ ++ fl.fl4_sport = inet_sk(sock)->inet_sport; ++ ++ if (cache) ++ rt = dst_cache_get_ip4(cache, &fl.saddr); ++ ++ if (!rt) { ++ security_sk_classify_flow(sock, flowi4_to_flowi(&fl)); ++ if (unlikely(!inet_confirm_addr(sock_net(sock), NULL, 0, ++ fl.saddr, RT_SCOPE_HOST))) { ++ endpoint->src4.s_addr = 0; ++ *(__force __be32 *)&endpoint->src_if4 = 0; ++ fl.saddr = 0; ++ if (cache) ++ dst_cache_reset(cache); ++ } ++ rt = ip_route_output_flow(sock_net(sock), &fl, sock); ++ if (unlikely(endpoint->src_if4 && ((IS_ERR(rt) && ++ PTR_ERR(rt) == -EINVAL) || (!IS_ERR(rt) && ++ rt->dst.dev->ifindex != endpoint->src_if4)))) { ++ endpoint->src4.s_addr = 0; ++ *(__force __be32 *)&endpoint->src_if4 = 0; ++ fl.saddr = 0; ++ if (cache) ++ dst_cache_reset(cache); ++ if (!IS_ERR(rt)) ++ ip_rt_put(rt); ++ rt = ip_route_output_flow(sock_net(sock), &fl, sock); ++ } ++ if (unlikely(IS_ERR(rt))) { ++ ret = PTR_ERR(rt); ++ net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n", ++ wg->dev->name, &endpoint->addr, ret); ++ goto err; ++ } else if (unlikely(rt->dst.dev == skb->dev)) { ++ ip_rt_put(rt); ++ ret = -ELOOP; ++ net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n", ++ wg->dev->name, &endpoint->addr); ++ goto err; ++ } ++ if (cache) ++ dst_cache_set_ip4(cache, &rt->dst, fl.saddr); ++ } ++ ++ skb->ignore_df = 1; ++ udp_tunnel_xmit_skb(rt, sock, skb, fl.saddr, fl.daddr, ds, ++ ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport, ++ fl.fl4_dport, false, false); ++ goto out; ++ ++err: ++ kfree_skb(skb); ++out: ++ rcu_read_unlock_bh(); ++ return ret; ++} ++ ++static int send6(struct wg_device *wg, struct sk_buff *skb, ++ struct endpoint *endpoint, u8 ds, struct dst_cache *cache) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ struct flowi6 fl = { ++ .saddr = endpoint->src6, ++ .daddr = endpoint->addr6.sin6_addr, ++ .fl6_dport = endpoint->addr6.sin6_port, ++ .flowi6_mark = wg->fwmark, ++ .flowi6_oif = endpoint->addr6.sin6_scope_id, ++ .flowi6_proto = IPPROTO_UDP ++ /* TODO: addr->sin6_flowinfo */ ++ }; ++ struct dst_entry *dst = NULL; ++ struct sock *sock; ++ int ret = 0; ++ ++ skb_mark_not_on_list(skb); ++ skb->dev = wg->dev; ++ skb->mark = wg->fwmark; ++ ++ rcu_read_lock_bh(); ++ sock = rcu_dereference_bh(wg->sock6); ++ ++ if (unlikely(!sock)) { ++ ret = -ENONET; ++ goto err; ++ } ++ ++ fl.fl6_sport = inet_sk(sock)->inet_sport; ++ ++ if (cache) ++ dst = dst_cache_get_ip6(cache, &fl.saddr); ++ ++ if (!dst) { ++ security_sk_classify_flow(sock, flowi6_to_flowi(&fl)); ++ if (unlikely(!ipv6_addr_any(&fl.saddr) && ++ !ipv6_chk_addr(sock_net(sock), &fl.saddr, NULL, 0))) { ++ endpoint->src6 = fl.saddr = in6addr_any; ++ if (cache) ++ dst_cache_reset(cache); ++ } ++ dst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sock), sock, &fl, ++ NULL); ++ if (unlikely(IS_ERR(dst))) { ++ ret = PTR_ERR(dst); ++ net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n", ++ wg->dev->name, &endpoint->addr, ret); ++ goto err; ++ } else if (unlikely(dst->dev == skb->dev)) { ++ dst_release(dst); ++ ret = -ELOOP; ++ net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n", ++ wg->dev->name, &endpoint->addr); ++ goto err; ++ } ++ if (cache) ++ dst_cache_set_ip6(cache, dst, &fl.saddr); ++ } ++ ++ skb->ignore_df = 1; ++ udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds, ++ ip6_dst_hoplimit(dst), 0, fl.fl6_sport, ++ fl.fl6_dport, false); ++ goto out; ++ ++err: ++ kfree_skb(skb); ++out: ++ rcu_read_unlock_bh(); ++ return ret; ++#else ++ return -EAFNOSUPPORT; ++#endif ++} ++ ++int wg_socket_send_skb_to_peer(struct wg_peer *peer, struct sk_buff *skb, u8 ds) ++{ ++ size_t skb_len = skb->len; ++ int ret = -EAFNOSUPPORT; ++ ++ read_lock_bh(&peer->endpoint_lock); ++ if (peer->endpoint.addr.sa_family == AF_INET) ++ ret = send4(peer->device, skb, &peer->endpoint, ds, ++ &peer->endpoint_cache); ++ else if (peer->endpoint.addr.sa_family == AF_INET6) ++ ret = send6(peer->device, skb, &peer->endpoint, ds, ++ &peer->endpoint_cache); ++ else ++ dev_kfree_skb(skb); ++ if (likely(!ret)) ++ peer->tx_bytes += skb_len; ++ read_unlock_bh(&peer->endpoint_lock); ++ ++ return ret; ++} ++ ++int wg_socket_send_buffer_to_peer(struct wg_peer *peer, void *buffer, ++ size_t len, u8 ds) ++{ ++ struct sk_buff *skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC); ++ ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ ++ skb_reserve(skb, SKB_HEADER_LEN); ++ skb_set_inner_network_header(skb, 0); ++ skb_put_data(skb, buffer, len); ++ return wg_socket_send_skb_to_peer(peer, skb, ds); ++} ++ ++int wg_socket_send_buffer_as_reply_to_skb(struct wg_device *wg, ++ struct sk_buff *in_skb, void *buffer, ++ size_t len) ++{ ++ int ret = 0; ++ struct sk_buff *skb; ++ struct endpoint endpoint; ++ ++ if (unlikely(!in_skb)) ++ return -EINVAL; ++ ret = wg_socket_endpoint_from_skb(&endpoint, in_skb); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ skb_reserve(skb, SKB_HEADER_LEN); ++ skb_set_inner_network_header(skb, 0); ++ skb_put_data(skb, buffer, len); ++ ++ if (endpoint.addr.sa_family == AF_INET) ++ ret = send4(wg, skb, &endpoint, 0, NULL); ++ else if (endpoint.addr.sa_family == AF_INET6) ++ ret = send6(wg, skb, &endpoint, 0, NULL); ++ /* No other possibilities if the endpoint is valid, which it is, ++ * as we checked above. ++ */ ++ ++ return ret; ++} ++ ++int wg_socket_endpoint_from_skb(struct endpoint *endpoint, ++ const struct sk_buff *skb) ++{ ++ memset(endpoint, 0, sizeof(*endpoint)); ++ if (skb->protocol == htons(ETH_P_IP)) { ++ endpoint->addr4.sin_family = AF_INET; ++ endpoint->addr4.sin_port = udp_hdr(skb)->source; ++ endpoint->addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; ++ endpoint->src4.s_addr = ip_hdr(skb)->daddr; ++ endpoint->src_if4 = skb->skb_iif; ++ } else if (skb->protocol == htons(ETH_P_IPV6)) { ++ endpoint->addr6.sin6_family = AF_INET6; ++ endpoint->addr6.sin6_port = udp_hdr(skb)->source; ++ endpoint->addr6.sin6_addr = ipv6_hdr(skb)->saddr; ++ endpoint->addr6.sin6_scope_id = ipv6_iface_scope_id( ++ &ipv6_hdr(skb)->saddr, skb->skb_iif); ++ endpoint->src6 = ipv6_hdr(skb)->daddr; ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static bool endpoint_eq(const struct endpoint *a, const struct endpoint *b) ++{ ++ return (a->addr.sa_family == AF_INET && b->addr.sa_family == AF_INET && ++ a->addr4.sin_port == b->addr4.sin_port && ++ a->addr4.sin_addr.s_addr == b->addr4.sin_addr.s_addr && ++ a->src4.s_addr == b->src4.s_addr && a->src_if4 == b->src_if4) || ++ (a->addr.sa_family == AF_INET6 && ++ b->addr.sa_family == AF_INET6 && ++ a->addr6.sin6_port == b->addr6.sin6_port && ++ ipv6_addr_equal(&a->addr6.sin6_addr, &b->addr6.sin6_addr) && ++ a->addr6.sin6_scope_id == b->addr6.sin6_scope_id && ++ ipv6_addr_equal(&a->src6, &b->src6)) || ++ unlikely(!a->addr.sa_family && !b->addr.sa_family); ++} ++ ++void wg_socket_set_peer_endpoint(struct wg_peer *peer, ++ const struct endpoint *endpoint) ++{ ++ /* First we check unlocked, in order to optimize, since it's pretty rare ++ * that an endpoint will change. If we happen to be mid-write, and two ++ * CPUs wind up writing the same thing or something slightly different, ++ * it doesn't really matter much either. ++ */ ++ if (endpoint_eq(endpoint, &peer->endpoint)) ++ return; ++ write_lock_bh(&peer->endpoint_lock); ++ if (endpoint->addr.sa_family == AF_INET) { ++ peer->endpoint.addr4 = endpoint->addr4; ++ peer->endpoint.src4 = endpoint->src4; ++ peer->endpoint.src_if4 = endpoint->src_if4; ++ } else if (endpoint->addr.sa_family == AF_INET6) { ++ peer->endpoint.addr6 = endpoint->addr6; ++ peer->endpoint.src6 = endpoint->src6; ++ } else { ++ goto out; ++ } ++ dst_cache_reset(&peer->endpoint_cache); ++out: ++ write_unlock_bh(&peer->endpoint_lock); ++} ++ ++void wg_socket_set_peer_endpoint_from_skb(struct wg_peer *peer, ++ const struct sk_buff *skb) ++{ ++ struct endpoint endpoint; ++ ++ if (!wg_socket_endpoint_from_skb(&endpoint, skb)) ++ wg_socket_set_peer_endpoint(peer, &endpoint); ++} ++ ++void wg_socket_clear_peer_endpoint_src(struct wg_peer *peer) ++{ ++ write_lock_bh(&peer->endpoint_lock); ++ memset(&peer->endpoint.src6, 0, sizeof(peer->endpoint.src6)); ++ dst_cache_reset(&peer->endpoint_cache); ++ write_unlock_bh(&peer->endpoint_lock); ++} ++ ++static int wg_receive(struct sock *sk, struct sk_buff *skb) ++{ ++ struct wg_device *wg; ++ ++ if (unlikely(!sk)) ++ goto err; ++ wg = sk->sk_user_data; ++ if (unlikely(!wg)) ++ goto err; ++ wg_packet_receive(wg, skb); ++ return 0; ++ ++err: ++ kfree_skb(skb); ++ return 0; ++} ++ ++static void sock_free(struct sock *sock) ++{ ++ if (unlikely(!sock)) ++ return; ++ sk_clear_memalloc(sock); ++ udp_tunnel_sock_release(sock->sk_socket); ++} ++ ++static void set_sock_opts(struct socket *sock) ++{ ++ sock->sk->sk_allocation = GFP_ATOMIC; ++ sock->sk->sk_sndbuf = INT_MAX; ++ sk_set_memalloc(sock->sk); ++} ++ ++int wg_socket_init(struct wg_device *wg, u16 port) ++{ ++ int ret; ++ struct udp_tunnel_sock_cfg cfg = { ++ .sk_user_data = wg, ++ .encap_type = 1, ++ .encap_rcv = wg_receive ++ }; ++ struct socket *new4 = NULL, *new6 = NULL; ++ struct udp_port_cfg port4 = { ++ .family = AF_INET, ++ .local_ip.s_addr = htonl(INADDR_ANY), ++ .local_udp_port = htons(port), ++ .use_udp_checksums = true ++ }; ++#if IS_ENABLED(CONFIG_IPV6) ++ int retries = 0; ++ struct udp_port_cfg port6 = { ++ .family = AF_INET6, ++ .local_ip6 = IN6ADDR_ANY_INIT, ++ .use_udp6_tx_checksums = true, ++ .use_udp6_rx_checksums = true, ++ .ipv6_v6only = true ++ }; ++#endif ++ ++#if IS_ENABLED(CONFIG_IPV6) ++retry: ++#endif ++ ++ ret = udp_sock_create(wg->creating_net, &port4, &new4); ++ if (ret < 0) { ++ pr_err("%s: Could not create IPv4 socket\n", wg->dev->name); ++ return ret; ++ } ++ set_sock_opts(new4); ++ setup_udp_tunnel_sock(wg->creating_net, new4, &cfg); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (ipv6_mod_enabled()) { ++ port6.local_udp_port = inet_sk(new4->sk)->inet_sport; ++ ret = udp_sock_create(wg->creating_net, &port6, &new6); ++ if (ret < 0) { ++ udp_tunnel_sock_release(new4); ++ if (ret == -EADDRINUSE && !port && retries++ < 100) ++ goto retry; ++ pr_err("%s: Could not create IPv6 socket\n", ++ wg->dev->name); ++ return ret; ++ } ++ set_sock_opts(new6); ++ setup_udp_tunnel_sock(wg->creating_net, new6, &cfg); ++ } ++#endif ++ ++ wg_socket_reinit(wg, new4->sk, new6 ? new6->sk : NULL); ++ return 0; ++} ++ ++void wg_socket_reinit(struct wg_device *wg, struct sock *new4, ++ struct sock *new6) ++{ ++ struct sock *old4, *old6; ++ ++ mutex_lock(&wg->socket_update_lock); ++ old4 = rcu_dereference_protected(wg->sock4, ++ lockdep_is_held(&wg->socket_update_lock)); ++ old6 = rcu_dereference_protected(wg->sock6, ++ lockdep_is_held(&wg->socket_update_lock)); ++ rcu_assign_pointer(wg->sock4, new4); ++ rcu_assign_pointer(wg->sock6, new6); ++ if (new4) ++ wg->incoming_port = ntohs(inet_sk(new4)->inet_sport); ++ mutex_unlock(&wg->socket_update_lock); ++ synchronize_rcu(); ++ synchronize_net(); ++ sock_free(old4); ++ sock_free(old6); ++} +--- /dev/null ++++ b/drivers/net/wireguard/socket.h +@@ -0,0 +1,44 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_SOCKET_H ++#define _WG_SOCKET_H ++ ++#include ++#include ++#include ++#include ++ ++int wg_socket_init(struct wg_device *wg, u16 port); ++void wg_socket_reinit(struct wg_device *wg, struct sock *new4, ++ struct sock *new6); ++int wg_socket_send_buffer_to_peer(struct wg_peer *peer, void *data, ++ size_t len, u8 ds); ++int wg_socket_send_skb_to_peer(struct wg_peer *peer, struct sk_buff *skb, ++ u8 ds); ++int wg_socket_send_buffer_as_reply_to_skb(struct wg_device *wg, ++ struct sk_buff *in_skb, ++ void *out_buffer, size_t len); ++ ++int wg_socket_endpoint_from_skb(struct endpoint *endpoint, ++ const struct sk_buff *skb); ++void wg_socket_set_peer_endpoint(struct wg_peer *peer, ++ const struct endpoint *endpoint); ++void wg_socket_set_peer_endpoint_from_skb(struct wg_peer *peer, ++ const struct sk_buff *skb); ++void wg_socket_clear_peer_endpoint_src(struct wg_peer *peer); ++ ++#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG) ++#define net_dbg_skb_ratelimited(fmt, dev, skb, ...) do { \ ++ struct endpoint __endpoint; \ ++ wg_socket_endpoint_from_skb(&__endpoint, skb); \ ++ net_dbg_ratelimited(fmt, dev, &__endpoint.addr, \ ++ ##__VA_ARGS__); \ ++ } while (0) ++#else ++#define net_dbg_skb_ratelimited(fmt, skb, ...) ++#endif ++ ++#endif /* _WG_SOCKET_H */ +--- /dev/null ++++ b/drivers/net/wireguard/timers.c +@@ -0,0 +1,243 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "timers.h" ++#include "device.h" ++#include "peer.h" ++#include "queueing.h" ++#include "socket.h" ++ ++/* ++ * - Timer for retransmitting the handshake if we don't hear back after ++ * `REKEY_TIMEOUT + jitter` ms. ++ * ++ * - Timer for sending empty packet if we have received a packet but after have ++ * not sent one for `KEEPALIVE_TIMEOUT` ms. ++ * ++ * - Timer for initiating new handshake if we have sent a packet but after have ++ * not received one (even empty) for `(KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) + ++ * jitter` ms. ++ * ++ * - Timer for zeroing out all ephemeral keys after `(REJECT_AFTER_TIME * 3)` ms ++ * if no new keys have been received. ++ * ++ * - Timer for, if enabled, sending an empty authenticated packet every user- ++ * specified seconds. ++ */ ++ ++static inline void mod_peer_timer(struct wg_peer *peer, ++ struct timer_list *timer, ++ unsigned long expires) ++{ ++ rcu_read_lock_bh(); ++ if (likely(netif_running(peer->device->dev) && ++ !READ_ONCE(peer->is_dead))) ++ mod_timer(timer, expires); ++ rcu_read_unlock_bh(); ++} ++ ++static void wg_expired_retransmit_handshake(struct timer_list *timer) ++{ ++ struct wg_peer *peer = from_timer(peer, timer, ++ timer_retransmit_handshake); ++ ++ if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) { ++ pr_debug("%s: Handshake for peer %llu (%pISpfsc) did not complete after %d attempts, giving up\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr, MAX_TIMER_HANDSHAKES + 2); ++ ++ del_timer(&peer->timer_send_keepalive); ++ /* We drop all packets without a keypair and don't try again, ++ * if we try unsuccessfully for too long to make a handshake. ++ */ ++ wg_packet_purge_staged_packets(peer); ++ ++ /* We set a timer for destroying any residue that might be left ++ * of a partial exchange. ++ */ ++ if (!timer_pending(&peer->timer_zero_key_material)) ++ mod_peer_timer(peer, &peer->timer_zero_key_material, ++ jiffies + REJECT_AFTER_TIME * 3 * HZ); ++ } else { ++ ++peer->timer_handshake_attempts; ++ pr_debug("%s: Handshake for peer %llu (%pISpfsc) did not complete after %d seconds, retrying (try %d)\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr, REKEY_TIMEOUT, ++ peer->timer_handshake_attempts + 1); ++ ++ /* We clear the endpoint address src address, in case this is ++ * the cause of trouble. ++ */ ++ wg_socket_clear_peer_endpoint_src(peer); ++ ++ wg_packet_send_queued_handshake_initiation(peer, true); ++ } ++} ++ ++static void wg_expired_send_keepalive(struct timer_list *timer) ++{ ++ struct wg_peer *peer = from_timer(peer, timer, timer_send_keepalive); ++ ++ wg_packet_send_keepalive(peer); ++ if (peer->timer_need_another_keepalive) { ++ peer->timer_need_another_keepalive = false; ++ mod_peer_timer(peer, &peer->timer_send_keepalive, ++ jiffies + KEEPALIVE_TIMEOUT * HZ); ++ } ++} ++ ++static void wg_expired_new_handshake(struct timer_list *timer) ++{ ++ struct wg_peer *peer = from_timer(peer, timer, timer_new_handshake); ++ ++ pr_debug("%s: Retrying handshake with peer %llu (%pISpfsc) because we stopped hearing back after %d seconds\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr, KEEPALIVE_TIMEOUT + REKEY_TIMEOUT); ++ /* We clear the endpoint address src address, in case this is the cause ++ * of trouble. ++ */ ++ wg_socket_clear_peer_endpoint_src(peer); ++ wg_packet_send_queued_handshake_initiation(peer, false); ++} ++ ++static void wg_expired_zero_key_material(struct timer_list *timer) ++{ ++ struct wg_peer *peer = from_timer(peer, timer, timer_zero_key_material); ++ ++ rcu_read_lock_bh(); ++ if (!READ_ONCE(peer->is_dead)) { ++ wg_peer_get(peer); ++ if (!queue_work(peer->device->handshake_send_wq, ++ &peer->clear_peer_work)) ++ /* If the work was already on the queue, we want to drop ++ * the extra reference. ++ */ ++ wg_peer_put(peer); ++ } ++ rcu_read_unlock_bh(); ++} ++ ++static void wg_queued_expired_zero_key_material(struct work_struct *work) ++{ ++ struct wg_peer *peer = container_of(work, struct wg_peer, ++ clear_peer_work); ++ ++ pr_debug("%s: Zeroing out all keys for peer %llu (%pISpfsc), since we haven't received a new one in %d seconds\n", ++ peer->device->dev->name, peer->internal_id, ++ &peer->endpoint.addr, REJECT_AFTER_TIME * 3); ++ wg_noise_handshake_clear(&peer->handshake); ++ wg_noise_keypairs_clear(&peer->keypairs); ++ wg_peer_put(peer); ++} ++ ++static void wg_expired_send_persistent_keepalive(struct timer_list *timer) ++{ ++ struct wg_peer *peer = from_timer(peer, timer, ++ timer_persistent_keepalive); ++ ++ if (likely(peer->persistent_keepalive_interval)) ++ wg_packet_send_keepalive(peer); ++} ++ ++/* Should be called after an authenticated data packet is sent. */ ++void wg_timers_data_sent(struct wg_peer *peer) ++{ ++ if (!timer_pending(&peer->timer_new_handshake)) ++ mod_peer_timer(peer, &peer->timer_new_handshake, ++ jiffies + (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) * HZ + ++ prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX_JIFFIES)); ++} ++ ++/* Should be called after an authenticated data packet is received. */ ++void wg_timers_data_received(struct wg_peer *peer) ++{ ++ if (likely(netif_running(peer->device->dev))) { ++ if (!timer_pending(&peer->timer_send_keepalive)) ++ mod_peer_timer(peer, &peer->timer_send_keepalive, ++ jiffies + KEEPALIVE_TIMEOUT * HZ); ++ else ++ peer->timer_need_another_keepalive = true; ++ } ++} ++ ++/* Should be called after any type of authenticated packet is sent, whether ++ * keepalive, data, or handshake. ++ */ ++void wg_timers_any_authenticated_packet_sent(struct wg_peer *peer) ++{ ++ del_timer(&peer->timer_send_keepalive); ++} ++ ++/* Should be called after any type of authenticated packet is received, whether ++ * keepalive, data, or handshake. ++ */ ++void wg_timers_any_authenticated_packet_received(struct wg_peer *peer) ++{ ++ del_timer(&peer->timer_new_handshake); ++} ++ ++/* Should be called after a handshake initiation message is sent. */ ++void wg_timers_handshake_initiated(struct wg_peer *peer) ++{ ++ mod_peer_timer(peer, &peer->timer_retransmit_handshake, ++ jiffies + REKEY_TIMEOUT * HZ + ++ prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX_JIFFIES)); ++} ++ ++/* Should be called after a handshake response message is received and processed ++ * or when getting key confirmation via the first data message. ++ */ ++void wg_timers_handshake_complete(struct wg_peer *peer) ++{ ++ del_timer(&peer->timer_retransmit_handshake); ++ peer->timer_handshake_attempts = 0; ++ peer->sent_lastminute_handshake = false; ++ ktime_get_real_ts64(&peer->walltime_last_handshake); ++} ++ ++/* Should be called after an ephemeral key is created, which is before sending a ++ * handshake response or after receiving a handshake response. ++ */ ++void wg_timers_session_derived(struct wg_peer *peer) ++{ ++ mod_peer_timer(peer, &peer->timer_zero_key_material, ++ jiffies + REJECT_AFTER_TIME * 3 * HZ); ++} ++ ++/* Should be called before a packet with authentication, whether ++ * keepalive, data, or handshakem is sent, or after one is received. ++ */ ++void wg_timers_any_authenticated_packet_traversal(struct wg_peer *peer) ++{ ++ if (peer->persistent_keepalive_interval) ++ mod_peer_timer(peer, &peer->timer_persistent_keepalive, ++ jiffies + peer->persistent_keepalive_interval * HZ); ++} ++ ++void wg_timers_init(struct wg_peer *peer) ++{ ++ timer_setup(&peer->timer_retransmit_handshake, ++ wg_expired_retransmit_handshake, 0); ++ timer_setup(&peer->timer_send_keepalive, wg_expired_send_keepalive, 0); ++ timer_setup(&peer->timer_new_handshake, wg_expired_new_handshake, 0); ++ timer_setup(&peer->timer_zero_key_material, ++ wg_expired_zero_key_material, 0); ++ timer_setup(&peer->timer_persistent_keepalive, ++ wg_expired_send_persistent_keepalive, 0); ++ INIT_WORK(&peer->clear_peer_work, wg_queued_expired_zero_key_material); ++ peer->timer_handshake_attempts = 0; ++ peer->sent_lastminute_handshake = false; ++ peer->timer_need_another_keepalive = false; ++} ++ ++void wg_timers_stop(struct wg_peer *peer) ++{ ++ del_timer_sync(&peer->timer_retransmit_handshake); ++ del_timer_sync(&peer->timer_send_keepalive); ++ del_timer_sync(&peer->timer_new_handshake); ++ del_timer_sync(&peer->timer_zero_key_material); ++ del_timer_sync(&peer->timer_persistent_keepalive); ++ flush_work(&peer->clear_peer_work); ++} +--- /dev/null ++++ b/drivers/net/wireguard/timers.h +@@ -0,0 +1,31 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#ifndef _WG_TIMERS_H ++#define _WG_TIMERS_H ++ ++#include ++ ++struct wg_peer; ++ ++void wg_timers_init(struct wg_peer *peer); ++void wg_timers_stop(struct wg_peer *peer); ++void wg_timers_data_sent(struct wg_peer *peer); ++void wg_timers_data_received(struct wg_peer *peer); ++void wg_timers_any_authenticated_packet_sent(struct wg_peer *peer); ++void wg_timers_any_authenticated_packet_received(struct wg_peer *peer); ++void wg_timers_handshake_initiated(struct wg_peer *peer); ++void wg_timers_handshake_complete(struct wg_peer *peer); ++void wg_timers_session_derived(struct wg_peer *peer); ++void wg_timers_any_authenticated_packet_traversal(struct wg_peer *peer); ++ ++static inline bool wg_birthdate_has_expired(u64 birthday_nanoseconds, ++ u64 expiration_seconds) ++{ ++ return (s64)(birthday_nanoseconds + expiration_seconds * NSEC_PER_SEC) ++ <= (s64)ktime_get_coarse_boottime_ns(); ++} ++ ++#endif /* _WG_TIMERS_H */ +--- /dev/null ++++ b/drivers/net/wireguard/version.h +@@ -0,0 +1 @@ ++#define WIREGUARD_VERSION "1.0.0" +--- /dev/null ++++ b/include/uapi/linux/wireguard.h +@@ -0,0 +1,196 @@ ++/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */ ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * Documentation ++ * ============= ++ * ++ * The below enums and macros are for interfacing with WireGuard, using generic ++ * netlink, with family WG_GENL_NAME and version WG_GENL_VERSION. It defines two ++ * methods: get and set. Note that while they share many common attributes, ++ * these two functions actually accept a slightly different set of inputs and ++ * outputs. ++ * ++ * WG_CMD_GET_DEVICE ++ * ----------------- ++ * ++ * May only be called via NLM_F_REQUEST | NLM_F_DUMP. The command should contain ++ * one but not both of: ++ * ++ * WGDEVICE_A_IFINDEX: NLA_U32 ++ * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1 ++ * ++ * The kernel will then return several messages (NLM_F_MULTI) containing the ++ * following tree of nested items: ++ * ++ * WGDEVICE_A_IFINDEX: NLA_U32 ++ * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1 ++ * WGDEVICE_A_PRIVATE_KEY: NLA_EXACT_LEN, len WG_KEY_LEN ++ * WGDEVICE_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN ++ * WGDEVICE_A_LISTEN_PORT: NLA_U16 ++ * WGDEVICE_A_FWMARK: NLA_U32 ++ * WGDEVICE_A_PEERS: NLA_NESTED ++ * 0: NLA_NESTED ++ * WGPEER_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN ++ * WGPEER_A_PRESHARED_KEY: NLA_EXACT_LEN, len WG_KEY_LEN ++ * WGPEER_A_ENDPOINT: NLA_MIN_LEN(struct sockaddr), struct sockaddr_in or struct sockaddr_in6 ++ * WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16 ++ * WGPEER_A_LAST_HANDSHAKE_TIME: NLA_EXACT_LEN, struct __kernel_timespec ++ * WGPEER_A_RX_BYTES: NLA_U64 ++ * WGPEER_A_TX_BYTES: NLA_U64 ++ * WGPEER_A_ALLOWEDIPS: NLA_NESTED ++ * 0: NLA_NESTED ++ * WGALLOWEDIP_A_FAMILY: NLA_U16 ++ * WGALLOWEDIP_A_IPADDR: NLA_MIN_LEN(struct in_addr), struct in_addr or struct in6_addr ++ * WGALLOWEDIP_A_CIDR_MASK: NLA_U8 ++ * 0: NLA_NESTED ++ * ... ++ * 0: NLA_NESTED ++ * ... ++ * ... ++ * WGPEER_A_PROTOCOL_VERSION: NLA_U32 ++ * 0: NLA_NESTED ++ * ... ++ * ... ++ * ++ * It is possible that all of the allowed IPs of a single peer will not ++ * fit within a single netlink message. In that case, the same peer will ++ * be written in the following message, except it will only contain ++ * WGPEER_A_PUBLIC_KEY and WGPEER_A_ALLOWEDIPS. This may occur several ++ * times in a row for the same peer. It is then up to the receiver to ++ * coalesce adjacent peers. Likewise, it is possible that all peers will ++ * not fit within a single message. So, subsequent peers will be sent ++ * in following messages, except those will only contain WGDEVICE_A_IFNAME ++ * and WGDEVICE_A_PEERS. It is then up to the receiver to coalesce these ++ * messages to form the complete list of peers. ++ * ++ * Since this is an NLA_F_DUMP command, the final message will always be ++ * NLMSG_DONE, even if an error occurs. However, this NLMSG_DONE message ++ * contains an integer error code. It is either zero or a negative error ++ * code corresponding to the errno. ++ * ++ * WG_CMD_SET_DEVICE ++ * ----------------- ++ * ++ * May only be called via NLM_F_REQUEST. The command should contain the ++ * following tree of nested items, containing one but not both of ++ * WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME: ++ * ++ * WGDEVICE_A_IFINDEX: NLA_U32 ++ * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1 ++ * WGDEVICE_A_FLAGS: NLA_U32, 0 or WGDEVICE_F_REPLACE_PEERS if all current ++ * peers should be removed prior to adding the list below. ++ * WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN, all zeros to remove ++ * WGDEVICE_A_LISTEN_PORT: NLA_U16, 0 to choose randomly ++ * WGDEVICE_A_FWMARK: NLA_U32, 0 to disable ++ * WGDEVICE_A_PEERS: NLA_NESTED ++ * 0: NLA_NESTED ++ * WGPEER_A_PUBLIC_KEY: len WG_KEY_LEN ++ * WGPEER_A_FLAGS: NLA_U32, 0 and/or WGPEER_F_REMOVE_ME if the ++ * specified peer should not exist at the end of the ++ * operation, rather than added/updated and/or ++ * WGPEER_F_REPLACE_ALLOWEDIPS if all current allowed ++ * IPs of this peer should be removed prior to adding ++ * the list below and/or WGPEER_F_UPDATE_ONLY if the ++ * peer should only be set if it already exists. ++ * WGPEER_A_PRESHARED_KEY: len WG_KEY_LEN, all zeros to remove ++ * WGPEER_A_ENDPOINT: struct sockaddr_in or struct sockaddr_in6 ++ * WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: NLA_U16, 0 to disable ++ * WGPEER_A_ALLOWEDIPS: NLA_NESTED ++ * 0: NLA_NESTED ++ * WGALLOWEDIP_A_FAMILY: NLA_U16 ++ * WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr ++ * WGALLOWEDIP_A_CIDR_MASK: NLA_U8 ++ * 0: NLA_NESTED ++ * ... ++ * 0: NLA_NESTED ++ * ... ++ * ... ++ * WGPEER_A_PROTOCOL_VERSION: NLA_U32, should not be set or used at ++ * all by most users of this API, as the ++ * most recent protocol will be used when ++ * this is unset. Otherwise, must be set ++ * to 1. ++ * 0: NLA_NESTED ++ * ... ++ * ... ++ * ++ * It is possible that the amount of configuration data exceeds that of ++ * the maximum message length accepted by the kernel. In that case, several ++ * messages should be sent one after another, with each successive one ++ * filling in information not contained in the prior. Note that if ++ * WGDEVICE_F_REPLACE_PEERS is specified in the first message, it probably ++ * should not be specified in fragments that come after, so that the list ++ * of peers is only cleared the first time but appened after. Likewise for ++ * peers, if WGPEER_F_REPLACE_ALLOWEDIPS is specified in the first message ++ * of a peer, it likely should not be specified in subsequent fragments. ++ * ++ * If an error occurs, NLMSG_ERROR will reply containing an errno. ++ */ ++ ++#ifndef _WG_UAPI_WIREGUARD_H ++#define _WG_UAPI_WIREGUARD_H ++ ++#define WG_GENL_NAME "wireguard" ++#define WG_GENL_VERSION 1 ++ ++#define WG_KEY_LEN 32 ++ ++enum wg_cmd { ++ WG_CMD_GET_DEVICE, ++ WG_CMD_SET_DEVICE, ++ __WG_CMD_MAX ++}; ++#define WG_CMD_MAX (__WG_CMD_MAX - 1) ++ ++enum wgdevice_flag { ++ WGDEVICE_F_REPLACE_PEERS = 1U << 0, ++ __WGDEVICE_F_ALL = WGDEVICE_F_REPLACE_PEERS ++}; ++enum wgdevice_attribute { ++ WGDEVICE_A_UNSPEC, ++ WGDEVICE_A_IFINDEX, ++ WGDEVICE_A_IFNAME, ++ WGDEVICE_A_PRIVATE_KEY, ++ WGDEVICE_A_PUBLIC_KEY, ++ WGDEVICE_A_FLAGS, ++ WGDEVICE_A_LISTEN_PORT, ++ WGDEVICE_A_FWMARK, ++ WGDEVICE_A_PEERS, ++ __WGDEVICE_A_LAST ++}; ++#define WGDEVICE_A_MAX (__WGDEVICE_A_LAST - 1) ++ ++enum wgpeer_flag { ++ WGPEER_F_REMOVE_ME = 1U << 0, ++ WGPEER_F_REPLACE_ALLOWEDIPS = 1U << 1, ++ WGPEER_F_UPDATE_ONLY = 1U << 2, ++ __WGPEER_F_ALL = WGPEER_F_REMOVE_ME | WGPEER_F_REPLACE_ALLOWEDIPS | ++ WGPEER_F_UPDATE_ONLY ++}; ++enum wgpeer_attribute { ++ WGPEER_A_UNSPEC, ++ WGPEER_A_PUBLIC_KEY, ++ WGPEER_A_PRESHARED_KEY, ++ WGPEER_A_FLAGS, ++ WGPEER_A_ENDPOINT, ++ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, ++ WGPEER_A_LAST_HANDSHAKE_TIME, ++ WGPEER_A_RX_BYTES, ++ WGPEER_A_TX_BYTES, ++ WGPEER_A_ALLOWEDIPS, ++ WGPEER_A_PROTOCOL_VERSION, ++ __WGPEER_A_LAST ++}; ++#define WGPEER_A_MAX (__WGPEER_A_LAST - 1) ++ ++enum wgallowedip_attribute { ++ WGALLOWEDIP_A_UNSPEC, ++ WGALLOWEDIP_A_FAMILY, ++ WGALLOWEDIP_A_IPADDR, ++ WGALLOWEDIP_A_CIDR_MASK, ++ __WGALLOWEDIP_A_LAST ++}; ++#define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1) ++ ++#endif /* _WG_UAPI_WIREGUARD_H */ +--- /dev/null ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -0,0 +1,537 @@ ++#!/bin/bash ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++# ++# This script tests the below topology: ++# ++# ┌─────────────────────┐ ┌──────────────────────────────────┐ ┌─────────────────────┐ ++# │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │ ++# │ │ │ │ │ │ ++# │┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐│ ++# ││ wg0 │───────────┼───┼────────────│ lo │────────────┼───┼───────────│ wg0 ││ ++# │├────────┴──────────┐│ │ ┌───────┴────────┴────────┐ │ │┌──────────┴────────┤│ ++# ││192.168.241.1/24 ││ │ │(ns1) (ns2) │ │ ││192.168.241.2/24 ││ ++# ││fd00::1/24 ││ │ │127.0.0.1:1 127.0.0.1:2│ │ ││fd00::2/24 ││ ++# │└───────────────────┘│ │ │[::]:1 [::]:2 │ │ │└───────────────────┘│ ++# └─────────────────────┘ │ └─────────────────────────┘ │ └─────────────────────┘ ++# └──────────────────────────────────┘ ++# ++# After the topology is prepared we run a series of TCP/UDP iperf3 tests between the ++# wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg0 ++# interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further ++# details on how this is accomplished. ++set -e ++ ++exec 3>&1 ++export WG_HIDE_KEYS=never ++netns0="wg-test-$$-0" ++netns1="wg-test-$$-1" ++netns2="wg-test-$$-2" ++pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; } ++pp() { pretty "" "$*"; "$@"; } ++maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; } ++n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; } ++n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; } ++n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; } ++ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; } ++ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; } ++ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; } ++sleep() { read -t "$1" -N 0 || true; } ++waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; } ++waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } ++waitncattcp() { pretty "${1//*-}" "wait for tcp:1111"; while [[ $(ss -N "$1" -tlp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } ++waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; } ++ ++cleanup() { ++ set +e ++ exec 2>/dev/null ++ printf "$orig_message_cost" > /proc/sys/net/core/message_cost ++ ip0 link del dev wg0 ++ ip1 link del dev wg0 ++ ip2 link del dev wg0 ++ local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)" ++ [[ -n $to_kill ]] && kill $to_kill ++ pp ip netns del $netns1 ++ pp ip netns del $netns2 ++ pp ip netns del $netns0 ++ exit ++} ++ ++orig_message_cost="$(< /proc/sys/net/core/message_cost)" ++trap cleanup EXIT ++printf 0 > /proc/sys/net/core/message_cost ++ ++ip netns del $netns0 2>/dev/null || true ++ip netns del $netns1 2>/dev/null || true ++ip netns del $netns2 2>/dev/null || true ++pp ip netns add $netns0 ++pp ip netns add $netns1 ++pp ip netns add $netns2 ++ip0 link set up dev lo ++ ++ip0 link add dev wg0 type wireguard ++ip0 link set wg0 netns $netns1 ++ip0 link add dev wg0 type wireguard ++ip0 link set wg0 netns $netns2 ++key1="$(pp wg genkey)" ++key2="$(pp wg genkey)" ++key3="$(pp wg genkey)" ++pub1="$(pp wg pubkey <<<"$key1")" ++pub2="$(pp wg pubkey <<<"$key2")" ++pub3="$(pp wg pubkey <<<"$key3")" ++psk="$(pp wg genpsk)" ++[[ -n $key1 && -n $key2 && -n $psk ]] ++ ++configure_peers() { ++ ip1 addr add 192.168.241.1/24 dev wg0 ++ ip1 addr add fd00::1/24 dev wg0 ++ ++ ip2 addr add 192.168.241.2/24 dev wg0 ++ ip2 addr add fd00::2/24 dev wg0 ++ ++ n1 wg set wg0 \ ++ private-key <(echo "$key1") \ ++ listen-port 1 \ ++ peer "$pub2" \ ++ preshared-key <(echo "$psk") \ ++ allowed-ips 192.168.241.2/32,fd00::2/128 ++ n2 wg set wg0 \ ++ private-key <(echo "$key2") \ ++ listen-port 2 \ ++ peer "$pub1" \ ++ preshared-key <(echo "$psk") \ ++ allowed-ips 192.168.241.1/32,fd00::1/128 ++ ++ ip1 link set up dev wg0 ++ ip2 link set up dev wg0 ++} ++configure_peers ++ ++tests() { ++ # Ping over IPv4 ++ n2 ping -c 10 -f -W 1 192.168.241.1 ++ n1 ping -c 10 -f -W 1 192.168.241.2 ++ ++ # Ping over IPv6 ++ n2 ping6 -c 10 -f -W 1 fd00::1 ++ n1 ping6 -c 10 -f -W 1 fd00::2 ++ ++ # TCP over IPv4 ++ n2 iperf3 -s -1 -B 192.168.241.2 & ++ waitiperf $netns2 ++ n1 iperf3 -Z -t 3 -c 192.168.241.2 ++ ++ # TCP over IPv6 ++ n1 iperf3 -s -1 -B fd00::1 & ++ waitiperf $netns1 ++ n2 iperf3 -Z -t 3 -c fd00::1 ++ ++ # UDP over IPv4 ++ n1 iperf3 -s -1 -B 192.168.241.1 & ++ waitiperf $netns1 ++ n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1 ++ ++ # UDP over IPv6 ++ n2 iperf3 -s -1 -B fd00::2 & ++ waitiperf $netns2 ++ n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2 ++} ++ ++[[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}" ++big_mtu=$(( 34816 - 1500 + $orig_mtu )) ++ ++# Test using IPv4 as outer transport ++n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2 ++n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1 ++# Before calling tests, we first make sure that the stats counters and timestamper are working ++n2 ping -c 10 -f -W 1 192.168.241.1 ++{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0) ++(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) )) ++{ read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0) ++(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) )) ++read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer) ++(( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) )) ++read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer) ++(( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) )) ++read _ timestamp < <(n1 wg show wg0 latest-handshakes) ++(( timestamp != 0 )) ++ ++tests ++ip1 link set wg0 mtu $big_mtu ++ip2 link set wg0 mtu $big_mtu ++tests ++ ++ip1 link set wg0 mtu $orig_mtu ++ip2 link set wg0 mtu $orig_mtu ++ ++# Test using IPv6 as outer transport ++n1 wg set wg0 peer "$pub2" endpoint [::1]:2 ++n2 wg set wg0 peer "$pub1" endpoint [::1]:1 ++tests ++ip1 link set wg0 mtu $big_mtu ++ip2 link set wg0 mtu $big_mtu ++tests ++ ++# Test that route MTUs work with the padding ++ip1 link set wg0 mtu 1300 ++ip2 link set wg0 mtu 1300 ++n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2 ++n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1 ++n0 iptables -A INPUT -m length --length 1360 -j DROP ++n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299 ++n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299 ++n2 ping -c 1 -W 1 -s 1269 192.168.241.1 ++n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299 ++n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299 ++n0 iptables -F INPUT ++ ++ip1 link set wg0 mtu $orig_mtu ++ip2 link set wg0 mtu $orig_mtu ++ ++# Test using IPv4 that roaming works ++ip0 -4 addr del 127.0.0.1/8 dev lo ++ip0 -4 addr add 127.212.121.99/8 dev lo ++n1 wg set wg0 listen-port 9999 ++n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2 ++n1 ping6 -W 1 -c 1 fd00::2 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 127.212.121.99:9999" ]] ++ ++# Test using IPv6 that roaming works ++n1 wg set wg0 listen-port 9998 ++n1 wg set wg0 peer "$pub2" endpoint [::1]:2 ++n1 ping -W 1 -c 1 192.168.241.2 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 [::1]:9998" ]] ++ ++# Test that crypto-RP filter works ++n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24 ++exec 4< <(n1 ncat -l -u -p 1111) ++ncat_pid=$! ++waitncatudp $netns1 ++n2 ncat -u 192.168.241.1 1111 <<<"X" ++read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]] ++kill $ncat_pid ++more_specific_key="$(pp wg genkey | pp wg pubkey)" ++n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32 ++n2 wg set wg0 listen-port 9997 ++exec 4< <(n1 ncat -l -u -p 1111) ++ncat_pid=$! ++waitncatudp $netns1 ++n2 ncat -u 192.168.241.1 1111 <<<"X" ++! read -r -N 1 -t 1 out <&4 || false ++kill $ncat_pid ++n1 wg set wg0 peer "$more_specific_key" remove ++[[ $(n1 wg show wg0 endpoints) == "$pub2 [::1]:9997" ]] ++ ++# Test that we can change private keys keys and immediately handshake ++n1 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") allowed-ips 192.168.241.2/32 endpoint 127.0.0.1:2 ++n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 ++n1 ping -W 1 -c 1 192.168.241.2 ++n1 wg set wg0 private-key <(echo "$key3") ++n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove ++n1 ping -W 1 -c 1 192.168.241.2 ++ ++ip1 link del wg0 ++ip2 link del wg0 ++ ++# Test using NAT. We now change the topology to this: ++# ┌────────────────────────────────────────┐ ┌────────────────────────────────────────────────┐ ┌────────────────────────────────────────┐ ++# │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │ ++# │ │ │ │ │ │ ++# │ ┌─────┐ ┌─────┐ │ │ ┌──────┐ ┌──────┐ │ │ ┌─────┐ ┌─────┐ │ ++# │ │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│ │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │ │ ++# │ ├─────┴──────────┐ ├─────┴──────────┐│ │ ├──────┴─────────┐ ├──────┴────────────┐ │ │ ├─────┴──────────┐ ├─────┴──────────┐ │ ++# │ │192.168.241.1/24│ │192.168.1.100/24││ │ │192.168.1.1/24 │ │10.0.0.1/24 │ │ │ │10.0.0.100/24 │ │192.168.241.2/24│ │ ++# │ │fd00::1/24 │ │ ││ │ │ │ │SNAT:192.168.1.0/24│ │ │ │ │ │fd00::2/24 │ │ ++# │ └────────────────┘ └────────────────┘│ │ └────────────────┘ └───────────────────┘ │ │ └────────────────┘ └────────────────┘ │ ++# └────────────────────────────────────────┘ └────────────────────────────────────────────────┘ └────────────────────────────────────────┘ ++ ++ip1 link add dev wg0 type wireguard ++ip2 link add dev wg0 type wireguard ++configure_peers ++ ++ip0 link add vethrc type veth peer name vethc ++ip0 link add vethrs type veth peer name veths ++ip0 link set vethc netns $netns1 ++ip0 link set veths netns $netns2 ++ip0 link set vethrc up ++ip0 link set vethrs up ++ip0 addr add 192.168.1.1/24 dev vethrc ++ip0 addr add 10.0.0.1/24 dev vethrs ++ip1 addr add 192.168.1.100/24 dev vethc ++ip1 link set vethc up ++ip1 route add default via 192.168.1.1 ++ip2 addr add 10.0.0.100/24 dev veths ++ip2 link set veths up ++waitiface $netns0 vethrc ++waitiface $netns0 vethrs ++waitiface $netns1 vethc ++waitiface $netns2 veths ++ ++n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward' ++n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout' ++n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream' ++n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1 ++ ++n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1 ++n1 ping -W 1 -c 1 192.168.241.2 ++n2 ping -W 1 -c 1 192.168.241.1 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]] ++# Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`). ++pp sleep 3 ++n2 ping -W 1 -c 1 192.168.241.1 ++n1 wg set wg0 peer "$pub2" persistent-keepalive 0 ++ ++# Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs. ++ip1 -6 addr add fc00::9/96 dev vethc ++ip1 -6 route add default via fc00::1 ++ip2 -4 addr add 192.168.99.7/32 dev wg0 ++ip2 -6 addr add abab::1111/128 dev wg0 ++n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111 ++ip1 -6 route add default dev wg0 table 51820 ++ip1 -6 rule add not fwmark 51820 table 51820 ++ip1 -6 rule add table main suppress_prefixlength 0 ++ip1 -4 route add default dev wg0 table 51820 ++ip1 -4 rule add not fwmark 51820 table 51820 ++ip1 -4 rule add table main suppress_prefixlength 0 ++# suppress_prefixlength only got added in 3.12, and we want to support 3.10+. ++if [[ $(ip1 -4 rule show all) == *suppress_prefixlength* ]]; then ++ # Flood the pings instead of sending just one, to trigger routing table reference counting bugs. ++ n1 ping -W 1 -c 100 -f 192.168.99.7 ++ n1 ping -W 1 -c 100 -f abab::1111 ++fi ++ ++n0 iptables -t nat -F ++ip0 link del vethrc ++ip0 link del vethrs ++ip1 link del wg0 ++ip2 link del wg0 ++ ++# Test that saddr routing is sticky but not too sticky, changing to this topology: ++# ┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐ ++# │ $ns1 namespace │ │ $ns2 namespace │ ++# │ │ │ │ ++# │ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ │ ++# │ │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │ │ ++# │ ├─────┴──────────┐ ├─────┴──────────┐│ │ ├─────┴──────────┐ ├─────┴──────────┐ │ ++# │ │192.168.241.1/24│ │10.0.0.1/24 ││ │ │10.0.0.2/24 │ │192.168.241.2/24│ │ ++# │ │fd00::1/24 │ │fd00:aa::1/96 ││ │ │fd00:aa::2/96 │ │fd00::2/24 │ │ ++# │ └────────────────┘ └────────────────┘│ │ └────────────────┘ └────────────────┘ │ ++# └────────────────────────────────────────┘ └────────────────────────────────────────┘ ++ ++ip1 link add dev wg0 type wireguard ++ip2 link add dev wg0 type wireguard ++configure_peers ++ip1 link add veth1 type veth peer name veth2 ++ip1 link set veth2 netns $netns2 ++n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad' ++n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad' ++n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad' ++n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad' ++n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries' ++ ++# First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed ++ip1 addr add 10.0.0.1/24 dev veth1 ++ip1 addr add fd00:aa::1/96 dev veth1 ++ip2 addr add 10.0.0.2/24 dev veth2 ++ip2 addr add fd00:aa::2/96 dev veth2 ++ip1 link set veth1 up ++ip2 link set veth2 up ++waitiface $netns1 veth1 ++waitiface $netns2 veth2 ++n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2 ++n1 ping -W 1 -c 1 192.168.241.2 ++ip1 addr add 10.0.0.10/24 dev veth1 ++ip1 addr del 10.0.0.1/24 dev veth1 ++n1 ping -W 1 -c 1 192.168.241.2 ++n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2 ++n1 ping -W 1 -c 1 192.168.241.2 ++ip1 addr add fd00:aa::10/96 dev veth1 ++ip1 addr del fd00:aa::1/96 dev veth1 ++n1 ping -W 1 -c 1 192.168.241.2 ++ ++# Now we show that we can successfully do reply to sender routing ++ip1 link set veth1 down ++ip2 link set veth2 down ++ip1 addr flush dev veth1 ++ip2 addr flush dev veth2 ++ip1 addr add 10.0.0.1/24 dev veth1 ++ip1 addr add 10.0.0.2/24 dev veth1 ++ip1 addr add fd00:aa::1/96 dev veth1 ++ip1 addr add fd00:aa::2/96 dev veth1 ++ip2 addr add 10.0.0.3/24 dev veth2 ++ip2 addr add fd00:aa::3/96 dev veth2 ++ip1 link set veth1 up ++ip2 link set veth2 up ++waitiface $netns1 veth1 ++waitiface $netns2 veth2 ++n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1 ++n2 ping -W 1 -c 1 192.168.241.1 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]] ++n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1 ++n2 ping -W 1 -c 1 192.168.241.1 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 [fd00:aa::1]:1" ]] ++n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1 ++n2 ping -W 1 -c 1 192.168.241.1 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.2:1" ]] ++n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1 ++n2 ping -W 1 -c 1 192.168.241.1 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 [fd00:aa::2]:1" ]] ++ ++# What happens if the inbound destination address belongs to a different interface as the default route? ++ip1 link add dummy0 type dummy ++ip1 addr add 10.50.0.1/24 dev dummy0 ++ip1 link set dummy0 up ++ip2 route add 10.50.0.0/24 dev veth2 ++n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1 ++n2 ping -W 1 -c 1 192.168.241.1 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 10.50.0.1:1" ]] ++ ++ip1 link del dummy0 ++ip1 addr flush dev veth1 ++ip2 addr flush dev veth2 ++ip1 route flush dev veth1 ++ip2 route flush dev veth2 ++ ++# Now we see what happens if another interface route takes precedence over an ongoing one ++ip1 link add veth3 type veth peer name veth4 ++ip1 link set veth4 netns $netns2 ++ip1 addr add 10.0.0.1/24 dev veth1 ++ip2 addr add 10.0.0.2/24 dev veth2 ++ip1 addr add 10.0.0.3/24 dev veth3 ++ip1 link set veth1 up ++ip2 link set veth2 up ++ip1 link set veth3 up ++ip2 link set veth4 up ++waitiface $netns1 veth1 ++waitiface $netns2 veth2 ++waitiface $netns1 veth3 ++waitiface $netns2 veth4 ++ip1 route flush dev veth1 ++ip1 route flush dev veth3 ++ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2 ++n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2 ++n1 ping -W 1 -c 1 192.168.241.2 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]] ++ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1 ++n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter' ++n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter' ++n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter' ++n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter' ++n1 ping -W 1 -c 1 192.168.241.2 ++[[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.3:1" ]] ++ ++ip1 link del veth1 ++ip1 link del veth3 ++ip1 link del wg0 ++ip2 link del wg0 ++ ++# We test that Netlink/IPC is working properly by doing things that usually cause split responses ++ip0 link add dev wg0 type wireguard ++config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" ) ++for a in {1..255}; do ++ for b in {0..255}; do ++ config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" ) ++ done ++done ++n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") ++i=0 ++for ip in $(n0 wg show wg0 allowed-ips); do ++ ((++i)) ++done ++((i == 255*256*2+1)) ++ip0 link del wg0 ++ip0 link add dev wg0 type wireguard ++config=( "[Interface]" "PrivateKey=$(wg genkey)" ) ++for a in {1..40}; do ++ config+=( "[Peer]" "PublicKey=$(wg genkey)" ) ++ for b in {1..52}; do ++ config+=( "AllowedIPs=$a.$b.0.0/16" ) ++ done ++done ++n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") ++i=0 ++while read -r line; do ++ j=0 ++ for ip in $line; do ++ ((++j)) ++ done ++ ((j == 53)) ++ ((++i)) ++done < <(n0 wg show wg0 allowed-ips) ++((i == 40)) ++ip0 link del wg0 ++ip0 link add wg0 type wireguard ++config=( ) ++for i in {1..29}; do ++ config+=( "[Peer]" "PublicKey=$(wg genkey)" ) ++done ++config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" ) ++n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") ++n0 wg showconf wg0 > /dev/null ++ip0 link del wg0 ++ ++allowedips=( ) ++for i in {1..197}; do ++ allowedips+=( abcd::$i ) ++done ++saved_ifs="$IFS" ++IFS=, ++allowedips="${allowedips[*]}" ++IFS="$saved_ifs" ++ip0 link add wg0 type wireguard ++n0 wg set wg0 peer "$pub1" ++n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips" ++{ ++ read -r pub allowedips ++ [[ $pub == "$pub1" && $allowedips == "(none)" ]] ++ read -r pub allowedips ++ [[ $pub == "$pub2" ]] ++ i=0 ++ for _ in $allowedips; do ++ ((++i)) ++ done ++ ((i == 197)) ++} < <(n0 wg show wg0 allowed-ips) ++ip0 link del wg0 ++ ++! n0 wg show doesnotexist || false ++ ++ip0 link add wg0 type wireguard ++n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") ++[[ $(n0 wg show wg0 private-key) == "$key1" ]] ++[[ $(n0 wg show wg0 preshared-keys) == "$pub2 $psk" ]] ++n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null ++[[ $(n0 wg show wg0 private-key) == "(none)" ]] ++[[ $(n0 wg show wg0 preshared-keys) == "$pub2 (none)" ]] ++n0 wg set wg0 peer "$pub2" ++n0 wg set wg0 private-key <(echo "$key2") ++[[ $(n0 wg show wg0 public-key) == "$pub2" ]] ++[[ -z $(n0 wg show wg0 peers) ]] ++n0 wg set wg0 peer "$pub2" ++[[ -z $(n0 wg show wg0 peers) ]] ++n0 wg set wg0 private-key <(echo "$key1") ++n0 wg set wg0 peer "$pub2" ++[[ $(n0 wg show wg0 peers) == "$pub2" ]] ++n0 wg set wg0 private-key <(echo "/${key1:1}") ++[[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]] ++n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0,10.0.0.0/8,100.0.0.0/10,172.16.0.0/12,192.168.0.0/16 ++n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0 ++n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75 ++n0 wg set wg0 peer "$pub2" allowed-ips ::/0 ++ip0 link del wg0 ++ ++declare -A objects ++while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do ++ [[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue ++ objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}" ++done < /dev/kmsg ++alldeleted=1 ++for object in "${!objects[@]}"; do ++ if [[ ${objects["$object"]} != *createddestroyed ]]; then ++ echo "Error: $object: merely ${objects["$object"]}" >&3 ++ alldeleted=0 ++ fi ++done ++[[ $alldeleted -eq 1 ]] ++pretty "" "Objects that were created were also destroyed." diff --git a/ipq806x/backport-5.4/080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch b/ipq806x/backport-5.4/080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch new file mode 100644 index 0000000..ca3853a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0073-wireguard-selftests-import-harness-makefile-for-test.patch @@ -0,0 +1,1078 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 15 Dec 2019 22:08:00 +0100 +Subject: [PATCH] wireguard: selftests: import harness makefile for test suite + +commit 65d88d04114bca7d85faebd5fed61069cb2b632c upstream. + +WireGuard has been using this on build.wireguard.com for the last +several years with considerable success. It allows for very quick and +iterative development cycles, and supports several platforms. + +To run the test suite on your current platform in QEMU: + + $ make -C tools/testing/selftests/wireguard/qemu -j$(nproc) + +To run it with KASAN and such turned on: + + $ DEBUG_KERNEL=yes make -C tools/testing/selftests/wireguard/qemu -j$(nproc) + +To run it emulated for another platform in QEMU: + + $ ARCH=arm make -C tools/testing/selftests/wireguard/qemu -j$(nproc) + +At the moment, we support aarch64_be, aarch64, arm, armeb, i686, m68k, +mips64, mips64el, mips, mipsel, powerpc64le, powerpc, and x86_64. + +The system supports incremental rebuilding, so it should be very fast to +change a single file and then test it out and have immediate feedback. + +This requires for the right toolchain and qemu to be installed prior. +I've had success with those from musl.cc. + +This is tailored for WireGuard at the moment, though later projects +might generalize it for other network testing. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + .../selftests/wireguard/qemu/.gitignore | 2 + + .../testing/selftests/wireguard/qemu/Makefile | 385 ++++++++++++++++++ + .../wireguard/qemu/arch/aarch64.config | 5 + + .../wireguard/qemu/arch/aarch64_be.config | 6 + + .../selftests/wireguard/qemu/arch/arm.config | 9 + + .../wireguard/qemu/arch/armeb.config | 10 + + .../selftests/wireguard/qemu/arch/i686.config | 5 + + .../selftests/wireguard/qemu/arch/m68k.config | 9 + + .../selftests/wireguard/qemu/arch/mips.config | 11 + + .../wireguard/qemu/arch/mips64.config | 14 + + .../wireguard/qemu/arch/mips64el.config | 15 + + .../wireguard/qemu/arch/mipsel.config | 12 + + .../wireguard/qemu/arch/powerpc.config | 10 + + .../wireguard/qemu/arch/powerpc64le.config | 12 + + .../wireguard/qemu/arch/x86_64.config | 5 + + .../selftests/wireguard/qemu/debug.config | 67 +++ + tools/testing/selftests/wireguard/qemu/init.c | 284 +++++++++++++ + .../selftests/wireguard/qemu/kernel.config | 86 ++++ + 18 files changed, 947 insertions(+) + create mode 100644 tools/testing/selftests/wireguard/qemu/.gitignore + create mode 100644 tools/testing/selftests/wireguard/qemu/Makefile + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/aarch64.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/aarch64_be.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/arm.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/armeb.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/i686.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/m68k.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mips.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mips64.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mips64el.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/mipsel.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/powerpc.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config + create mode 100644 tools/testing/selftests/wireguard/qemu/arch/x86_64.config + create mode 100644 tools/testing/selftests/wireguard/qemu/debug.config + create mode 100644 tools/testing/selftests/wireguard/qemu/init.c + create mode 100644 tools/testing/selftests/wireguard/qemu/kernel.config + +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/.gitignore +@@ -0,0 +1,2 @@ ++build/ ++distfiles/ +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/Makefile +@@ -0,0 +1,385 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ ++PWD := $(shell pwd) ++ ++CHOST := $(shell gcc -dumpmachine) ++ifneq (,$(ARCH)) ++CBUILD := $(subst -gcc,,$(lastword $(subst /, ,$(firstword $(wildcard $(foreach bindir,$(subst :, ,$(PATH)),$(bindir)/$(ARCH)-*-gcc)))))) ++ifeq (,$(CBUILD)) ++$(error The toolchain for $(ARCH) is not installed) ++endif ++else ++CBUILD := $(CHOST) ++ARCH := $(firstword $(subst -, ,$(CBUILD))) ++endif ++ ++# Set these from the environment to override ++KERNEL_PATH ?= $(PWD)/../../../../.. ++BUILD_PATH ?= $(PWD)/build/$(ARCH) ++DISTFILES_PATH ?= $(PWD)/distfiles ++NR_CPUS ?= 4 ++ ++MIRROR := https://download.wireguard.com/qemu-test/distfiles/ ++ ++default: qemu ++ ++# variable name, tarball project name, version, tarball extension, default URI base ++define tar_download = ++$(1)_VERSION := $(3) ++$(1)_NAME := $(2)-$$($(1)_VERSION) ++$(1)_TAR := $(DISTFILES_PATH)/$$($(1)_NAME)$(4) ++$(1)_PATH := $(BUILD_PATH)/$$($(1)_NAME) ++$(call file_download,$$($(1)_NAME)$(4),$(5),$(6)) ++endef ++ ++define file_download = ++$(DISTFILES_PATH)/$(1): ++ mkdir -p $(DISTFILES_PATH) ++ flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -t inf --retry-on-http-error=404 -O $$@.tmp $(2)$(1) || rm -f $$@.tmp' ++ if echo "$(3) $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi ++endef ++ ++$(eval $(call tar_download,MUSL,musl,1.1.20,.tar.gz,https://www.musl-libc.org/releases/,44be8771d0e6c6b5f82dd15662eb2957c9a3173a19a8b49966ac0542bbd40d61)) ++$(eval $(call tar_download,LIBMNL,libmnl,1.0.4,.tar.bz2,https://www.netfilter.org/projects/libmnl/files/,171f89699f286a5854b72b91d06e8f8e3683064c5901fb09d954a9ab6f551f81)) ++$(eval $(call tar_download,IPERF,iperf,3.1.7,.tar.gz,http://downloads.es.net/pub/iperf/,a4ef73406fe92250602b8da2ae89ec53211f805df97a1d1d629db5a14043734f)) ++$(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d)) ++$(eval $(call tar_download,IPROUTE2,iproute2,5.1.0,.tar.gz,https://www.kernel.org/pub/linux/utils/net/iproute2/,9b43707d6075ecdca14803ca8ce0c8553848c49fa1586d12fd508d66577243f2)) ++$(eval $(call tar_download,IPTABLES,iptables,1.6.1,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,0fc2d7bd5d7be11311726466789d4c65fb4c8e096c9182b56ce97440864f0cf5)) ++$(eval $(call tar_download,NMAP,nmap,7.60,.tar.bz2,https://nmap.org/dist/,a8796ecc4fa6c38aad6139d9515dc8113023a82e9d787e5a5fb5fa1b05516f21)) ++$(eval $(call tar_download,IPUTILS,iputils,s20161105,.tar.gz,https://github.com/iputils/iputils/archive/s20161105.tar.gz/#,f813092f03d17294fd23544b129b95cdb87fe19f7970a51908a6b88509acad8a)) ++$(eval $(call tar_download,WIREGUARD_TOOLS,WireGuard,0.0.20191212,.tar.xz,https://git.zx2c4.com/WireGuard/snapshot/,b0d718380f7a8822b2f12d75e462fa4eafa3a77871002981f367cd4fe2a1b071)) ++ ++KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug) ++rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) ++WIREGUARD_SOURCES := $(call rwildcard,$(KERNEL_PATH)/drivers/net/wireguard/,*) ++ ++export CFLAGS ?= -O3 -pipe ++export LDFLAGS ?= ++export CPPFLAGS := -I$(BUILD_PATH)/include ++ ++ifeq ($(CHOST),$(CBUILD)) ++CROSS_COMPILE_FLAG := --host=$(CHOST) ++NOPIE_GCC := gcc -fno-PIE ++CFLAGS += -march=native ++STRIP := strip ++else ++$(info Cross compilation: building for $(CBUILD) using $(CHOST)) ++CROSS_COMPILE_FLAG := --build=$(CBUILD) --host=$(CHOST) ++export CROSS_COMPILE=$(CBUILD)- ++NOPIE_GCC := $(CBUILD)-gcc -fno-PIE ++STRIP := $(CBUILD)-strip ++endif ++ifeq ($(ARCH),aarch64) ++QEMU_ARCH := aarch64 ++KERNEL_ARCH := arm64 ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm ++else ++QEMU_MACHINE := -cpu cortex-a53 -machine virt ++CFLAGS += -march=armv8-a -mtune=cortex-a53 ++endif ++else ifeq ($(ARCH),aarch64_be) ++QEMU_ARCH := aarch64 ++KERNEL_ARCH := arm64 ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm ++else ++QEMU_MACHINE := -cpu cortex-a53 -machine virt ++CFLAGS += -march=armv8-a -mtune=cortex-a53 ++endif ++else ifeq ($(ARCH),arm) ++QEMU_ARCH := arm ++KERNEL_ARCH := arm ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm ++else ++QEMU_MACHINE := -cpu cortex-a15 -machine virt ++CFLAGS += -march=armv7-a -mtune=cortex-a15 -mabi=aapcs-linux ++endif ++else ifeq ($(ARCH),armeb) ++QEMU_ARCH := arm ++KERNEL_ARCH := arm ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm ++else ++QEMU_MACHINE := -cpu cortex-a15 -machine virt ++CFLAGS += -march=armv7-a -mabi=aapcs-linux # We don't pass -mtune=cortex-a15 due to a compiler bug on big endian. ++LDFLAGS += -Wl,--be8 ++endif ++else ifeq ($(ARCH),x86_64) ++QEMU_ARCH := x86_64 ++KERNEL_ARCH := x86_64 ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine q35,accel=kvm ++else ++QEMU_MACHINE := -cpu Skylake-Server -machine q35 ++CFLAGS += -march=skylake-avx512 ++endif ++else ifeq ($(ARCH),i686) ++QEMU_ARCH := i386 ++KERNEL_ARCH := x86 ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage ++ifeq ($(subst i686,x86_64,$(CBUILD)),$(CHOST)) ++QEMU_MACHINE := -cpu host -machine q35,accel=kvm ++else ++QEMU_MACHINE := -cpu coreduo -machine q35 ++CFLAGS += -march=prescott ++endif ++else ifeq ($(ARCH),mips64) ++QEMU_ARCH := mips64 ++KERNEL_ARCH := mips ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine malta,accel=kvm ++CFLAGS += -EB ++else ++QEMU_MACHINE := -cpu MIPS64R2-generic -machine malta -smp 1 ++CFLAGS += -march=mips64r2 -EB ++endif ++else ifeq ($(ARCH),mips64el) ++QEMU_ARCH := mips64el ++KERNEL_ARCH := mips ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine malta,accel=kvm ++CFLAGS += -EL ++else ++QEMU_MACHINE := -cpu MIPS64R2-generic -machine malta -smp 1 ++CFLAGS += -march=mips64r2 -EL ++endif ++else ifeq ($(ARCH),mips) ++QEMU_ARCH := mips ++KERNEL_ARCH := mips ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine malta,accel=kvm ++CFLAGS += -EB ++else ++QEMU_MACHINE := -cpu 24Kf -machine malta -smp 1 ++CFLAGS += -march=mips32r2 -EB ++endif ++else ifeq ($(ARCH),mipsel) ++QEMU_ARCH := mipsel ++KERNEL_ARCH := mips ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host -machine malta,accel=kvm ++CFLAGS += -EL ++else ++QEMU_MACHINE := -cpu 24Kf -machine malta -smp 1 ++CFLAGS += -march=mips32r2 -EL ++endif ++else ifeq ($(ARCH),powerpc64le) ++QEMU_ARCH := ppc64 ++KERNEL_ARCH := powerpc ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host,accel=kvm -machine pseries ++else ++QEMU_MACHINE := -machine pseries ++endif ++CFLAGS += -mcpu=powerpc64le -mlong-double-64 ++else ifeq ($(ARCH),powerpc) ++QEMU_ARCH := ppc ++KERNEL_ARCH := powerpc ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/powerpc/boot/uImage ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host,accel=kvm -machine ppce500 ++else ++QEMU_MACHINE := -machine ppce500 ++endif ++CFLAGS += -mcpu=powerpc -mlong-double-64 -msecure-plt ++else ifeq ($(ARCH),m68k) ++QEMU_ARCH := m68k ++KERNEL_ARCH := m68k ++KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux ++ifeq ($(CHOST),$(CBUILD)) ++QEMU_MACHINE := -cpu host,accel=kvm -machine q800 ++else ++QEMU_MACHINE := -machine q800 ++endif ++else ++$(error I only build: x86_64, i686, arm, armeb, aarch64, aarch64_be, mips, mipsel, mips64, mips64el, powerpc64le, powerpc, m68k) ++endif ++ ++REAL_CC := $(CBUILD)-gcc ++MUSL_CC := $(BUILD_PATH)/musl-gcc ++export CC := $(MUSL_CC) ++USERSPACE_DEPS := $(MUSL_CC) $(BUILD_PATH)/include/.installed $(BUILD_PATH)/include/linux/.installed ++ ++build: $(KERNEL_BZIMAGE) ++qemu: $(KERNEL_BZIMAGE) ++ rm -f $(BUILD_PATH)/result ++ timeout --foreground 20m qemu-system-$(QEMU_ARCH) \ ++ -nodefaults \ ++ -nographic \ ++ -smp $(NR_CPUS) \ ++ $(QEMU_MACHINE) \ ++ -m $$(grep -q CONFIG_DEBUG_KMEMLEAK=y $(KERNEL_BUILD_PATH)/.config && echo 1G || echo 256M) \ ++ -serial stdio \ ++ -serial file:$(BUILD_PATH)/result \ ++ -no-reboot \ ++ -monitor none \ ++ -kernel $< ++ grep -Fq success $(BUILD_PATH)/result ++ ++$(BUILD_PATH)/init-cpio-spec.txt: ++ mkdir -p $(BUILD_PATH) ++ echo "file /init $(BUILD_PATH)/init 755 0 0" > $@ ++ echo "file /init.sh $(PWD)/../netns.sh 755 0 0" >> $@ ++ echo "dir /dev 755 0 0" >> $@ ++ echo "nod /dev/console 644 0 0 c 5 1" >> $@ ++ echo "dir /bin 755 0 0" >> $@ ++ echo "file /bin/iperf3 $(IPERF_PATH)/src/iperf3 755 0 0" >> $@ ++ echo "file /bin/wg $(WIREGUARD_TOOLS_PATH)/src/tools/wg 755 0 0" >> $@ ++ echo "file /bin/bash $(BASH_PATH)/bash 755 0 0" >> $@ ++ echo "file /bin/ip $(IPROUTE2_PATH)/ip/ip 755 0 0" >> $@ ++ echo "file /bin/ss $(IPROUTE2_PATH)/misc/ss 755 0 0" >> $@ ++ echo "file /bin/ping $(IPUTILS_PATH)/ping 755 0 0" >> $@ ++ echo "file /bin/ncat $(NMAP_PATH)/ncat/ncat 755 0 0" >> $@ ++ echo "file /bin/xtables-multi $(IPTABLES_PATH)/iptables/xtables-multi 755 0 0" >> $@ ++ echo "slink /bin/iptables xtables-multi 777 0 0" >> $@ ++ echo "slink /bin/ping6 ping 777 0 0" >> $@ ++ echo "dir /lib 755 0 0" >> $@ ++ echo "file /lib/libc.so $(MUSL_PATH)/lib/libc.so 755 0 0" >> $@ ++ echo "slink /lib/ld-linux.so.1 libc.so 777 0 0" >> $@ ++ ++$(KERNEL_BUILD_PATH)/.config: kernel.config arch/$(ARCH).config ++ mkdir -p $(KERNEL_BUILD_PATH) ++ cp kernel.config $(KERNEL_BUILD_PATH)/minimal.config ++ printf 'CONFIG_NR_CPUS=$(NR_CPUS)\nCONFIG_INITRAMFS_SOURCE="$(BUILD_PATH)/init-cpio-spec.txt"\n' >> $(KERNEL_BUILD_PATH)/minimal.config ++ cat arch/$(ARCH).config >> $(KERNEL_BUILD_PATH)/minimal.config ++ $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) allnoconfig ++ cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config $(KERNEL_BUILD_PATH)/minimal.config ++ $(if $(findstring yes,$(DEBUG_KERNEL)),cp debug.config $(KERNEL_BUILD_PATH) && cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config debug.config,) ++ ++$(KERNEL_BZIMAGE): $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(MUSL_PATH)/lib/libc.so $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/tools/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES) ++ $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)" ++ ++$(BUILD_PATH)/include/linux/.installed: | $(KERNEL_BUILD_PATH)/.config ++ $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) INSTALL_HDR_PATH=$(BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) headers_install ++ touch $@ ++ ++$(MUSL_PATH)/lib/libc.so: $(MUSL_TAR) ++ mkdir -p $(BUILD_PATH) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ cd $(MUSL_PATH) && CC=$(REAL_CC) ./configure --prefix=/ --disable-static --build=$(CBUILD) ++ $(MAKE) -C $(MUSL_PATH) ++ $(STRIP) -s $@ ++ ++$(BUILD_PATH)/include/.installed: $(MUSL_PATH)/lib/libc.so ++ $(MAKE) -C $(MUSL_PATH) DESTDIR=$(BUILD_PATH) install-headers ++ touch $@ ++ ++$(MUSL_CC): $(MUSL_PATH)/lib/libc.so ++ sh $(MUSL_PATH)/tools/musl-gcc.specs.sh $(BUILD_PATH)/include $(MUSL_PATH)/lib /lib/ld-linux.so.1 > $(BUILD_PATH)/musl-gcc.specs ++ printf '#!/bin/sh\nexec "$(REAL_CC)" --specs="$(BUILD_PATH)/musl-gcc.specs" -fno-stack-protector -no-pie "$$@"\n' > $(BUILD_PATH)/musl-gcc ++ chmod +x $(BUILD_PATH)/musl-gcc ++ ++$(IPERF_PATH)/.installed: $(IPERF_TAR) ++ mkdir -p $(BUILD_PATH) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ sed -i '1s/^/#include /' $(IPERF_PATH)/src/cjson.h $(IPERF_PATH)/src/timer.h ++ sed -i -r 's/-p?g//g' $(IPERF_PATH)/src/Makefile* ++ touch $@ ++ ++$(IPERF_PATH)/src/iperf3: | $(IPERF_PATH)/.installed $(USERSPACE_DEPS) ++ cd $(IPERF_PATH) && CFLAGS="$(CFLAGS) -D_GNU_SOURCE" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared ++ $(MAKE) -C $(IPERF_PATH) ++ $(STRIP) -s $@ ++ ++$(LIBMNL_PATH)/.installed: $(LIBMNL_TAR) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ touch $@ ++ ++$(LIBMNL_PATH)/src/.libs/libmnl.a: | $(LIBMNL_PATH)/.installed $(USERSPACE_DEPS) ++ cd $(LIBMNL_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared ++ $(MAKE) -C $(LIBMNL_PATH) ++ sed -i 's:prefix=.*:prefix=$(LIBMNL_PATH):' $(LIBMNL_PATH)/libmnl.pc ++ ++$(WIREGUARD_TOOLS_PATH)/.installed: $(WIREGUARD_TOOLS_TAR) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ touch $@ ++ ++$(WIREGUARD_TOOLS_PATH)/src/tools/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) ++ LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src/tools LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg ++ $(STRIP) -s $@ ++ ++$(BUILD_PATH)/init: init.c | $(USERSPACE_DEPS) ++ mkdir -p $(BUILD_PATH) ++ $(MUSL_CC) -o $@ $(CFLAGS) $(LDFLAGS) -std=gnu11 $< ++ $(STRIP) -s $@ ++ ++$(IPUTILS_PATH)/.installed: $(IPUTILS_TAR) ++ mkdir -p $(BUILD_PATH) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ touch $@ ++ ++$(IPUTILS_PATH)/ping: | $(IPUTILS_PATH)/.installed $(USERSPACE_DEPS) ++ $(MAKE) -C $(IPUTILS_PATH) USE_CAP=no USE_IDN=no USE_NETTLE=no USE_CRYPTO=no ping ++ $(STRIP) -s $@ ++ ++$(BASH_PATH)/.installed: $(BASH_TAR) ++ mkdir -p $(BUILD_PATH) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ touch $@ ++ ++$(BASH_PATH)/bash: | $(BASH_PATH)/.installed $(USERSPACE_DEPS) ++ cd $(BASH_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --without-bash-malloc --disable-debugger --disable-help-builtin --disable-history --disable-multibyte --disable-progcomp --disable-readline --disable-mem-scramble ++ $(MAKE) -C $(BASH_PATH) ++ $(STRIP) -s $@ ++ ++$(IPROUTE2_PATH)/.installed: $(IPROUTE2_TAR) ++ mkdir -p $(BUILD_PATH) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ printf 'CC:=$(CC)\nPKG_CONFIG:=pkg-config\nTC_CONFIG_XT:=n\nTC_CONFIG_ATM:=n\nTC_CONFIG_IPSET:=n\nIP_CONFIG_SETNS:=y\nHAVE_ELF:=n\nHAVE_MNL:=y\nHAVE_BERKELEY_DB:=n\nHAVE_LATEX:=n\nHAVE_PDFLATEX:=n\nCFLAGS+=-DHAVE_SETNS -DHAVE_LIBMNL -I$(LIBMNL_PATH)/include\nLDLIBS+=-lmnl' > $(IPROUTE2_PATH)/config.mk ++ printf 'lib: snapshot\n\t$$(MAKE) -C lib\nip/ip: lib\n\t$$(MAKE) -C ip ip\nmisc/ss: lib\n\t$$(MAKE) -C misc ss\n' >> $(IPROUTE2_PATH)/Makefile ++ touch $@ ++ ++$(IPROUTE2_PATH)/ip/ip: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) ++ LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ ip/ip ++ $(STRIP) -s $(IPROUTE2_PATH)/ip/ip ++ ++$(IPROUTE2_PATH)/misc/ss: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) ++ LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ misc/ss ++ $(STRIP) -s $(IPROUTE2_PATH)/misc/ss ++ ++$(IPTABLES_PATH)/.installed: $(IPTABLES_TAR) ++ mkdir -p $(BUILD_PATH) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ sed -i -e "/nfnetlink=[01]/s:=[01]:=0:" -e "/nfconntrack=[01]/s:=[01]:=0:" $(IPTABLES_PATH)/configure ++ touch $@ ++ ++$(IPTABLES_PATH)/iptables/xtables-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) ++ cd $(IPTABLES_PATH) && PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --with-kernel=$(BUILD_PATH)/include ++ $(MAKE) -C $(IPTABLES_PATH) ++ $(STRIP) -s $@ ++ ++$(NMAP_PATH)/.installed: $(NMAP_TAR) ++ mkdir -p $(BUILD_PATH) ++ flock -s $<.lock tar -C $(BUILD_PATH) -xf $< ++ touch $@ ++ ++$(NMAP_PATH)/ncat/ncat: | $(NMAP_PATH)/.installed $(USERSPACE_DEPS) ++ cd $(NMAP_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --without-ndiff --without-zenmap --without-nping --with-libpcap=included --with-libpcre=included --with-libdnet=included --without-liblua --with-liblinear=included --without-nmap-update --without-openssl --with-pcap=linux ++ $(MAKE) -C $(NMAP_PATH) build-ncat ++ $(STRIP) -s $@ ++ ++clean: ++ rm -rf $(BUILD_PATH) ++ ++distclean: clean ++ rm -rf $(DISTFILES_PATH) ++ ++menuconfig: $(KERNEL_BUILD_PATH)/.config ++ $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)" menuconfig ++ ++.PHONY: qemu build clean distclean menuconfig ++.DELETE_ON_ERROR: +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/aarch64.config +@@ -0,0 +1,5 @@ ++CONFIG_SERIAL_AMBA_PL011=y ++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1" ++CONFIG_FRAME_WARN=1280 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/aarch64_be.config +@@ -0,0 +1,6 @@ ++CONFIG_CPU_BIG_ENDIAN=y ++CONFIG_SERIAL_AMBA_PL011=y ++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1" ++CONFIG_FRAME_WARN=1280 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/arm.config +@@ -0,0 +1,9 @@ ++CONFIG_MMU=y ++CONFIG_ARCH_MULTI_V7=y ++CONFIG_ARCH_VIRT=y ++CONFIG_THUMB2_KERNEL=n ++CONFIG_SERIAL_AMBA_PL011=y ++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1" ++CONFIG_FRAME_WARN=1024 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/armeb.config +@@ -0,0 +1,10 @@ ++CONFIG_MMU=y ++CONFIG_ARCH_MULTI_V7=y ++CONFIG_ARCH_VIRT=y ++CONFIG_THUMB2_KERNEL=n ++CONFIG_SERIAL_AMBA_PL011=y ++CONFIG_SERIAL_AMBA_PL011_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyAMA0 wg.success=ttyAMA1" ++CONFIG_CPU_BIG_ENDIAN=y ++CONFIG_FRAME_WARN=1024 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/i686.config +@@ -0,0 +1,5 @@ ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1024 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/m68k.config +@@ -0,0 +1,9 @@ ++CONFIG_MMU=y ++CONFIG_M68040=y ++CONFIG_MAC=y ++CONFIG_SERIAL_PMACZILOG=y ++CONFIG_SERIAL_PMACZILOG_TTYS=y ++CONFIG_SERIAL_PMACZILOG_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1024 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/mips.config +@@ -0,0 +1,11 @@ ++CONFIG_CPU_MIPS32_R2=y ++CONFIG_MIPS_MALTA=y ++CONFIG_MIPS_CPS=y ++CONFIG_MIPS_FP_SUPPORT=y ++CONFIG_POWER_RESET=y ++CONFIG_POWER_RESET_SYSCON=y ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1024 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/mips64.config +@@ -0,0 +1,14 @@ ++CONFIG_64BIT=y ++CONFIG_CPU_MIPS64_R2=y ++CONFIG_MIPS32_N32=y ++CONFIG_CPU_HAS_MSA=y ++CONFIG_MIPS_MALTA=y ++CONFIG_MIPS_CPS=y ++CONFIG_MIPS_FP_SUPPORT=y ++CONFIG_POWER_RESET=y ++CONFIG_POWER_RESET_SYSCON=y ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1280 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/mips64el.config +@@ -0,0 +1,15 @@ ++CONFIG_64BIT=y ++CONFIG_CPU_MIPS64_R2=y ++CONFIG_MIPS32_N32=y ++CONFIG_CPU_HAS_MSA=y ++CONFIG_MIPS_MALTA=y ++CONFIG_CPU_LITTLE_ENDIAN=y ++CONFIG_MIPS_CPS=y ++CONFIG_MIPS_FP_SUPPORT=y ++CONFIG_POWER_RESET=y ++CONFIG_POWER_RESET_SYSCON=y ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1280 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/mipsel.config +@@ -0,0 +1,12 @@ ++CONFIG_CPU_MIPS32_R2=y ++CONFIG_MIPS_MALTA=y ++CONFIG_CPU_LITTLE_ENDIAN=y ++CONFIG_MIPS_CPS=y ++CONFIG_MIPS_FP_SUPPORT=y ++CONFIG_POWER_RESET=y ++CONFIG_POWER_RESET_SYSCON=y ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1024 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/powerpc.config +@@ -0,0 +1,10 @@ ++CONFIG_PPC_QEMU_E500=y ++CONFIG_FSL_SOC_BOOKE=y ++CONFIG_PPC_85xx=y ++CONFIG_PHYS_64BIT=y ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_MATH_EMULATION=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1024 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config +@@ -0,0 +1,12 @@ ++CONFIG_PPC64=y ++CONFIG_PPC_PSERIES=y ++CONFIG_ALTIVEC=y ++CONFIG_VSX=y ++CONFIG_PPC_OF_BOOT_TRAMPOLINE=y ++CONFIG_PPC_RADIX_MMU=y ++CONFIG_HVC_CONSOLE=y ++CONFIG_CPU_LITTLE_ENDIAN=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=hvc0 wg.success=hvc1" ++CONFIG_SECTION_MISMATCH_WARN_ONLY=y ++CONFIG_FRAME_WARN=1280 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/arch/x86_64.config +@@ -0,0 +1,5 @@ ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_CMDLINE_BOOL=y ++CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" ++CONFIG_FRAME_WARN=1280 +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/debug.config +@@ -0,0 +1,67 @@ ++CONFIG_LOCALVERSION="-debug" ++CONFIG_ENABLE_WARN_DEPRECATED=y ++CONFIG_ENABLE_MUST_CHECK=y ++CONFIG_FRAME_POINTER=y ++CONFIG_STACK_VALIDATION=y ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_INFO=y ++CONFIG_DEBUG_INFO_DWARF4=y ++CONFIG_PAGE_EXTENSION=y ++CONFIG_PAGE_POISONING=y ++CONFIG_DEBUG_OBJECTS=y ++CONFIG_DEBUG_OBJECTS_FREE=y ++CONFIG_DEBUG_OBJECTS_TIMERS=y ++CONFIG_DEBUG_OBJECTS_WORK=y ++CONFIG_DEBUG_OBJECTS_RCU_HEAD=y ++CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y ++CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1 ++CONFIG_SLUB_DEBUG_ON=y ++CONFIG_DEBUG_VM=y ++CONFIG_DEBUG_MEMORY_INIT=y ++CONFIG_HAVE_DEBUG_STACKOVERFLOW=y ++CONFIG_DEBUG_STACKOVERFLOW=y ++CONFIG_HAVE_ARCH_KMEMCHECK=y ++CONFIG_HAVE_ARCH_KASAN=y ++CONFIG_KASAN=y ++CONFIG_KASAN_INLINE=y ++CONFIG_UBSAN=y ++CONFIG_UBSAN_SANITIZE_ALL=y ++CONFIG_UBSAN_NO_ALIGNMENT=y ++CONFIG_UBSAN_NULL=y ++CONFIG_DEBUG_KMEMLEAK=y ++CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=8192 ++CONFIG_DEBUG_STACK_USAGE=y ++CONFIG_DEBUG_SHIRQ=y ++CONFIG_WQ_WATCHDOG=y ++CONFIG_SCHED_DEBUG=y ++CONFIG_SCHED_INFO=y ++CONFIG_SCHEDSTATS=y ++CONFIG_SCHED_STACK_END_CHECK=y ++CONFIG_DEBUG_TIMEKEEPING=y ++CONFIG_TIMER_STATS=y ++CONFIG_DEBUG_PREEMPT=y ++CONFIG_DEBUG_RT_MUTEXES=y ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_MUTEXES=y ++CONFIG_DEBUG_LOCK_ALLOC=y ++CONFIG_PROVE_LOCKING=y ++CONFIG_LOCKDEP=y ++CONFIG_DEBUG_ATOMIC_SLEEP=y ++CONFIG_TRACE_IRQFLAGS=y ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_LIST=y ++CONFIG_DEBUG_PI_LIST=y ++CONFIG_PROVE_RCU=y ++CONFIG_SPARSE_RCU_POINTER=y ++CONFIG_RCU_CPU_STALL_TIMEOUT=21 ++CONFIG_RCU_TRACE=y ++CONFIG_RCU_EQS_DEBUG=y ++CONFIG_USER_STACKTRACE_SUPPORT=y ++CONFIG_DEBUG_SG=y ++CONFIG_DEBUG_NOTIFIERS=y ++CONFIG_DOUBLEFAULT=y ++CONFIG_X86_DEBUG_FPU=y ++CONFIG_DEBUG_SECTION_MISMATCH=y ++CONFIG_DEBUG_PAGEALLOC=y ++CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y ++CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/init.c +@@ -0,0 +1,284 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++__attribute__((noreturn)) static void poweroff(void) ++{ ++ fflush(stdout); ++ fflush(stderr); ++ reboot(RB_AUTOBOOT); ++ sleep(30); ++ fprintf(stderr, "\x1b[37m\x1b[41m\x1b[1mFailed to power off!!!\x1b[0m\n"); ++ exit(1); ++} ++ ++static void panic(const char *what) ++{ ++ fprintf(stderr, "\n\n\x1b[37m\x1b[41m\x1b[1mSOMETHING WENT HORRIBLY WRONG\x1b[0m\n\n \x1b[31m\x1b[1m%s: %s\x1b[0m\n\n\x1b[37m\x1b[44m\x1b[1mPower off...\x1b[0m\n\n", what, strerror(errno)); ++ poweroff(); ++} ++ ++#define pretty_message(msg) puts("\x1b[32m\x1b[1m" msg "\x1b[0m") ++ ++static void print_banner(void) ++{ ++ struct utsname utsname; ++ int len; ++ ++ if (uname(&utsname) < 0) ++ panic("uname"); ++ ++ len = strlen(" WireGuard Test Suite on ") + strlen(utsname.sysname) + strlen(utsname.release) + strlen(utsname.machine); ++ printf("\x1b[45m\x1b[33m\x1b[1m%*.s\x1b[0m\n\x1b[45m\x1b[33m\x1b[1m WireGuard Test Suite on %s %s %s \x1b[0m\n\x1b[45m\x1b[33m\x1b[1m%*.s\x1b[0m\n\n", len, "", utsname.sysname, utsname.release, utsname.machine, len, ""); ++} ++ ++static void seed_rng(void) ++{ ++ int fd; ++ struct { ++ int entropy_count; ++ int buffer_size; ++ unsigned char buffer[256]; ++ } entropy = { ++ .entropy_count = sizeof(entropy.buffer) * 8, ++ .buffer_size = sizeof(entropy.buffer), ++ .buffer = "Adding real entropy is not actually important for these tests. Don't try this at home, kids!" ++ }; ++ ++ if (mknod("/dev/urandom", S_IFCHR | 0644, makedev(1, 9))) ++ panic("mknod(/dev/urandom)"); ++ fd = open("/dev/urandom", O_WRONLY); ++ if (fd < 0) ++ panic("open(urandom)"); ++ for (int i = 0; i < 256; ++i) { ++ if (ioctl(fd, RNDADDENTROPY, &entropy) < 0) ++ panic("ioctl(urandom)"); ++ } ++ close(fd); ++} ++ ++static void mount_filesystems(void) ++{ ++ pretty_message("[+] Mounting filesystems..."); ++ mkdir("/dev", 0755); ++ mkdir("/proc", 0755); ++ mkdir("/sys", 0755); ++ mkdir("/tmp", 0755); ++ mkdir("/run", 0755); ++ mkdir("/var", 0755); ++ if (mount("none", "/dev", "devtmpfs", 0, NULL)) ++ panic("devtmpfs mount"); ++ if (mount("none", "/proc", "proc", 0, NULL)) ++ panic("procfs mount"); ++ if (mount("none", "/sys", "sysfs", 0, NULL)) ++ panic("sysfs mount"); ++ if (mount("none", "/tmp", "tmpfs", 0, NULL)) ++ panic("tmpfs mount"); ++ if (mount("none", "/run", "tmpfs", 0, NULL)) ++ panic("tmpfs mount"); ++ if (mount("none", "/sys/kernel/debug", "debugfs", 0, NULL)) ++ ; /* Not a problem if it fails.*/ ++ if (symlink("/run", "/var/run")) ++ panic("run symlink"); ++ if (symlink("/proc/self/fd", "/dev/fd")) ++ panic("fd symlink"); ++} ++ ++static void enable_logging(void) ++{ ++ int fd; ++ pretty_message("[+] Enabling logging..."); ++ fd = open("/proc/sys/kernel/printk", O_WRONLY); ++ if (fd >= 0) { ++ if (write(fd, "9\n", 2) != 2) ++ panic("write(printk)"); ++ close(fd); ++ } ++ fd = open("/proc/sys/debug/exception-trace", O_WRONLY); ++ if (fd >= 0) { ++ if (write(fd, "1\n", 2) != 2) ++ panic("write(exception-trace)"); ++ close(fd); ++ } ++ fd = open("/proc/sys/kernel/panic_on_warn", O_WRONLY); ++ if (fd >= 0) { ++ if (write(fd, "1\n", 2) != 2) ++ panic("write(panic_on_warn)"); ++ close(fd); ++ } ++} ++ ++static void kmod_selftests(void) ++{ ++ FILE *file; ++ char line[2048], *start, *pass; ++ bool success = true; ++ pretty_message("[+] Module self-tests:"); ++ file = fopen("/proc/kmsg", "r"); ++ if (!file) ++ panic("fopen(kmsg)"); ++ if (fcntl(fileno(file), F_SETFL, O_NONBLOCK) < 0) ++ panic("fcntl(kmsg, nonblock)"); ++ while (fgets(line, sizeof(line), file)) { ++ start = strstr(line, "wireguard: "); ++ if (!start) ++ continue; ++ start += 11; ++ *strchrnul(start, '\n') = '\0'; ++ if (strstr(start, "www.wireguard.com")) ++ break; ++ pass = strstr(start, ": pass"); ++ if (!pass || pass[6] != '\0') { ++ success = false; ++ printf(" \x1b[31m* %s\x1b[0m\n", start); ++ } else ++ printf(" \x1b[32m* %s\x1b[0m\n", start); ++ } ++ fclose(file); ++ if (!success) { ++ puts("\x1b[31m\x1b[1m[-] Tests failed! \u2639\x1b[0m"); ++ poweroff(); ++ } ++} ++ ++static void launch_tests(void) ++{ ++ char cmdline[4096], *success_dev; ++ int status, fd; ++ pid_t pid; ++ ++ pretty_message("[+] Launching tests..."); ++ pid = fork(); ++ if (pid == -1) ++ panic("fork"); ++ else if (pid == 0) { ++ execl("/init.sh", "init", NULL); ++ panic("exec"); ++ } ++ if (waitpid(pid, &status, 0) < 0) ++ panic("waitpid"); ++ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { ++ pretty_message("[+] Tests successful! :-)"); ++ fd = open("/proc/cmdline", O_RDONLY); ++ if (fd < 0) ++ panic("open(/proc/cmdline)"); ++ if (read(fd, cmdline, sizeof(cmdline) - 1) <= 0) ++ panic("read(/proc/cmdline)"); ++ cmdline[sizeof(cmdline) - 1] = '\0'; ++ for (success_dev = strtok(cmdline, " \n"); success_dev; success_dev = strtok(NULL, " \n")) { ++ if (strncmp(success_dev, "wg.success=", 11)) ++ continue; ++ memcpy(success_dev + 11 - 5, "/dev/", 5); ++ success_dev += 11 - 5; ++ break; ++ } ++ if (!success_dev || !strlen(success_dev)) ++ panic("Unable to find success device"); ++ ++ fd = open(success_dev, O_WRONLY); ++ if (fd < 0) ++ panic("open(success_dev)"); ++ if (write(fd, "success\n", 8) != 8) ++ panic("write(success_dev)"); ++ close(fd); ++ } else { ++ const char *why = "unknown cause"; ++ int what = -1; ++ ++ if (WIFEXITED(status)) { ++ why = "exit code"; ++ what = WEXITSTATUS(status); ++ } else if (WIFSIGNALED(status)) { ++ why = "signal"; ++ what = WTERMSIG(status); ++ } ++ printf("\x1b[31m\x1b[1m[-] Tests failed with %s %d! \u2639\x1b[0m\n", why, what); ++ } ++} ++ ++static void ensure_console(void) ++{ ++ for (unsigned int i = 0; i < 1000; ++i) { ++ int fd = open("/dev/console", O_RDWR); ++ if (fd < 0) { ++ usleep(50000); ++ continue; ++ } ++ dup2(fd, 0); ++ dup2(fd, 1); ++ dup2(fd, 2); ++ close(fd); ++ if (write(1, "\0\0\0\0\n", 5) == 5) ++ return; ++ } ++ panic("Unable to open console device"); ++} ++ ++static void clear_leaks(void) ++{ ++ int fd; ++ ++ fd = open("/sys/kernel/debug/kmemleak", O_WRONLY); ++ if (fd < 0) ++ return; ++ pretty_message("[+] Starting memory leak detection..."); ++ write(fd, "clear\n", 5); ++ close(fd); ++} ++ ++static void check_leaks(void) ++{ ++ int fd; ++ ++ fd = open("/sys/kernel/debug/kmemleak", O_WRONLY); ++ if (fd < 0) ++ return; ++ pretty_message("[+] Scanning for memory leaks..."); ++ sleep(2); /* Wait for any grace periods. */ ++ write(fd, "scan\n", 5); ++ close(fd); ++ ++ fd = open("/sys/kernel/debug/kmemleak", O_RDONLY); ++ if (fd < 0) ++ return; ++ if (sendfile(1, fd, NULL, 0x7ffff000) > 0) ++ panic("Memory leaks encountered"); ++ close(fd); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ seed_rng(); ++ ensure_console(); ++ print_banner(); ++ mount_filesystems(); ++ kmod_selftests(); ++ enable_logging(); ++ clear_leaks(); ++ launch_tests(); ++ check_leaks(); ++ poweroff(); ++ return 1; ++} +--- /dev/null ++++ b/tools/testing/selftests/wireguard/qemu/kernel.config +@@ -0,0 +1,86 @@ ++CONFIG_LOCALVERSION="" ++CONFIG_NET=y ++CONFIG_NETDEVICES=y ++CONFIG_NET_CORE=y ++CONFIG_NET_IPIP=y ++CONFIG_DUMMY=y ++CONFIG_VETH=y ++CONFIG_MULTIUSER=y ++CONFIG_NAMESPACES=y ++CONFIG_NET_NS=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IPV6=y ++CONFIG_NETFILTER=y ++CONFIG_NETFILTER_ADVANCED=y ++CONFIG_NF_CONNTRACK=y ++CONFIG_NF_NAT=y ++CONFIG_NETFILTER_XTABLES=y ++CONFIG_NETFILTER_XT_NAT=y ++CONFIG_NETFILTER_XT_MATCH_LENGTH=y ++CONFIG_NF_CONNTRACK_IPV4=y ++CONFIG_NF_NAT_IPV4=y ++CONFIG_IP_NF_IPTABLES=y ++CONFIG_IP_NF_FILTER=y ++CONFIG_IP_NF_NAT=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IPV6_MULTIPLE_TABLES=y ++CONFIG_TTY=y ++CONFIG_BINFMT_ELF=y ++CONFIG_BINFMT_SCRIPT=y ++CONFIG_VDSO=y ++CONFIG_VIRTUALIZATION=y ++CONFIG_HYPERVISOR_GUEST=y ++CONFIG_PARAVIRT=y ++CONFIG_KVM_GUEST=y ++CONFIG_PARAVIRT_SPINLOCKS=y ++CONFIG_PRINTK=y ++CONFIG_KALLSYMS=y ++CONFIG_BUG=y ++CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y ++CONFIG_EMBEDDED=n ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_SHMEM=y ++CONFIG_SLUB=y ++CONFIG_SPARSEMEM_VMEMMAP=y ++CONFIG_SMP=y ++CONFIG_SCHED_SMT=y ++CONFIG_SCHED_MC=y ++CONFIG_NUMA=y ++CONFIG_PREEMPT=y ++CONFIG_NO_HZ=y ++CONFIG_NO_HZ_IDLE=y ++CONFIG_NO_HZ_FULL=n ++CONFIG_HZ_PERIODIC=n ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_ARCH_RANDOM=y ++CONFIG_FILE_LOCKING=y ++CONFIG_POSIX_TIMERS=y ++CONFIG_DEVTMPFS=y ++CONFIG_PROC_FS=y ++CONFIG_PROC_SYSCTL=y ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15 ++CONFIG_PRINTK_TIME=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_LEGACY_VSYSCALL_NONE=y ++CONFIG_KERNEL_GZIP=y ++CONFIG_PANIC_ON_OOPS=y ++CONFIG_BUG_ON_DATA_CORRUPTION=y ++CONFIG_LOCKUP_DETECTOR=y ++CONFIG_SOFTLOCKUP_DETECTOR=y ++CONFIG_HARDLOCKUP_DETECTOR=y ++CONFIG_WQ_WATCHDOG=y ++CONFIG_DETECT_HUNG_TASK=y ++CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y ++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y ++CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y ++CONFIG_PANIC_TIMEOUT=-1 ++CONFIG_STACKTRACE=y ++CONFIG_EARLY_PRINTK=y ++CONFIG_GDB_SCRIPTS=y ++CONFIG_WIREGUARD=y ++CONFIG_WIREGUARD_DEBUG=y diff --git a/ipq806x/backport-5.4/080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch b/ipq806x/backport-5.4/080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch new file mode 100644 index 0000000..c2f8f77 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0074-wireguard-Kconfig-select-parent-dependency-for-crypt.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 15 Dec 2019 22:08:01 +0100 +Subject: [PATCH] wireguard: Kconfig: select parent dependency for crypto + +commit d7c68a38bb4f9b7c1a2e4a772872c752ee5c44a6 upstream. + +This fixes the crypto selection submenu depenencies. Otherwise, we'd +wind up issuing warnings in which certain dependencies we also select +couldn't be satisfied. This condition was triggered by the addition of +the test suite autobuilder in the previous commit. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/Kconfig | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -85,6 +85,8 @@ config WIREGUARD + select CRYPTO_POLY1305_X86_64 if X86 && 64BIT + select CRYPTO_BLAKE2S_X86 if X86 && 64BIT + select CRYPTO_CURVE25519_X86 if X86 && 64BIT ++ select ARM_CRYPTO if ARM ++ select ARM64_CRYPTO if ARM64 + select CRYPTO_CHACHA20_NEON if (ARM || ARM64) && KERNEL_MODE_NEON + select CRYPTO_POLY1305_NEON if ARM64 && KERNEL_MODE_NEON + select CRYPTO_POLY1305_ARM if ARM diff --git a/ipq806x/backport-5.4/080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch b/ipq806x/backport-5.4/080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch new file mode 100644 index 0000000..9b34e66 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0075-wireguard-global-fix-spelling-mistakes-in-comments.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josh Soref +Date: Sun, 15 Dec 2019 22:08:02 +0100 +Subject: [PATCH] wireguard: global: fix spelling mistakes in comments + +commit a2ec8b5706944d228181c8b91d815f41d6dd8e7b upstream. + +This fixes two spelling errors in source code comments. + +Signed-off-by: Josh Soref +[Jason: rewrote commit message] +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/receive.c | 2 +- + include/uapi/linux/wireguard.h | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -380,7 +380,7 @@ static void wg_packet_consume_data_done( + /* We've already verified the Poly1305 auth tag, which means this packet + * was not modified in transit. We can therefore tell the networking + * stack that all checksums of every layer of encapsulation have already +- * been checked "by the hardware" and therefore is unneccessary to check ++ * been checked "by the hardware" and therefore is unnecessary to check + * again in software. + */ + skb->ip_summed = CHECKSUM_UNNECESSARY; +--- a/include/uapi/linux/wireguard.h ++++ b/include/uapi/linux/wireguard.h +@@ -18,13 +18,13 @@ + * one but not both of: + * + * WGDEVICE_A_IFINDEX: NLA_U32 +- * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1 ++ * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1 + * + * The kernel will then return several messages (NLM_F_MULTI) containing the + * following tree of nested items: + * + * WGDEVICE_A_IFINDEX: NLA_U32 +- * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1 ++ * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1 + * WGDEVICE_A_PRIVATE_KEY: NLA_EXACT_LEN, len WG_KEY_LEN + * WGDEVICE_A_PUBLIC_KEY: NLA_EXACT_LEN, len WG_KEY_LEN + * WGDEVICE_A_LISTEN_PORT: NLA_U16 +@@ -77,7 +77,7 @@ + * WGDEVICE_A_IFINDEX and WGDEVICE_A_IFNAME: + * + * WGDEVICE_A_IFINDEX: NLA_U32 +- * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMESIZ - 1 ++ * WGDEVICE_A_IFNAME: NLA_NUL_STRING, maxlen IFNAMSIZ - 1 + * WGDEVICE_A_FLAGS: NLA_U32, 0 or WGDEVICE_F_REPLACE_PEERS if all current + * peers should be removed prior to adding the list below. + * WGDEVICE_A_PRIVATE_KEY: len WG_KEY_LEN, all zeros to remove +@@ -121,7 +121,7 @@ + * filling in information not contained in the prior. Note that if + * WGDEVICE_F_REPLACE_PEERS is specified in the first message, it probably + * should not be specified in fragments that come after, so that the list +- * of peers is only cleared the first time but appened after. Likewise for ++ * of peers is only cleared the first time but appended after. Likewise for + * peers, if WGPEER_F_REPLACE_ALLOWEDIPS is specified in the first message + * of a peer, it likely should not be specified in subsequent fragments. + * diff --git a/ipq806x/backport-5.4/080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch b/ipq806x/backport-5.4/080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch new file mode 100644 index 0000000..3cc0b56 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0076-wireguard-main-remove-unused-include-linux-version.h.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Sun, 15 Dec 2019 22:08:03 +0100 +Subject: [PATCH] wireguard: main: remove unused include + +commit 43967b6ff91e53bcce5ae08c16a0588a475b53a1 upstream. + +Remove from the includes for main.c, which is unused. + +Signed-off-by: YueHaibing +[Jason: reworded commit message] +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/main.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireguard/main.c ++++ b/drivers/net/wireguard/main.c +@@ -12,7 +12,6 @@ + + #include + +-#include + #include + #include + #include diff --git a/ipq806x/backport-5.4/080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch b/ipq806x/backport-5.4/080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch new file mode 100644 index 0000000..edd9048 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0077-wireguard-allowedips-use-kfree_rcu-instead-of-call_r.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Wei Yongjun +Date: Sun, 15 Dec 2019 22:08:04 +0100 +Subject: [PATCH] wireguard: allowedips: use kfree_rcu() instead of call_rcu() + +commit d89ee7d5c73af15c1c6f12b016cdf469742b5726 upstream. + +The callback function of call_rcu() just calls a kfree(), so we +can use kfree_rcu() instead of call_rcu() + callback function. + +Signed-off-by: Wei Yongjun +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/allowedips.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +--- a/drivers/net/wireguard/allowedips.c ++++ b/drivers/net/wireguard/allowedips.c +@@ -31,11 +31,6 @@ static void copy_and_assign_cidr(struct + #define CHOOSE_NODE(parent, key) \ + parent->bit[(key[parent->bit_at_a] >> parent->bit_at_b) & 1] + +-static void node_free_rcu(struct rcu_head *rcu) +-{ +- kfree(container_of(rcu, struct allowedips_node, rcu)); +-} +- + static void push_rcu(struct allowedips_node **stack, + struct allowedips_node __rcu *p, unsigned int *len) + { +@@ -112,7 +107,7 @@ static void walk_remove_by_peer(struct a + if (!node->bit[0] || !node->bit[1]) { + rcu_assign_pointer(*nptr, DEREF( + &node->bit[!REF(node->bit[0])])); +- call_rcu(&node->rcu, node_free_rcu); ++ kfree_rcu(node, rcu); + node = DEREF(nptr); + } + } diff --git a/ipq806x/backport-5.4/080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch b/ipq806x/backport-5.4/080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch new file mode 100644 index 0000000..6ff0dd9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0078-wireguard-selftests-remove-ancient-kernel-compatibil.patch @@ -0,0 +1,373 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 2 Jan 2020 17:47:49 +0100 +Subject: [PATCH] wireguard: selftests: remove ancient kernel compatibility + code + +commit 9a69a4c8802adf642bc4a13d471b5a86b44ed434 upstream. + +Quite a bit of the test suite was designed to work with ancient kernels. +Thankfully we no longer have to deal with this. This commit updates +things that we can finally update and removes things that we can finally +remove, to avoid the build-up of the last several years as a result of +having to support ancient kernels. We can finally rely on suppress_ +prefixlength being available. On the build side of things, the no-PIE +hack is no longer required, and we can bump some of the tools, repair +our m68k and i686-kvm support, and get better coverage of the static +branches used in the crypto lib and in udp_tunnel. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/netns.sh | 11 +-- + .../testing/selftests/wireguard/qemu/Makefile | 82 ++++++++++--------- + .../selftests/wireguard/qemu/arch/m68k.config | 2 +- + tools/testing/selftests/wireguard/qemu/init.c | 1 + + .../selftests/wireguard/qemu/kernel.config | 2 + + 5 files changed, 50 insertions(+), 48 deletions(-) + +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -37,7 +37,7 @@ n2() { pretty 2 "$*"; maybe_exec ip netn + ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; } + ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; } + ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; } +-sleep() { read -t "$1" -N 0 || true; } ++sleep() { read -t "$1" -N 1 || true; } + waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; } + waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } + waitncattcp() { pretty "${1//*-}" "wait for tcp:1111"; while [[ $(ss -N "$1" -tlp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } +@@ -294,12 +294,9 @@ ip1 -6 rule add table main suppress_pref + ip1 -4 route add default dev wg0 table 51820 + ip1 -4 rule add not fwmark 51820 table 51820 + ip1 -4 rule add table main suppress_prefixlength 0 +-# suppress_prefixlength only got added in 3.12, and we want to support 3.10+. +-if [[ $(ip1 -4 rule show all) == *suppress_prefixlength* ]]; then +- # Flood the pings instead of sending just one, to trigger routing table reference counting bugs. +- n1 ping -W 1 -c 100 -f 192.168.99.7 +- n1 ping -W 1 -c 100 -f abab::1111 +-fi ++# Flood the pings instead of sending just one, to trigger routing table reference counting bugs. ++n1 ping -W 1 -c 100 -f 192.168.99.7 ++n1 ping -W 1 -c 100 -f abab::1111 + + n0 iptables -t nat -F + ip0 link del vethrc +--- a/tools/testing/selftests/wireguard/qemu/Makefile ++++ b/tools/testing/selftests/wireguard/qemu/Makefile +@@ -5,6 +5,7 @@ + PWD := $(shell pwd) + + CHOST := $(shell gcc -dumpmachine) ++HOST_ARCH := $(firstword $(subst -, ,$(CHOST))) + ifneq (,$(ARCH)) + CBUILD := $(subst -gcc,,$(lastword $(subst /, ,$(firstword $(wildcard $(foreach bindir,$(subst :, ,$(PATH)),$(bindir)/$(ARCH)-*-gcc)))))) + ifeq (,$(CBUILD)) +@@ -37,19 +38,19 @@ endef + define file_download = + $(DISTFILES_PATH)/$(1): + mkdir -p $(DISTFILES_PATH) +- flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -t inf --retry-on-http-error=404 -O $$@.tmp $(2)$(1) || rm -f $$@.tmp' ++ flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -O $$@.tmp $(2)$(1) || rm -f $$@.tmp' + if echo "$(3) $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi + endef + +-$(eval $(call tar_download,MUSL,musl,1.1.20,.tar.gz,https://www.musl-libc.org/releases/,44be8771d0e6c6b5f82dd15662eb2957c9a3173a19a8b49966ac0542bbd40d61)) ++$(eval $(call tar_download,MUSL,musl,1.1.24,.tar.gz,https://www.musl-libc.org/releases/,1370c9a812b2cf2a7d92802510cca0058cc37e66a7bedd70051f0a34015022a3)) + $(eval $(call tar_download,LIBMNL,libmnl,1.0.4,.tar.bz2,https://www.netfilter.org/projects/libmnl/files/,171f89699f286a5854b72b91d06e8f8e3683064c5901fb09d954a9ab6f551f81)) +-$(eval $(call tar_download,IPERF,iperf,3.1.7,.tar.gz,http://downloads.es.net/pub/iperf/,a4ef73406fe92250602b8da2ae89ec53211f805df97a1d1d629db5a14043734f)) ++$(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c)) + $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d)) +-$(eval $(call tar_download,IPROUTE2,iproute2,5.1.0,.tar.gz,https://www.kernel.org/pub/linux/utils/net/iproute2/,9b43707d6075ecdca14803ca8ce0c8553848c49fa1586d12fd508d66577243f2)) +-$(eval $(call tar_download,IPTABLES,iptables,1.6.1,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,0fc2d7bd5d7be11311726466789d4c65fb4c8e096c9182b56ce97440864f0cf5)) +-$(eval $(call tar_download,NMAP,nmap,7.60,.tar.bz2,https://nmap.org/dist/,a8796ecc4fa6c38aad6139d9515dc8113023a82e9d787e5a5fb5fa1b05516f21)) +-$(eval $(call tar_download,IPUTILS,iputils,s20161105,.tar.gz,https://github.com/iputils/iputils/archive/s20161105.tar.gz/#,f813092f03d17294fd23544b129b95cdb87fe19f7970a51908a6b88509acad8a)) +-$(eval $(call tar_download,WIREGUARD_TOOLS,WireGuard,0.0.20191212,.tar.xz,https://git.zx2c4.com/WireGuard/snapshot/,b0d718380f7a8822b2f12d75e462fa4eafa3a77871002981f367cd4fe2a1b071)) ++$(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae)) ++$(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c)) ++$(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa)) ++$(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a)) ++$(eval $(call tar_download,WIREGUARD_TOOLS,wireguard-tools,1.0.20191226,.tar.xz,https://git.zx2c4.com/wireguard-tools/snapshot/,aa8af0fdc9872d369d8c890a84dbc2a2466b55795dccd5b47721b2d97644b04f)) + + KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug) + rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) +@@ -59,23 +60,21 @@ export CFLAGS ?= -O3 -pipe + export LDFLAGS ?= + export CPPFLAGS := -I$(BUILD_PATH)/include + +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + CROSS_COMPILE_FLAG := --host=$(CHOST) +-NOPIE_GCC := gcc -fno-PIE + CFLAGS += -march=native + STRIP := strip + else + $(info Cross compilation: building for $(CBUILD) using $(CHOST)) + CROSS_COMPILE_FLAG := --build=$(CBUILD) --host=$(CHOST) + export CROSS_COMPILE=$(CBUILD)- +-NOPIE_GCC := $(CBUILD)-gcc -fno-PIE + STRIP := $(CBUILD)-strip + endif + ifeq ($(ARCH),aarch64) + QEMU_ARCH := aarch64 + KERNEL_ARCH := arm64 + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm + else + QEMU_MACHINE := -cpu cortex-a53 -machine virt +@@ -85,7 +84,7 @@ else ifeq ($(ARCH),aarch64_be) + QEMU_ARCH := aarch64 + KERNEL_ARCH := arm64 + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm64/boot/Image +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm + else + QEMU_MACHINE := -cpu cortex-a53 -machine virt +@@ -95,7 +94,7 @@ else ifeq ($(ARCH),arm) + QEMU_ARCH := arm + KERNEL_ARCH := arm + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm + else + QEMU_MACHINE := -cpu cortex-a15 -machine virt +@@ -105,7 +104,7 @@ else ifeq ($(ARCH),armeb) + QEMU_ARCH := arm + KERNEL_ARCH := arm + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/arm/boot/zImage +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine virt,gic_version=host,accel=kvm + else + QEMU_MACHINE := -cpu cortex-a15 -machine virt +@@ -116,7 +115,7 @@ else ifeq ($(ARCH),x86_64) + QEMU_ARCH := x86_64 + KERNEL_ARCH := x86_64 + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine q35,accel=kvm + else + QEMU_MACHINE := -cpu Skylake-Server -machine q35 +@@ -126,7 +125,7 @@ else ifeq ($(ARCH),i686) + QEMU_ARCH := i386 + KERNEL_ARCH := x86 + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage +-ifeq ($(subst i686,x86_64,$(CBUILD)),$(CHOST)) ++ifeq ($(subst x86_64,i686,$(HOST_ARCH)),$(ARCH)) + QEMU_MACHINE := -cpu host -machine q35,accel=kvm + else + QEMU_MACHINE := -cpu coreduo -machine q35 +@@ -136,7 +135,7 @@ else ifeq ($(ARCH),mips64) + QEMU_ARCH := mips64 + KERNEL_ARCH := mips + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine malta,accel=kvm + CFLAGS += -EB + else +@@ -147,7 +146,7 @@ else ifeq ($(ARCH),mips64el) + QEMU_ARCH := mips64el + KERNEL_ARCH := mips + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine malta,accel=kvm + CFLAGS += -EL + else +@@ -158,7 +157,7 @@ else ifeq ($(ARCH),mips) + QEMU_ARCH := mips + KERNEL_ARCH := mips + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine malta,accel=kvm + CFLAGS += -EB + else +@@ -169,7 +168,7 @@ else ifeq ($(ARCH),mipsel) + QEMU_ARCH := mipsel + KERNEL_ARCH := mips + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host -machine malta,accel=kvm + CFLAGS += -EL + else +@@ -180,7 +179,7 @@ else ifeq ($(ARCH),powerpc64le) + QEMU_ARCH := ppc64 + KERNEL_ARCH := powerpc + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host,accel=kvm -machine pseries + else + QEMU_MACHINE := -machine pseries +@@ -190,7 +189,7 @@ else ifeq ($(ARCH),powerpc) + QEMU_ARCH := ppc + KERNEL_ARCH := powerpc + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/powerpc/boot/uImage +-ifeq ($(CHOST),$(CBUILD)) ++ifeq ($(HOST_ARCH),$(ARCH)) + QEMU_MACHINE := -cpu host,accel=kvm -machine ppce500 + else + QEMU_MACHINE := -machine ppce500 +@@ -200,10 +199,11 @@ else ifeq ($(ARCH),m68k) + QEMU_ARCH := m68k + KERNEL_ARCH := m68k + KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux +-ifeq ($(CHOST),$(CBUILD)) +-QEMU_MACHINE := -cpu host,accel=kvm -machine q800 ++KERNEL_CMDLINE := $(shell sed -n 's/CONFIG_CMDLINE=\(.*\)/\1/p' arch/m68k.config) ++ifeq ($(HOST_ARCH),$(ARCH)) ++QEMU_MACHINE := -cpu host,accel=kvm -machine q800 -smp 1 -append $(KERNEL_CMDLINE) + else +-QEMU_MACHINE := -machine q800 ++QEMU_MACHINE := -machine q800 -smp 1 -append $(KERNEL_CMDLINE) + endif + else + $(error I only build: x86_64, i686, arm, armeb, aarch64, aarch64_be, mips, mipsel, mips64, mips64el, powerpc64le, powerpc, m68k) +@@ -238,14 +238,14 @@ $(BUILD_PATH)/init-cpio-spec.txt: + echo "nod /dev/console 644 0 0 c 5 1" >> $@ + echo "dir /bin 755 0 0" >> $@ + echo "file /bin/iperf3 $(IPERF_PATH)/src/iperf3 755 0 0" >> $@ +- echo "file /bin/wg $(WIREGUARD_TOOLS_PATH)/src/tools/wg 755 0 0" >> $@ ++ echo "file /bin/wg $(WIREGUARD_TOOLS_PATH)/src/wg 755 0 0" >> $@ + echo "file /bin/bash $(BASH_PATH)/bash 755 0 0" >> $@ + echo "file /bin/ip $(IPROUTE2_PATH)/ip/ip 755 0 0" >> $@ + echo "file /bin/ss $(IPROUTE2_PATH)/misc/ss 755 0 0" >> $@ + echo "file /bin/ping $(IPUTILS_PATH)/ping 755 0 0" >> $@ + echo "file /bin/ncat $(NMAP_PATH)/ncat/ncat 755 0 0" >> $@ +- echo "file /bin/xtables-multi $(IPTABLES_PATH)/iptables/xtables-multi 755 0 0" >> $@ +- echo "slink /bin/iptables xtables-multi 777 0 0" >> $@ ++ echo "file /bin/xtables-legacy-multi $(IPTABLES_PATH)/iptables/xtables-legacy-multi 755 0 0" >> $@ ++ echo "slink /bin/iptables xtables-legacy-multi 777 0 0" >> $@ + echo "slink /bin/ping6 ping 777 0 0" >> $@ + echo "dir /lib 755 0 0" >> $@ + echo "file /lib/libc.so $(MUSL_PATH)/lib/libc.so 755 0 0" >> $@ +@@ -260,8 +260,8 @@ $(KERNEL_BUILD_PATH)/.config: kernel.con + cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config $(KERNEL_BUILD_PATH)/minimal.config + $(if $(findstring yes,$(DEBUG_KERNEL)),cp debug.config $(KERNEL_BUILD_PATH) && cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config debug.config,) + +-$(KERNEL_BZIMAGE): $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(MUSL_PATH)/lib/libc.so $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/tools/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES) +- $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)" ++$(KERNEL_BZIMAGE): $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(MUSL_PATH)/lib/libc.so $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES) ++ $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) + + $(BUILD_PATH)/include/linux/.installed: | $(KERNEL_BUILD_PATH)/.config + $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) INSTALL_HDR_PATH=$(BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) headers_install +@@ -280,7 +280,7 @@ $(BUILD_PATH)/include/.installed: $(MUSL + + $(MUSL_CC): $(MUSL_PATH)/lib/libc.so + sh $(MUSL_PATH)/tools/musl-gcc.specs.sh $(BUILD_PATH)/include $(MUSL_PATH)/lib /lib/ld-linux.so.1 > $(BUILD_PATH)/musl-gcc.specs +- printf '#!/bin/sh\nexec "$(REAL_CC)" --specs="$(BUILD_PATH)/musl-gcc.specs" -fno-stack-protector -no-pie "$$@"\n' > $(BUILD_PATH)/musl-gcc ++ printf '#!/bin/sh\nexec "$(REAL_CC)" --specs="$(BUILD_PATH)/musl-gcc.specs" "$$@"\n' > $(BUILD_PATH)/musl-gcc + chmod +x $(BUILD_PATH)/musl-gcc + + $(IPERF_PATH)/.installed: $(IPERF_TAR) +@@ -291,7 +291,7 @@ $(IPERF_PATH)/.installed: $(IPERF_TAR) + touch $@ + + $(IPERF_PATH)/src/iperf3: | $(IPERF_PATH)/.installed $(USERSPACE_DEPS) +- cd $(IPERF_PATH) && CFLAGS="$(CFLAGS) -D_GNU_SOURCE" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared ++ cd $(IPERF_PATH) && CFLAGS="$(CFLAGS) -D_GNU_SOURCE" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --with-openssl=no + $(MAKE) -C $(IPERF_PATH) + $(STRIP) -s $@ + +@@ -308,8 +308,8 @@ $(WIREGUARD_TOOLS_PATH)/.installed: $(WI + flock -s $<.lock tar -C $(BUILD_PATH) -xf $< + touch $@ + +-$(WIREGUARD_TOOLS_PATH)/src/tools/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) +- LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src/tools LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg ++$(WIREGUARD_TOOLS_PATH)/src/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) ++ LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg + $(STRIP) -s $@ + + $(BUILD_PATH)/init: init.c | $(USERSPACE_DEPS) +@@ -323,7 +323,8 @@ $(IPUTILS_PATH)/.installed: $(IPUTILS_TA + touch $@ + + $(IPUTILS_PATH)/ping: | $(IPUTILS_PATH)/.installed $(USERSPACE_DEPS) +- $(MAKE) -C $(IPUTILS_PATH) USE_CAP=no USE_IDN=no USE_NETTLE=no USE_CRYPTO=no ping ++ sed -i /atexit/d $(IPUTILS_PATH)/ping.c ++ cd $(IPUTILS_PATH) && $(CC) $(CFLAGS) -std=c99 -o $@ ping.c ping_common.c ping6_common.c iputils_common.c -D_GNU_SOURCE -D'IPUTILS_VERSION(f)=f' -lresolv $(LDFLAGS) + $(STRIP) -s $@ + + $(BASH_PATH)/.installed: $(BASH_TAR) +@@ -357,7 +358,7 @@ $(IPTABLES_PATH)/.installed: $(IPTABLES_ + sed -i -e "/nfnetlink=[01]/s:=[01]:=0:" -e "/nfconntrack=[01]/s:=[01]:=0:" $(IPTABLES_PATH)/configure + touch $@ + +-$(IPTABLES_PATH)/iptables/xtables-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) ++$(IPTABLES_PATH)/iptables/xtables-legacy-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) + cd $(IPTABLES_PATH) && PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --with-kernel=$(BUILD_PATH)/include + $(MAKE) -C $(IPTABLES_PATH) + $(STRIP) -s $@ +@@ -368,8 +369,9 @@ $(NMAP_PATH)/.installed: $(NMAP_TAR) + touch $@ + + $(NMAP_PATH)/ncat/ncat: | $(NMAP_PATH)/.installed $(USERSPACE_DEPS) +- cd $(NMAP_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --without-ndiff --without-zenmap --without-nping --with-libpcap=included --with-libpcre=included --with-libdnet=included --without-liblua --with-liblinear=included --without-nmap-update --without-openssl --with-pcap=linux +- $(MAKE) -C $(NMAP_PATH) build-ncat ++ cd $(NMAP_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --without-ndiff --without-zenmap --without-nping --with-libpcap=included --with-libpcre=included --with-libdnet=included --without-liblua --with-liblinear=included --without-nmap-update --without-openssl --with-pcap=linux --without-libssh ++ $(MAKE) -C $(NMAP_PATH)/libpcap ++ $(MAKE) -C $(NMAP_PATH)/ncat + $(STRIP) -s $@ + + clean: +@@ -379,7 +381,7 @@ distclean: clean + rm -rf $(DISTFILES_PATH) + + menuconfig: $(KERNEL_BUILD_PATH)/.config +- $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) CC="$(NOPIE_GCC)" menuconfig ++ $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE) menuconfig + + .PHONY: qemu build clean distclean menuconfig + .DELETE_ON_ERROR: +--- a/tools/testing/selftests/wireguard/qemu/arch/m68k.config ++++ b/tools/testing/selftests/wireguard/qemu/arch/m68k.config +@@ -1,9 +1,9 @@ + CONFIG_MMU=y ++CONFIG_M68KCLASSIC=y + CONFIG_M68040=y + CONFIG_MAC=y + CONFIG_SERIAL_PMACZILOG=y + CONFIG_SERIAL_PMACZILOG_TTYS=y + CONFIG_SERIAL_PMACZILOG_CONSOLE=y +-CONFIG_CMDLINE_BOOL=y + CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1" + CONFIG_FRAME_WARN=1024 +--- a/tools/testing/selftests/wireguard/qemu/init.c ++++ b/tools/testing/selftests/wireguard/qemu/init.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + +--- a/tools/testing/selftests/wireguard/qemu/kernel.config ++++ b/tools/testing/selftests/wireguard/qemu/kernel.config +@@ -39,6 +39,7 @@ CONFIG_PRINTK=y + CONFIG_KALLSYMS=y + CONFIG_BUG=y + CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y ++CONFIG_JUMP_LABEL=y + CONFIG_EMBEDDED=n + CONFIG_BASE_FULL=y + CONFIG_FUTEX=y +@@ -55,6 +56,7 @@ CONFIG_NO_HZ_IDLE=y + CONFIG_NO_HZ_FULL=n + CONFIG_HZ_PERIODIC=n + CONFIG_HIGH_RES_TIMERS=y ++CONFIG_COMPAT_32BIT_TIME=y + CONFIG_ARCH_RANDOM=y + CONFIG_FILE_LOCKING=y + CONFIG_POSIX_TIMERS=y diff --git a/ipq806x/backport-5.4/080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch b/ipq806x/backport-5.4/080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch new file mode 100644 index 0000000..fb03b1b --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0079-wireguard-queueing-do-not-account-for-pfmemalloc-whe.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 2 Jan 2020 17:47:50 +0100 +Subject: [PATCH] wireguard: queueing: do not account for pfmemalloc when + clearing skb header + +commit 04d2ea92a18417619182cbb79063f154892b0150 upstream. + +Before 8b7008620b84 ("net: Don't copy pfmemalloc flag in __copy_skb_ +header()"), the pfmemalloc flag used to be between headers_start and +headers_end, which is a region we clear when preparing the packet for +encryption/decryption. This is a parameter we certainly want to +preserve, which is why 8b7008620b84 moved it out of there. The code here +was written in a world before 8b7008620b84, though, where we had to +manually account for it. This commit brings things up to speed. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/queueing.h | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/net/wireguard/queueing.h ++++ b/drivers/net/wireguard/queueing.h +@@ -83,13 +83,10 @@ static inline __be16 wg_skb_examine_untr + + static inline void wg_reset_packet(struct sk_buff *skb) + { +- const int pfmemalloc = skb->pfmemalloc; +- + skb_scrub_packet(skb, true); + memset(&skb->headers_start, 0, + offsetof(struct sk_buff, headers_end) - + offsetof(struct sk_buff, headers_start)); +- skb->pfmemalloc = pfmemalloc; + skb->queue_mapping = 0; + skb->nohdr = 0; + skb->peeked = 0; diff --git a/ipq806x/backport-5.4/080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch b/ipq806x/backport-5.4/080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch new file mode 100644 index 0000000..779491c --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0080-wireguard-socket-mark-skbs-as-not-on-list-when-recei.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 2 Jan 2020 17:47:51 +0100 +Subject: [PATCH] wireguard: socket: mark skbs as not on list when receiving + via gro + +commit 736775d06bac60d7a353e405398b48b2bd8b1e54 upstream. + +Certain drivers will pass gro skbs to udp, at which point the udp driver +simply iterates through them and passes them off to encap_rcv, which is +where we pick up. At the moment, we're not attempting to coalesce these +into bundles, but we also don't want to wind up having cascaded lists of +skbs treated separately. The right behavior here, then, is to just mark +each incoming one as not on a list. This can be seen in practice, for +example, with Qualcomm's rmnet_perf driver. + +Signed-off-by: Jason A. Donenfeld +Tested-by: Yaroslav Furman +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/socket.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireguard/socket.c ++++ b/drivers/net/wireguard/socket.c +@@ -333,6 +333,7 @@ static int wg_receive(struct sock *sk, s + wg = sk->sk_user_data; + if (unlikely(!wg)) + goto err; ++ skb_mark_not_on_list(skb); + wg_packet_receive(wg, skb); + return 0; + diff --git a/ipq806x/backport-5.4/080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch b/ipq806x/backport-5.4/080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch new file mode 100644 index 0000000..e77ab58 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0081-wireguard-allowedips-fix-use-after-free-in-root_remo.patch @@ -0,0 +1,164 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Tue, 4 Feb 2020 22:17:25 +0100 +Subject: [PATCH] wireguard: allowedips: fix use-after-free in + root_remove_peer_lists + +commit 9981159fc3b677b357f84e069a11de5a5ec8a2a8 upstream. + +In the unlikely case a new node could not be allocated, we need to +remove @newnode from @peer->allowedips_list before freeing it. + +syzbot reported: + +BUG: KASAN: use-after-free in __list_del_entry_valid+0xdc/0xf5 lib/list_debug.c:54 +Read of size 8 at addr ffff88809881a538 by task syz-executor.4/30133 + +CPU: 0 PID: 30133 Comm: syz-executor.4 Not tainted 5.5.0-syzkaller #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0x197/0x210 lib/dump_stack.c:118 + print_address_description.constprop.0.cold+0xd4/0x30b mm/kasan/report.c:374 + __kasan_report.cold+0x1b/0x32 mm/kasan/report.c:506 + kasan_report+0x12/0x20 mm/kasan/common.c:639 + __asan_report_load8_noabort+0x14/0x20 mm/kasan/generic_report.c:135 + __list_del_entry_valid+0xdc/0xf5 lib/list_debug.c:54 + __list_del_entry include/linux/list.h:132 [inline] + list_del include/linux/list.h:146 [inline] + root_remove_peer_lists+0x24f/0x4b0 drivers/net/wireguard/allowedips.c:65 + wg_allowedips_free+0x232/0x390 drivers/net/wireguard/allowedips.c:300 + wg_peer_remove_all+0xd5/0x620 drivers/net/wireguard/peer.c:187 + wg_set_device+0xd01/0x1350 drivers/net/wireguard/netlink.c:542 + genl_family_rcv_msg_doit net/netlink/genetlink.c:672 [inline] + genl_family_rcv_msg net/netlink/genetlink.c:717 [inline] + genl_rcv_msg+0x67d/0xea0 net/netlink/genetlink.c:734 + netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 + genl_rcv+0x29/0x40 net/netlink/genetlink.c:745 + netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] + netlink_unicast+0x59e/0x7e0 net/netlink/af_netlink.c:1328 + netlink_sendmsg+0x91c/0xea0 net/netlink/af_netlink.c:1917 + sock_sendmsg_nosec net/socket.c:652 [inline] + sock_sendmsg+0xd7/0x130 net/socket.c:672 + ____sys_sendmsg+0x753/0x880 net/socket.c:2343 + ___sys_sendmsg+0x100/0x170 net/socket.c:2397 + __sys_sendmsg+0x105/0x1d0 net/socket.c:2430 + __do_sys_sendmsg net/socket.c:2439 [inline] + __se_sys_sendmsg net/socket.c:2437 [inline] + __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2437 + do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x45b399 +Code: ad b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 7b b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00 +RSP: 002b:00007f99a9bcdc78 EFLAGS: 00000246 ORIG_RAX: 000000000000002e +RAX: ffffffffffffffda RBX: 00007f99a9bce6d4 RCX: 000000000045b399 +RDX: 0000000000000000 RSI: 0000000020001340 RDI: 0000000000000003 +RBP: 000000000075bf20 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000004 +R13: 00000000000009ba R14: 00000000004cb2b8 R15: 0000000000000009 + +Allocated by task 30103: + save_stack+0x23/0x90 mm/kasan/common.c:72 + set_track mm/kasan/common.c:80 [inline] + __kasan_kmalloc mm/kasan/common.c:513 [inline] + __kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:486 + kasan_kmalloc+0x9/0x10 mm/kasan/common.c:527 + kmem_cache_alloc_trace+0x158/0x790 mm/slab.c:3551 + kmalloc include/linux/slab.h:556 [inline] + kzalloc include/linux/slab.h:670 [inline] + add+0x70a/0x1970 drivers/net/wireguard/allowedips.c:236 + wg_allowedips_insert_v4+0xf6/0x160 drivers/net/wireguard/allowedips.c:320 + set_allowedip drivers/net/wireguard/netlink.c:343 [inline] + set_peer+0xfb9/0x1150 drivers/net/wireguard/netlink.c:468 + wg_set_device+0xbd4/0x1350 drivers/net/wireguard/netlink.c:591 + genl_family_rcv_msg_doit net/netlink/genetlink.c:672 [inline] + genl_family_rcv_msg net/netlink/genetlink.c:717 [inline] + genl_rcv_msg+0x67d/0xea0 net/netlink/genetlink.c:734 + netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 + genl_rcv+0x29/0x40 net/netlink/genetlink.c:745 + netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] + netlink_unicast+0x59e/0x7e0 net/netlink/af_netlink.c:1328 + netlink_sendmsg+0x91c/0xea0 net/netlink/af_netlink.c:1917 + sock_sendmsg_nosec net/socket.c:652 [inline] + sock_sendmsg+0xd7/0x130 net/socket.c:672 + ____sys_sendmsg+0x753/0x880 net/socket.c:2343 + ___sys_sendmsg+0x100/0x170 net/socket.c:2397 + __sys_sendmsg+0x105/0x1d0 net/socket.c:2430 + __do_sys_sendmsg net/socket.c:2439 [inline] + __se_sys_sendmsg net/socket.c:2437 [inline] + __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2437 + do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +Freed by task 30103: + save_stack+0x23/0x90 mm/kasan/common.c:72 + set_track mm/kasan/common.c:80 [inline] + kasan_set_free_info mm/kasan/common.c:335 [inline] + __kasan_slab_free+0x102/0x150 mm/kasan/common.c:474 + kasan_slab_free+0xe/0x10 mm/kasan/common.c:483 + __cache_free mm/slab.c:3426 [inline] + kfree+0x10a/0x2c0 mm/slab.c:3757 + add+0x12d2/0x1970 drivers/net/wireguard/allowedips.c:266 + wg_allowedips_insert_v4+0xf6/0x160 drivers/net/wireguard/allowedips.c:320 + set_allowedip drivers/net/wireguard/netlink.c:343 [inline] + set_peer+0xfb9/0x1150 drivers/net/wireguard/netlink.c:468 + wg_set_device+0xbd4/0x1350 drivers/net/wireguard/netlink.c:591 + genl_family_rcv_msg_doit net/netlink/genetlink.c:672 [inline] + genl_family_rcv_msg net/netlink/genetlink.c:717 [inline] + genl_rcv_msg+0x67d/0xea0 net/netlink/genetlink.c:734 + netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 + genl_rcv+0x29/0x40 net/netlink/genetlink.c:745 + netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] + netlink_unicast+0x59e/0x7e0 net/netlink/af_netlink.c:1328 + netlink_sendmsg+0x91c/0xea0 net/netlink/af_netlink.c:1917 + sock_sendmsg_nosec net/socket.c:652 [inline] + sock_sendmsg+0xd7/0x130 net/socket.c:672 + ____sys_sendmsg+0x753/0x880 net/socket.c:2343 + ___sys_sendmsg+0x100/0x170 net/socket.c:2397 + __sys_sendmsg+0x105/0x1d0 net/socket.c:2430 + __do_sys_sendmsg net/socket.c:2439 [inline] + __se_sys_sendmsg net/socket.c:2437 [inline] + __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2437 + do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 + entry_SYSCALL_64_after_hwframe+0x49/0xbe + +The buggy address belongs to the object at ffff88809881a500 + which belongs to the cache kmalloc-64 of size 64 +The buggy address is located 56 bytes inside of + 64-byte region [ffff88809881a500, ffff88809881a540) +The buggy address belongs to the page: +page:ffffea0002620680 refcount:1 mapcount:0 mapping:ffff8880aa400380 index:0x0 +raw: 00fffe0000000200 ffffea000250b748 ffffea000254bac8 ffff8880aa400380 +raw: 0000000000000000 ffff88809881a000 0000000100000020 0000000000000000 +page dumped because: kasan: bad access detected + +Memory state around the buggy address: + ffff88809881a400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc + ffff88809881a480: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc +>ffff88809881a500: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc + ^ + ffff88809881a580: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc + ffff88809881a600: 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Eric Dumazet +Reported-by: syzbot +Cc: Jason A. Donenfeld +Cc: wireguard@lists.zx2c4.com +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/allowedips.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireguard/allowedips.c ++++ b/drivers/net/wireguard/allowedips.c +@@ -263,6 +263,7 @@ static int add(struct allowedips_node __ + } else { + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (unlikely(!node)) { ++ list_del(&newnode->peer_list); + kfree(newnode); + return -ENOMEM; + } diff --git a/ipq806x/backport-5.4/080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch b/ipq806x/backport-5.4/080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch new file mode 100644 index 0000000..55bb276 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0082-wireguard-noise-reject-peers-with-low-order-public-k.patch @@ -0,0 +1,233 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 4 Feb 2020 22:17:26 +0100 +Subject: [PATCH] wireguard: noise: reject peers with low order public keys + +commit ec31c2676a10e064878927b243fada8c2fb0c03c upstream. + +Our static-static calculation returns a failure if the public key is of +low order. We check for this when peers are added, and don't allow them +to be added if they're low order, except in the case where we haven't +yet been given a private key. In that case, we would defer the removal +of the peer until we're given a private key, since at that point we're +doing new static-static calculations which incur failures we can act on. +This meant, however, that we wound up removing peers rather late in the +configuration flow. + +Syzkaller points out that peer_remove calls flush_workqueue, which in +turn might then wait for sending a handshake initiation to complete. +Since handshake initiation needs the static identity lock, holding the +static identity lock while calling peer_remove can result in a rare +deadlock. We have precisely this case in this situation of late-stage +peer removal based on an invalid public key. We can't drop the lock when +removing, because then incoming handshakes might interact with a bogus +static-static calculation. + +While the band-aid patch for this would involve breaking up the peer +removal into two steps like wg_peer_remove_all does, in order to solve +the locking issue, there's actually a much more elegant way of fixing +this: + +If the static-static calculation succeeds with one private key, it +*must* succeed with all others, because all 32-byte strings map to valid +private keys, thanks to clamping. That means we can get rid of this +silly dance and locking headaches of removing peers late in the +configuration flow, and instead just reject them early on, regardless of +whether the device has yet been assigned a private key. For the case +where the device doesn't yet have a private key, we safely use zeros +just for the purposes of checking for low order points by way of +checking the output of the calculation. + +The following PoC will trigger the deadlock: + +ip link add wg0 type wireguard +ip addr add 10.0.0.1/24 dev wg0 +ip link set wg0 up +ping -f 10.0.0.2 & +while true; do + wg set wg0 private-key /dev/null peer AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= allowed-ips 10.0.0.0/24 endpoint 10.0.0.3:1234 + wg set wg0 private-key <(echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) +done + +[ 0.949105] ====================================================== +[ 0.949550] WARNING: possible circular locking dependency detected +[ 0.950143] 5.5.0-debug+ #18 Not tainted +[ 0.950431] ------------------------------------------------------ +[ 0.950959] wg/89 is trying to acquire lock: +[ 0.951252] ffff8880333e2128 ((wq_completion)wg-kex-wg0){+.+.}, at: flush_workqueue+0xe3/0x12f0 +[ 0.951865] +[ 0.951865] but task is already holding lock: +[ 0.952280] ffff888032819bc0 (&wg->static_identity.lock){++++}, at: wg_set_device+0x95d/0xcc0 +[ 0.953011] +[ 0.953011] which lock already depends on the new lock. +[ 0.953011] +[ 0.953651] +[ 0.953651] the existing dependency chain (in reverse order) is: +[ 0.954292] +[ 0.954292] -> #2 (&wg->static_identity.lock){++++}: +[ 0.954804] lock_acquire+0x127/0x350 +[ 0.955133] down_read+0x83/0x410 +[ 0.955428] wg_noise_handshake_create_initiation+0x97/0x700 +[ 0.955885] wg_packet_send_handshake_initiation+0x13a/0x280 +[ 0.956401] wg_packet_handshake_send_worker+0x10/0x20 +[ 0.956841] process_one_work+0x806/0x1500 +[ 0.957167] worker_thread+0x8c/0xcb0 +[ 0.957549] kthread+0x2ee/0x3b0 +[ 0.957792] ret_from_fork+0x24/0x30 +[ 0.958234] +[ 0.958234] -> #1 ((work_completion)(&peer->transmit_handshake_work)){+.+.}: +[ 0.958808] lock_acquire+0x127/0x350 +[ 0.959075] process_one_work+0x7ab/0x1500 +[ 0.959369] worker_thread+0x8c/0xcb0 +[ 0.959639] kthread+0x2ee/0x3b0 +[ 0.959896] ret_from_fork+0x24/0x30 +[ 0.960346] +[ 0.960346] -> #0 ((wq_completion)wg-kex-wg0){+.+.}: +[ 0.960945] check_prev_add+0x167/0x1e20 +[ 0.961351] __lock_acquire+0x2012/0x3170 +[ 0.961725] lock_acquire+0x127/0x350 +[ 0.961990] flush_workqueue+0x106/0x12f0 +[ 0.962280] peer_remove_after_dead+0x160/0x220 +[ 0.962600] wg_set_device+0xa24/0xcc0 +[ 0.962994] genl_rcv_msg+0x52f/0xe90 +[ 0.963298] netlink_rcv_skb+0x111/0x320 +[ 0.963618] genl_rcv+0x1f/0x30 +[ 0.963853] netlink_unicast+0x3f6/0x610 +[ 0.964245] netlink_sendmsg+0x700/0xb80 +[ 0.964586] __sys_sendto+0x1dd/0x2c0 +[ 0.964854] __x64_sys_sendto+0xd8/0x1b0 +[ 0.965141] do_syscall_64+0x90/0xd9a +[ 0.965408] entry_SYSCALL_64_after_hwframe+0x49/0xbe +[ 0.965769] +[ 0.965769] other info that might help us debug this: +[ 0.965769] +[ 0.966337] Chain exists of: +[ 0.966337] (wq_completion)wg-kex-wg0 --> (work_completion)(&peer->transmit_handshake_work) --> &wg->static_identity.lock +[ 0.966337] +[ 0.967417] Possible unsafe locking scenario: +[ 0.967417] +[ 0.967836] CPU0 CPU1 +[ 0.968155] ---- ---- +[ 0.968497] lock(&wg->static_identity.lock); +[ 0.968779] lock((work_completion)(&peer->transmit_handshake_work)); +[ 0.969345] lock(&wg->static_identity.lock); +[ 0.969809] lock((wq_completion)wg-kex-wg0); +[ 0.970146] +[ 0.970146] *** DEADLOCK *** +[ 0.970146] +[ 0.970531] 5 locks held by wg/89: +[ 0.970908] #0: ffffffff827433c8 (cb_lock){++++}, at: genl_rcv+0x10/0x30 +[ 0.971400] #1: ffffffff82743480 (genl_mutex){+.+.}, at: genl_rcv_msg+0x642/0xe90 +[ 0.971924] #2: ffffffff827160c0 (rtnl_mutex){+.+.}, at: wg_set_device+0x9f/0xcc0 +[ 0.972488] #3: ffff888032819de0 (&wg->device_update_lock){+.+.}, at: wg_set_device+0xb0/0xcc0 +[ 0.973095] #4: ffff888032819bc0 (&wg->static_identity.lock){++++}, at: wg_set_device+0x95d/0xcc0 +[ 0.973653] +[ 0.973653] stack backtrace: +[ 0.973932] CPU: 1 PID: 89 Comm: wg Not tainted 5.5.0-debug+ #18 +[ 0.974476] Call Trace: +[ 0.974638] dump_stack+0x97/0xe0 +[ 0.974869] check_noncircular+0x312/0x3e0 +[ 0.975132] ? print_circular_bug+0x1f0/0x1f0 +[ 0.975410] ? __kernel_text_address+0x9/0x30 +[ 0.975727] ? unwind_get_return_address+0x51/0x90 +[ 0.976024] check_prev_add+0x167/0x1e20 +[ 0.976367] ? graph_lock+0x70/0x160 +[ 0.976682] __lock_acquire+0x2012/0x3170 +[ 0.976998] ? register_lock_class+0x1140/0x1140 +[ 0.977323] lock_acquire+0x127/0x350 +[ 0.977627] ? flush_workqueue+0xe3/0x12f0 +[ 0.977890] flush_workqueue+0x106/0x12f0 +[ 0.978147] ? flush_workqueue+0xe3/0x12f0 +[ 0.978410] ? find_held_lock+0x2c/0x110 +[ 0.978662] ? lock_downgrade+0x6e0/0x6e0 +[ 0.978919] ? queue_rcu_work+0x60/0x60 +[ 0.979166] ? netif_napi_del+0x151/0x3b0 +[ 0.979501] ? peer_remove_after_dead+0x160/0x220 +[ 0.979871] peer_remove_after_dead+0x160/0x220 +[ 0.980232] wg_set_device+0xa24/0xcc0 +[ 0.980516] ? deref_stack_reg+0x8e/0xc0 +[ 0.980801] ? set_peer+0xe10/0xe10 +[ 0.981040] ? __ww_mutex_check_waiters+0x150/0x150 +[ 0.981430] ? __nla_validate_parse+0x163/0x270 +[ 0.981719] ? genl_family_rcv_msg_attrs_parse+0x13f/0x310 +[ 0.982078] genl_rcv_msg+0x52f/0xe90 +[ 0.982348] ? genl_family_rcv_msg_attrs_parse+0x310/0x310 +[ 0.982690] ? register_lock_class+0x1140/0x1140 +[ 0.983049] netlink_rcv_skb+0x111/0x320 +[ 0.983298] ? genl_family_rcv_msg_attrs_parse+0x310/0x310 +[ 0.983645] ? netlink_ack+0x880/0x880 +[ 0.983888] genl_rcv+0x1f/0x30 +[ 0.984168] netlink_unicast+0x3f6/0x610 +[ 0.984443] ? netlink_detachskb+0x60/0x60 +[ 0.984729] ? find_held_lock+0x2c/0x110 +[ 0.984976] netlink_sendmsg+0x700/0xb80 +[ 0.985220] ? netlink_broadcast_filtered+0xa60/0xa60 +[ 0.985533] __sys_sendto+0x1dd/0x2c0 +[ 0.985763] ? __x64_sys_getpeername+0xb0/0xb0 +[ 0.986039] ? sockfd_lookup_light+0x17/0x160 +[ 0.986397] ? __sys_recvmsg+0x8c/0xf0 +[ 0.986711] ? __sys_recvmsg_sock+0xd0/0xd0 +[ 0.987018] __x64_sys_sendto+0xd8/0x1b0 +[ 0.987283] ? lockdep_hardirqs_on+0x39b/0x5a0 +[ 0.987666] do_syscall_64+0x90/0xd9a +[ 0.987903] entry_SYSCALL_64_after_hwframe+0x49/0xbe +[ 0.988223] RIP: 0033:0x7fe77c12003e +[ 0.988508] Code: c3 8b 07 85 c0 75 24 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 4 +[ 0.989666] RSP: 002b:00007fffada2ed58 EFLAGS: 00000246 ORIG_RAX: 000000000000002c +[ 0.990137] RAX: ffffffffffffffda RBX: 00007fe77c159d48 RCX: 00007fe77c12003e +[ 0.990583] RDX: 0000000000000040 RSI: 000055fd1d38e020 RDI: 0000000000000004 +[ 0.991091] RBP: 000055fd1d38e020 R08: 000055fd1cb63358 R09: 000000000000000c +[ 0.991568] R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000002c +[ 0.992014] R13: 0000000000000004 R14: 000055fd1d38e020 R15: 0000000000000001 + +Signed-off-by: Jason A. Donenfeld +Reported-by: syzbot +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/netlink.c | 6 ++---- + drivers/net/wireguard/noise.c | 10 +++++++--- + 2 files changed, 9 insertions(+), 7 deletions(-) + +--- a/drivers/net/wireguard/netlink.c ++++ b/drivers/net/wireguard/netlink.c +@@ -575,10 +575,8 @@ static int wg_set_device(struct sk_buff + private_key); + list_for_each_entry_safe(peer, temp, &wg->peer_list, + peer_list) { +- if (wg_noise_precompute_static_static(peer)) +- wg_noise_expire_current_peer_keypairs(peer); +- else +- wg_peer_remove(peer); ++ BUG_ON(!wg_noise_precompute_static_static(peer)); ++ wg_noise_expire_current_peer_keypairs(peer); + } + wg_cookie_checker_precompute_device_keys(&wg->cookie_checker); + up_write(&wg->static_identity.lock); +--- a/drivers/net/wireguard/noise.c ++++ b/drivers/net/wireguard/noise.c +@@ -46,17 +46,21 @@ void __init wg_noise_init(void) + /* Must hold peer->handshake.static_identity->lock */ + bool wg_noise_precompute_static_static(struct wg_peer *peer) + { +- bool ret = true; ++ bool ret; + + down_write(&peer->handshake.lock); +- if (peer->handshake.static_identity->has_identity) ++ if (peer->handshake.static_identity->has_identity) { + ret = curve25519( + peer->handshake.precomputed_static_static, + peer->handshake.static_identity->static_private, + peer->handshake.remote_static); +- else ++ } else { ++ u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 }; ++ ++ ret = curve25519(empty, empty, peer->handshake.remote_static); + memset(peer->handshake.precomputed_static_static, 0, + NOISE_PUBLIC_KEY_LEN); ++ } + up_write(&peer->handshake.lock); + return ret; + } diff --git a/ipq806x/backport-5.4/080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch b/ipq806x/backport-5.4/080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch new file mode 100644 index 0000000..86877a6 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0083-wireguard-selftests-ensure-non-addition-of-peers-wit.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 4 Feb 2020 22:17:27 +0100 +Subject: [PATCH] wireguard: selftests: ensure non-addition of peers with + failed precomputation + +commit f9398acba6a4ae9cb98bfe4d56414d376eff8d57 upstream. + +Ensure that peers with low order points are ignored, both in the case +where we already have a device private key and in the case where we do +not. This adds points that naturally give a zero output. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/netns.sh | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -516,6 +516,12 @@ n0 wg set wg0 peer "$pub2" allowed-ips 0 + n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0 + n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75 + n0 wg set wg0 peer "$pub2" allowed-ips ::/0 ++n0 wg set wg0 peer "$pub2" remove ++low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= ) ++n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer } ++[[ -z $(n0 wg show wg0 peers) ]] ++n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer } ++[[ -z $(n0 wg show wg0 peers) ]] + ip0 link del wg0 + + declare -A objects diff --git a/ipq806x/backport-5.4/080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch b/ipq806x/backport-5.4/080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch new file mode 100644 index 0000000..4530f0f --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0084-wireguard-selftests-tie-socket-waiting-to-target-pid.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 4 Feb 2020 22:17:29 +0100 +Subject: [PATCH] wireguard: selftests: tie socket waiting to target pid + +commit 88f404a9b1d75388225b1c67b6dd327cb2182777 upstream. + +Without this, we wind up proceeding too early sometimes when the +previous process has just used the same listening port. So, we tie the +listening socket query to the specific pid we're interested in. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/netns.sh | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -38,9 +38,8 @@ ip0() { pretty 0 "ip $*"; ip -n $netns0 + ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; } + ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; } + sleep() { read -t "$1" -N 1 || true; } +-waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; } +-waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } +-waitncattcp() { pretty "${1//*-}" "wait for tcp:1111"; while [[ $(ss -N "$1" -tlp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } ++waitiperf() { pretty "${1//*-}" "wait for iperf:5201 pid $2"; while [[ $(ss -N "$1" -tlpH 'sport = 5201') != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; } ++waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; } + waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; } + + cleanup() { +@@ -119,22 +118,22 @@ tests() { + + # TCP over IPv4 + n2 iperf3 -s -1 -B 192.168.241.2 & +- waitiperf $netns2 ++ waitiperf $netns2 $! + n1 iperf3 -Z -t 3 -c 192.168.241.2 + + # TCP over IPv6 + n1 iperf3 -s -1 -B fd00::1 & +- waitiperf $netns1 ++ waitiperf $netns1 $! + n2 iperf3 -Z -t 3 -c fd00::1 + + # UDP over IPv4 + n1 iperf3 -s -1 -B 192.168.241.1 & +- waitiperf $netns1 ++ waitiperf $netns1 $! + n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1 + + # UDP over IPv6 + n2 iperf3 -s -1 -B fd00::2 & +- waitiperf $netns2 ++ waitiperf $netns2 $! + n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2 + } + +@@ -207,7 +206,7 @@ n1 ping -W 1 -c 1 192.168.241.2 + n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24 + exec 4< <(n1 ncat -l -u -p 1111) + ncat_pid=$! +-waitncatudp $netns1 ++waitncatudp $netns1 $ncat_pid + n2 ncat -u 192.168.241.1 1111 <<<"X" + read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]] + kill $ncat_pid +@@ -216,7 +215,7 @@ n1 wg set wg0 peer "$more_specific_key" + n2 wg set wg0 listen-port 9997 + exec 4< <(n1 ncat -l -u -p 1111) + ncat_pid=$! +-waitncatudp $netns1 ++waitncatudp $netns1 $ncat_pid + n2 ncat -u 192.168.241.1 1111 <<<"X" + ! read -r -N 1 -t 1 out <&4 || false + kill $ncat_pid diff --git a/ipq806x/backport-5.4/080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch b/ipq806x/backport-5.4/080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch new file mode 100644 index 0000000..321db18 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0085-wireguard-device-use-icmp_ndo_send-helper.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 11 Feb 2020 20:47:08 +0100 +Subject: [PATCH] wireguard: device: use icmp_ndo_send helper + +commit a12d7f3cbdc72c7625881c8dc2660fc2c979fdf2 upstream. + +Because wireguard is calling icmp from network device context, it should +use the ndo helper so that the rate limiting applies correctly. This +commit adds a small test to the wireguard test suite to ensure that the +new functions continue doing the right thing in the context of +wireguard. It does this by setting up a condition that will definately +evoke an icmp error message from the driver, but along a nat'd path. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 4 ++-- + tools/testing/selftests/wireguard/netns.sh | 11 +++++++++++ + 2 files changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -203,9 +203,9 @@ err_peer: + err: + ++dev->stats.tx_errors; + if (skb->protocol == htons(ETH_P_IP)) +- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); ++ icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); + else if (skb->protocol == htons(ETH_P_IPV6)) +- icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); ++ icmpv6_ndo_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); + kfree_skb(skb); + return ret; + } +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -24,6 +24,7 @@ + set -e + + exec 3>&1 ++export LANG=C + export WG_HIDE_KEYS=never + netns0="wg-test-$$-0" + netns1="wg-test-$$-1" +@@ -297,7 +298,17 @@ ip1 -4 rule add table main suppress_pref + n1 ping -W 1 -c 100 -f 192.168.99.7 + n1 ping -W 1 -c 100 -f abab::1111 + ++# Have ns2 NAT into wg0 packets from ns0, but return an icmp error along the right route. ++n2 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -d 192.168.241.0/24 -j SNAT --to 192.168.241.2 ++n0 iptables -t filter -A INPUT \! -s 10.0.0.0/24 -i vethrs -j DROP # Manual rpfilter just to be explicit. ++n2 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward' ++ip0 -4 route add 192.168.241.1 via 10.0.0.100 ++n2 wg set wg0 peer "$pub1" remove ++[[ $(! n0 ping -W 1 -c 1 192.168.241.1 || false) == *"From 10.0.0.100 icmp_seq=1 Destination Host Unreachable"* ]] ++ + n0 iptables -t nat -F ++n0 iptables -t filter -F ++n2 iptables -t nat -F + ip0 link del vethrc + ip0 link del vethrs + ip1 link del wg0 diff --git a/ipq806x/backport-5.4/080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch b/ipq806x/backport-5.4/080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch new file mode 100644 index 0000000..ac292a8 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0086-wireguard-selftests-reduce-complexity-and-fix-make-r.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 14 Feb 2020 23:57:20 +0100 +Subject: [PATCH] wireguard: selftests: reduce complexity and fix make races + +commit 04ddf1208f03e1dbc39a4619c40eba640051b950 upstream. + +This gives us fewer dependencies and shortens build time, fixes up some +hash checking race conditions, and also fixes missing directory creation +that caused issues on massively parallel builds. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + .../testing/selftests/wireguard/qemu/Makefile | 38 +++++++------------ + 1 file changed, 14 insertions(+), 24 deletions(-) + +--- a/tools/testing/selftests/wireguard/qemu/Makefile ++++ b/tools/testing/selftests/wireguard/qemu/Makefile +@@ -38,19 +38,17 @@ endef + define file_download = + $(DISTFILES_PATH)/$(1): + mkdir -p $(DISTFILES_PATH) +- flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -O $$@.tmp $(2)$(1) || rm -f $$@.tmp' +- if echo "$(3) $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi ++ flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -O $$@.tmp $(2)$(1) || rm -f $$@.tmp; [ -f $$@.tmp ] || exit 1; if echo "$(3) $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi' + endef + + $(eval $(call tar_download,MUSL,musl,1.1.24,.tar.gz,https://www.musl-libc.org/releases/,1370c9a812b2cf2a7d92802510cca0058cc37e66a7bedd70051f0a34015022a3)) +-$(eval $(call tar_download,LIBMNL,libmnl,1.0.4,.tar.bz2,https://www.netfilter.org/projects/libmnl/files/,171f89699f286a5854b72b91d06e8f8e3683064c5901fb09d954a9ab6f551f81)) + $(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c)) + $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d)) + $(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae)) + $(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c)) + $(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa)) + $(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a)) +-$(eval $(call tar_download,WIREGUARD_TOOLS,wireguard-tools,1.0.20191226,.tar.xz,https://git.zx2c4.com/wireguard-tools/snapshot/,aa8af0fdc9872d369d8c890a84dbc2a2466b55795dccd5b47721b2d97644b04f)) ++$(eval $(call tar_download,WIREGUARD_TOOLS,wireguard-tools,1.0.20200206,.tar.xz,https://git.zx2c4.com/wireguard-tools/snapshot/,f5207248c6a3c3e3bfc9ab30b91c1897b00802ed861e1f9faaed873366078c64)) + + KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug) + rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) +@@ -295,21 +293,13 @@ $(IPERF_PATH)/src/iperf3: | $(IPERF_PATH + $(MAKE) -C $(IPERF_PATH) + $(STRIP) -s $@ + +-$(LIBMNL_PATH)/.installed: $(LIBMNL_TAR) +- flock -s $<.lock tar -C $(BUILD_PATH) -xf $< +- touch $@ +- +-$(LIBMNL_PATH)/src/.libs/libmnl.a: | $(LIBMNL_PATH)/.installed $(USERSPACE_DEPS) +- cd $(LIBMNL_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared +- $(MAKE) -C $(LIBMNL_PATH) +- sed -i 's:prefix=.*:prefix=$(LIBMNL_PATH):' $(LIBMNL_PATH)/libmnl.pc +- + $(WIREGUARD_TOOLS_PATH)/.installed: $(WIREGUARD_TOOLS_TAR) ++ mkdir -p $(BUILD_PATH) + flock -s $<.lock tar -C $(BUILD_PATH) -xf $< + touch $@ + +-$(WIREGUARD_TOOLS_PATH)/src/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) +- LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src LIBMNL_CFLAGS="-I$(LIBMNL_PATH)/include" LIBMNL_LDLIBS="-lmnl" wg ++$(WIREGUARD_TOOLS_PATH)/src/wg: | $(WIREGUARD_TOOLS_PATH)/.installed $(USERSPACE_DEPS) ++ $(MAKE) -C $(WIREGUARD_TOOLS_PATH)/src wg + $(STRIP) -s $@ + + $(BUILD_PATH)/init: init.c | $(USERSPACE_DEPS) +@@ -340,17 +330,17 @@ $(BASH_PATH)/bash: | $(BASH_PATH)/.insta + $(IPROUTE2_PATH)/.installed: $(IPROUTE2_TAR) + mkdir -p $(BUILD_PATH) + flock -s $<.lock tar -C $(BUILD_PATH) -xf $< +- printf 'CC:=$(CC)\nPKG_CONFIG:=pkg-config\nTC_CONFIG_XT:=n\nTC_CONFIG_ATM:=n\nTC_CONFIG_IPSET:=n\nIP_CONFIG_SETNS:=y\nHAVE_ELF:=n\nHAVE_MNL:=y\nHAVE_BERKELEY_DB:=n\nHAVE_LATEX:=n\nHAVE_PDFLATEX:=n\nCFLAGS+=-DHAVE_SETNS -DHAVE_LIBMNL -I$(LIBMNL_PATH)/include\nLDLIBS+=-lmnl' > $(IPROUTE2_PATH)/config.mk ++ printf 'CC:=$(CC)\nPKG_CONFIG:=pkg-config\nTC_CONFIG_XT:=n\nTC_CONFIG_ATM:=n\nTC_CONFIG_IPSET:=n\nIP_CONFIG_SETNS:=y\nHAVE_ELF:=n\nHAVE_MNL:=n\nHAVE_BERKELEY_DB:=n\nHAVE_LATEX:=n\nHAVE_PDFLATEX:=n\nCFLAGS+=-DHAVE_SETNS\n' > $(IPROUTE2_PATH)/config.mk + printf 'lib: snapshot\n\t$$(MAKE) -C lib\nip/ip: lib\n\t$$(MAKE) -C ip ip\nmisc/ss: lib\n\t$$(MAKE) -C misc ss\n' >> $(IPROUTE2_PATH)/Makefile + touch $@ + +-$(IPROUTE2_PATH)/ip/ip: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) +- LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ ip/ip +- $(STRIP) -s $(IPROUTE2_PATH)/ip/ip +- +-$(IPROUTE2_PATH)/misc/ss: | $(IPROUTE2_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) +- LDFLAGS="$(LDFLAGS) -L$(LIBMNL_PATH)/src/.libs" PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ misc/ss +- $(STRIP) -s $(IPROUTE2_PATH)/misc/ss ++$(IPROUTE2_PATH)/ip/ip: | $(IPROUTE2_PATH)/.installed $(USERSPACE_DEPS) ++ $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ ip/ip ++ $(STRIP) -s $@ ++ ++$(IPROUTE2_PATH)/misc/ss: | $(IPROUTE2_PATH)/.installed $(USERSPACE_DEPS) ++ $(MAKE) -C $(IPROUTE2_PATH) PREFIX=/ misc/ss ++ $(STRIP) -s $@ + + $(IPTABLES_PATH)/.installed: $(IPTABLES_TAR) + mkdir -p $(BUILD_PATH) +@@ -358,8 +348,8 @@ $(IPTABLES_PATH)/.installed: $(IPTABLES_ + sed -i -e "/nfnetlink=[01]/s:=[01]:=0:" -e "/nfconntrack=[01]/s:=[01]:=0:" $(IPTABLES_PATH)/configure + touch $@ + +-$(IPTABLES_PATH)/iptables/xtables-legacy-multi: | $(IPTABLES_PATH)/.installed $(LIBMNL_PATH)/src/.libs/libmnl.a $(USERSPACE_DEPS) +- cd $(IPTABLES_PATH) && PKG_CONFIG_LIBDIR="$(LIBMNL_PATH)" ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --with-kernel=$(BUILD_PATH)/include ++$(IPTABLES_PATH)/iptables/xtables-legacy-multi: | $(IPTABLES_PATH)/.installed $(USERSPACE_DEPS) ++ cd $(IPTABLES_PATH) && ./configure --prefix=/ $(CROSS_COMPILE_FLAG) --enable-static --disable-shared --disable-nftables --disable-bpf-compiler --disable-nfsynproxy --disable-libipq --disable-connlabel --with-kernel=$(BUILD_PATH)/include + $(MAKE) -C $(IPTABLES_PATH) + $(STRIP) -s $@ + diff --git a/ipq806x/backport-5.4/080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch b/ipq806x/backport-5.4/080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch new file mode 100644 index 0000000..193d28a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0087-wireguard-receive-reset-last_under_load-to-zero.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 14 Feb 2020 23:57:21 +0100 +Subject: [PATCH] wireguard: receive: reset last_under_load to zero + +commit 2a8a4df36462aa85b0db87b7c5ea145ba67e34a8 upstream. + +This is a small optimization that prevents more expensive comparisons +from happening when they are no longer necessary, by clearing the +last_under_load variable whenever we wind up in a state where we were +under load but we no longer are. + +Signed-off-by: Jason A. Donenfeld +Suggested-by: Matt Dunwoodie +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/receive.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -118,10 +118,13 @@ static void wg_receive_handshake_packet( + + under_load = skb_queue_len(&wg->incoming_handshakes) >= + MAX_QUEUED_INCOMING_HANDSHAKES / 8; +- if (under_load) ++ if (under_load) { + last_under_load = ktime_get_coarse_boottime_ns(); +- else if (last_under_load) ++ } else if (last_under_load) { + under_load = !wg_birthdate_has_expired(last_under_load, 1); ++ if (!under_load) ++ last_under_load = 0; ++ } + mac_state = wg_cookie_validate_packet(&wg->cookie_checker, skb, + under_load); + if ((under_load && mac_state == VALID_MAC_WITH_COOKIE) || diff --git a/ipq806x/backport-5.4/080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch b/ipq806x/backport-5.4/080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch new file mode 100644 index 0000000..d84efe2 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0088-wireguard-send-account-for-mtu-0-devices.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 14 Feb 2020 23:57:22 +0100 +Subject: [PATCH] wireguard: send: account for mtu=0 devices + +commit 175f1ca9a9ed8689d2028da1a7c624bb4fb4ff7e upstream. + +It turns out there's an easy way to get packets queued up while still +having an MTU of zero, and that's via persistent keep alive. This commit +makes sure that in whatever condition, we don't wind up dividing by +zero. Note that an MTU of zero for a wireguard interface is something +quasi-valid, so I don't think the correct fix is to limit it via +min_mtu. This can be reproduced easily with: + +ip link add wg0 type wireguard +ip link add wg1 type wireguard +ip link set wg0 up mtu 0 +ip link set wg1 up +wg set wg0 private-key <(wg genkey) +wg set wg1 listen-port 1 private-key <(wg genkey) peer $(wg show wg0 public-key) +wg set wg0 peer $(wg show wg1 public-key) persistent-keepalive 1 endpoint 127.0.0.1:1 + +However, while min_mtu=0 seems fine, it makes sense to restrict the +max_mtu. This commit also restricts the maximum MTU to the greatest +number for which rounding up to the padding multiple won't overflow a +signed integer. Packets this large were always rejected anyway +eventually, due to checks deeper in, but it seems more sound not to even +let the administrator configure something that won't work anyway. + +We use this opportunity to clean up this function a bit so that it's +clear which paths we're expecting. + +Signed-off-by: Jason A. Donenfeld +Cc: Eric Dumazet +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 7 ++++--- + drivers/net/wireguard/send.c | 16 +++++++++++----- + 2 files changed, 15 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -258,6 +258,8 @@ static void wg_setup(struct net_device * + enum { WG_NETDEV_FEATURES = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | + NETIF_F_SG | NETIF_F_GSO | + NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA }; ++ const int overhead = MESSAGE_MINIMUM_LENGTH + sizeof(struct udphdr) + ++ max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); + + dev->netdev_ops = &netdev_ops; + dev->hard_header_len = 0; +@@ -271,9 +273,8 @@ static void wg_setup(struct net_device * + dev->features |= WG_NETDEV_FEATURES; + dev->hw_features |= WG_NETDEV_FEATURES; + dev->hw_enc_features |= WG_NETDEV_FEATURES; +- dev->mtu = ETH_DATA_LEN - MESSAGE_MINIMUM_LENGTH - +- sizeof(struct udphdr) - +- max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); ++ dev->mtu = ETH_DATA_LEN - overhead; ++ dev->max_mtu = round_down(INT_MAX, MESSAGE_PADDING_MULTIPLE) - overhead; + + SET_NETDEV_DEVTYPE(dev, &device_type); + +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -143,16 +143,22 @@ static void keep_key_fresh(struct wg_pee + + static unsigned int calculate_skb_padding(struct sk_buff *skb) + { ++ unsigned int padded_size, last_unit = skb->len; ++ ++ if (unlikely(!PACKET_CB(skb)->mtu)) ++ return ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE) - last_unit; ++ + /* We do this modulo business with the MTU, just in case the networking + * layer gives us a packet that's bigger than the MTU. In that case, we + * wouldn't want the final subtraction to overflow in the case of the +- * padded_size being clamped. ++ * padded_size being clamped. Fortunately, that's very rarely the case, ++ * so we optimize for that not happening. + */ +- unsigned int last_unit = skb->len % PACKET_CB(skb)->mtu; +- unsigned int padded_size = ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE); ++ if (unlikely(last_unit > PACKET_CB(skb)->mtu)) ++ last_unit %= PACKET_CB(skb)->mtu; + +- if (padded_size > PACKET_CB(skb)->mtu) +- padded_size = PACKET_CB(skb)->mtu; ++ padded_size = min(PACKET_CB(skb)->mtu, ++ ALIGN(last_unit, MESSAGE_PADDING_MULTIPLE)); + return padded_size - last_unit; + } + diff --git a/ipq806x/backport-5.4/080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch b/ipq806x/backport-5.4/080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch new file mode 100644 index 0000000..458e9d5 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0089-wireguard-socket-remove-extra-call-to-synchronize_ne.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 14 Feb 2020 23:57:23 +0100 +Subject: [PATCH] wireguard: socket: remove extra call to synchronize_net + +commit 1fbc33b0a7feb6ca72bf7dc8a05d81485ee8ee2e upstream. + +synchronize_net() is a wrapper around synchronize_rcu(), so there's no +point in having synchronize_net and synchronize_rcu back to back, +despite the documentation comment suggesting maybe it's somewhat useful, +"Wait for packets currently being received to be done." This commit +removes the extra call. + +Signed-off-by: Jason A. Donenfeld +Suggested-by: Eric Dumazet +Reviewed-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/socket.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireguard/socket.c ++++ b/drivers/net/wireguard/socket.c +@@ -432,7 +432,6 @@ void wg_socket_reinit(struct wg_device * + wg->incoming_port = ntohs(inet_sk(new4)->inet_sport); + mutex_unlock(&wg->socket_update_lock); + synchronize_rcu(); +- synchronize_net(); + sock_free(old4); + sock_free(old6); + } diff --git a/ipq806x/backport-5.4/080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch b/ipq806x/backport-5.4/080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch new file mode 100644 index 0000000..93545e6 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0090-wireguard-selftests-remove-duplicated-include-sys-ty.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Wed, 18 Mar 2020 18:30:43 -0600 +Subject: [PATCH] wireguard: selftests: remove duplicated include + +commit 166391159c5deb84795d2ff46e95f276177fa5fb upstream. + +This commit removes a duplicated include. + +Signed-off-by: YueHaibing +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/qemu/init.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/tools/testing/selftests/wireguard/qemu/init.c ++++ b/tools/testing/selftests/wireguard/qemu/init.c +@@ -13,7 +13,6 @@ + #include + #include + #include +-#include + #include + #include + #include diff --git a/ipq806x/backport-5.4/080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch b/ipq806x/backport-5.4/080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch new file mode 100644 index 0000000..a9ca655 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0091-wireguard-queueing-account-for-skb-protocol-0.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 18 Mar 2020 18:30:45 -0600 +Subject: [PATCH] wireguard: queueing: account for skb->protocol==0 + +commit a5588604af448664e796daf3c1d5a4523c60667b upstream. + +We carry out checks to the effect of: + + if (skb->protocol != wg_examine_packet_protocol(skb)) + goto err; + +By having wg_skb_examine_untrusted_ip_hdr return 0 on failure, this +means that the check above still passes in the case where skb->protocol +is zero, which is possible to hit with AF_PACKET: + + struct sockaddr_pkt saddr = { .spkt_device = "wg0" }; + unsigned char buffer[5] = { 0 }; + sendto(socket(AF_PACKET, SOCK_PACKET, /* skb->protocol = */ 0), + buffer, sizeof(buffer), 0, (const struct sockaddr *)&saddr, sizeof(saddr)); + +Additional checks mean that this isn't actually a problem in the code +base, but I could imagine it becoming a problem later if the function is +used more liberally. + +I would prefer to fix this by having wg_examine_packet_protocol return a +32-bit ~0 value on failure, which will never match any value of +skb->protocol, which would simply change the generated code from a mov +to a movzx. However, sparse complains, and adding __force casts doesn't +seem like a good idea, so instead we just add a simple helper function +to check for the zero return value. Since wg_examine_packet_protocol +itself gets inlined, this winds up not adding an additional branch to +the generated code, since the 0 return value already happens in a +mergable branch. + +Reported-by: Fabian Freyer +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 2 +- + drivers/net/wireguard/queueing.h | 8 +++++++- + drivers/net/wireguard/receive.c | 4 ++-- + 3 files changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -122,7 +122,7 @@ static netdev_tx_t wg_xmit(struct sk_buf + u32 mtu; + int ret; + +- if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol)) { ++ if (unlikely(!wg_check_packet_protocol(skb))) { + ret = -EPROTONOSUPPORT; + net_dbg_ratelimited("%s: Invalid IP packet\n", dev->name); + goto err; +--- a/drivers/net/wireguard/queueing.h ++++ b/drivers/net/wireguard/queueing.h +@@ -66,7 +66,7 @@ struct packet_cb { + #define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer) + + /* Returns either the correct skb->protocol value, or 0 if invalid. */ +-static inline __be16 wg_skb_examine_untrusted_ip_hdr(struct sk_buff *skb) ++static inline __be16 wg_examine_packet_protocol(struct sk_buff *skb) + { + if (skb_network_header(skb) >= skb->head && + (skb_network_header(skb) + sizeof(struct iphdr)) <= +@@ -81,6 +81,12 @@ static inline __be16 wg_skb_examine_untr + return 0; + } + ++static inline bool wg_check_packet_protocol(struct sk_buff *skb) ++{ ++ __be16 real_protocol = wg_examine_packet_protocol(skb); ++ return real_protocol && skb->protocol == real_protocol; ++} ++ + static inline void wg_reset_packet(struct sk_buff *skb) + { + skb_scrub_packet(skb, true); +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -56,7 +56,7 @@ static int prepare_skb_header(struct sk_ + size_t data_offset, data_len, header_len; + struct udphdr *udp; + +- if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol || ++ if (unlikely(!wg_check_packet_protocol(skb) || + skb_transport_header(skb) < skb->head || + (skb_transport_header(skb) + sizeof(struct udphdr)) > + skb_tail_pointer(skb))) +@@ -388,7 +388,7 @@ static void wg_packet_consume_data_done( + */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->csum_level = ~0; /* All levels */ +- skb->protocol = wg_skb_examine_untrusted_ip_hdr(skb); ++ skb->protocol = wg_examine_packet_protocol(skb); + if (skb->protocol == htons(ETH_P_IP)) { + len = ntohs(ip_hdr(skb)->tot_len); + if (unlikely(len < sizeof(struct iphdr))) diff --git a/ipq806x/backport-5.4/080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch b/ipq806x/backport-5.4/080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch new file mode 100644 index 0000000..bcd4fbf --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0092-wireguard-receive-remove-dead-code-from-default-pack.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 18 Mar 2020 18:30:46 -0600 +Subject: [PATCH] wireguard: receive: remove dead code from default packet type + case + +commit 2b8765c52db24c0fbcc81bac9b5e8390f2c7d3c8 upstream. + +The situation in which we wind up hitting the default case here +indicates a major bug in earlier parsing code. It is not a usual thing +that should ever happen, which means a "friendly" message for it doesn't +make sense. Rather, replace this with a WARN_ON, just like we do earlier +in the file for a similar situation, so that somebody sends us a bug +report and we can fix it. + +Reported-by: Fabian Freyer +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/receive.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -587,8 +587,7 @@ void wg_packet_receive(struct wg_device + wg_packet_consume_data(wg, skb); + break; + default: +- net_dbg_skb_ratelimited("%s: Invalid packet from %pISpfsc\n", +- wg->dev->name, skb); ++ WARN(1, "Non-exhaustive parsing of packet header lead to unknown packet type!\n"); + goto err; + } + return; diff --git a/ipq806x/backport-5.4/080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch b/ipq806x/backport-5.4/080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch new file mode 100644 index 0000000..dac3046 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0093-wireguard-noise-error-out-precomputed-DH-during-hand.patch @@ -0,0 +1,224 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 18 Mar 2020 18:30:47 -0600 +Subject: [PATCH] wireguard: noise: error out precomputed DH during handshake + rather than config + +commit 11a7686aa99c7fe4b3f80f6dcccd54129817984d upstream. + +We precompute the static-static ECDH during configuration time, in order +to save an expensive computation later when receiving network packets. +However, not all ECDH computations yield a contributory result. Prior, +we were just not letting those peers be added to the interface. However, +this creates a strange inconsistency, since it was still possible to add +other weird points, like a valid public key plus a low-order point, and, +like points that result in zeros, a handshake would not complete. In +order to make the behavior more uniform and less surprising, simply +allow all peers to be added. Then, we'll error out later when doing the +crypto if there's an issue. This also adds more separation between the +crypto layer and the configuration layer. + +Discussed-with: Mathias Hall-Andersen +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/netlink.c | 8 +--- + drivers/net/wireguard/noise.c | 55 ++++++++++++---------- + drivers/net/wireguard/noise.h | 12 ++--- + drivers/net/wireguard/peer.c | 7 +-- + tools/testing/selftests/wireguard/netns.sh | 15 ++++-- + 5 files changed, 49 insertions(+), 48 deletions(-) + +--- a/drivers/net/wireguard/netlink.c ++++ b/drivers/net/wireguard/netlink.c +@@ -417,11 +417,7 @@ static int set_peer(struct wg_device *wg + + peer = wg_peer_create(wg, public_key, preshared_key); + if (IS_ERR(peer)) { +- /* Similar to the above, if the key is invalid, we skip +- * it without fanfare, so that services don't need to +- * worry about doing key validation themselves. +- */ +- ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer); ++ ret = PTR_ERR(peer); + peer = NULL; + goto out; + } +@@ -575,7 +571,7 @@ static int wg_set_device(struct sk_buff + private_key); + list_for_each_entry_safe(peer, temp, &wg->peer_list, + peer_list) { +- BUG_ON(!wg_noise_precompute_static_static(peer)); ++ wg_noise_precompute_static_static(peer); + wg_noise_expire_current_peer_keypairs(peer); + } + wg_cookie_checker_precompute_device_keys(&wg->cookie_checker); +--- a/drivers/net/wireguard/noise.c ++++ b/drivers/net/wireguard/noise.c +@@ -44,32 +44,23 @@ void __init wg_noise_init(void) + } + + /* Must hold peer->handshake.static_identity->lock */ +-bool wg_noise_precompute_static_static(struct wg_peer *peer) ++void wg_noise_precompute_static_static(struct wg_peer *peer) + { +- bool ret; +- + down_write(&peer->handshake.lock); +- if (peer->handshake.static_identity->has_identity) { +- ret = curve25519( +- peer->handshake.precomputed_static_static, ++ if (!peer->handshake.static_identity->has_identity || ++ !curve25519(peer->handshake.precomputed_static_static, + peer->handshake.static_identity->static_private, +- peer->handshake.remote_static); +- } else { +- u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 }; +- +- ret = curve25519(empty, empty, peer->handshake.remote_static); ++ peer->handshake.remote_static)) + memset(peer->handshake.precomputed_static_static, 0, + NOISE_PUBLIC_KEY_LEN); +- } + up_write(&peer->handshake.lock); +- return ret; + } + +-bool wg_noise_handshake_init(struct noise_handshake *handshake, +- struct noise_static_identity *static_identity, +- const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], +- const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN], +- struct wg_peer *peer) ++void wg_noise_handshake_init(struct noise_handshake *handshake, ++ struct noise_static_identity *static_identity, ++ const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], ++ const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN], ++ struct wg_peer *peer) + { + memset(handshake, 0, sizeof(*handshake)); + init_rwsem(&handshake->lock); +@@ -81,7 +72,7 @@ bool wg_noise_handshake_init(struct nois + NOISE_SYMMETRIC_KEY_LEN); + handshake->static_identity = static_identity; + handshake->state = HANDSHAKE_ZEROED; +- return wg_noise_precompute_static_static(peer); ++ wg_noise_precompute_static_static(peer); + } + + static void handshake_zero(struct noise_handshake *handshake) +@@ -403,6 +394,19 @@ static bool __must_check mix_dh(u8 chain + return true; + } + ++static bool __must_check mix_precomputed_dh(u8 chaining_key[NOISE_HASH_LEN], ++ u8 key[NOISE_SYMMETRIC_KEY_LEN], ++ const u8 precomputed[NOISE_PUBLIC_KEY_LEN]) ++{ ++ static u8 zero_point[NOISE_PUBLIC_KEY_LEN]; ++ if (unlikely(!crypto_memneq(precomputed, zero_point, NOISE_PUBLIC_KEY_LEN))) ++ return false; ++ kdf(chaining_key, key, NULL, precomputed, NOISE_HASH_LEN, ++ NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, ++ chaining_key); ++ return true; ++} ++ + static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len) + { + struct blake2s_state blake; +@@ -531,10 +535,9 @@ wg_noise_handshake_create_initiation(str + NOISE_PUBLIC_KEY_LEN, key, handshake->hash); + + /* ss */ +- kdf(handshake->chaining_key, key, NULL, +- handshake->precomputed_static_static, NOISE_HASH_LEN, +- NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, +- handshake->chaining_key); ++ if (!mix_precomputed_dh(handshake->chaining_key, key, ++ handshake->precomputed_static_static)) ++ goto out; + + /* {t} */ + tai64n_now(timestamp); +@@ -595,9 +598,9 @@ wg_noise_handshake_consume_initiation(st + handshake = &peer->handshake; + + /* ss */ +- kdf(chaining_key, key, NULL, handshake->precomputed_static_static, +- NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, +- chaining_key); ++ if (!mix_precomputed_dh(chaining_key, key, ++ handshake->precomputed_static_static)) ++ goto out; + + /* {t} */ + if (!message_decrypt(t, src->encrypted_timestamp, +--- a/drivers/net/wireguard/noise.h ++++ b/drivers/net/wireguard/noise.h +@@ -94,11 +94,11 @@ struct noise_handshake { + struct wg_device; + + void wg_noise_init(void); +-bool wg_noise_handshake_init(struct noise_handshake *handshake, +- struct noise_static_identity *static_identity, +- const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], +- const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN], +- struct wg_peer *peer); ++void wg_noise_handshake_init(struct noise_handshake *handshake, ++ struct noise_static_identity *static_identity, ++ const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], ++ const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN], ++ struct wg_peer *peer); + void wg_noise_handshake_clear(struct noise_handshake *handshake); + static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns) + { +@@ -116,7 +116,7 @@ void wg_noise_expire_current_peer_keypai + void wg_noise_set_static_identity_private_key( + struct noise_static_identity *static_identity, + const u8 private_key[NOISE_PUBLIC_KEY_LEN]); +-bool wg_noise_precompute_static_static(struct wg_peer *peer); ++void wg_noise_precompute_static_static(struct wg_peer *peer); + + bool + wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst, +--- a/drivers/net/wireguard/peer.c ++++ b/drivers/net/wireguard/peer.c +@@ -34,11 +34,8 @@ struct wg_peer *wg_peer_create(struct wg + return ERR_PTR(ret); + peer->device = wg; + +- if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity, +- public_key, preshared_key, peer)) { +- ret = -EKEYREJECTED; +- goto err_1; +- } ++ wg_noise_handshake_init(&peer->handshake, &wg->static_identity, ++ public_key, preshared_key, peer); + if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) + goto err_1; + if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false, +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -527,11 +527,16 @@ n0 wg set wg0 peer "$pub2" allowed-ips 0 + n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75 + n0 wg set wg0 peer "$pub2" allowed-ips ::/0 + n0 wg set wg0 peer "$pub2" remove +-low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= ) +-n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer } +-[[ -z $(n0 wg show wg0 peers) ]] +-n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer } +-[[ -z $(n0 wg show wg0 peers) ]] ++for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do ++ n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111 ++done ++[[ -n $(n0 wg show wg0 peers) ]] ++exec 4< <(n0 ncat -l -u -p 1111) ++ncat_pid=$! ++waitncatudp $netns0 $ncat_pid ++ip0 link set wg0 up ++! read -r -n 1 -t 2 <&4 || false ++kill $ncat_pid + ip0 link del wg0 + + declare -A objects diff --git a/ipq806x/backport-5.4/080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch b/ipq806x/backport-5.4/080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch new file mode 100644 index 0000000..c92b6a7 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0094-wireguard-send-remove-errant-newline-from-packet_enc.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sultan Alsawaf +Date: Wed, 29 Apr 2020 14:59:20 -0600 +Subject: [PATCH] wireguard: send: remove errant newline from + packet_encrypt_worker + +commit d6833e42786e050e7522d6a91a9361e54085897d upstream. + +This commit removes a useless newline at the end of a scope, which +doesn't add anything in the way of organization or readability. + +Signed-off-by: Sultan Alsawaf +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/send.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -304,7 +304,6 @@ void wg_packet_encrypt_worker(struct wor + } + wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first, + state); +- + } + } + diff --git a/ipq806x/backport-5.4/080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch b/ipq806x/backport-5.4/080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch new file mode 100644 index 0000000..a72c509 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0095-wireguard-queueing-cleanup-ptr_ring-in-error-path-of.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 29 Apr 2020 14:59:21 -0600 +Subject: [PATCH] wireguard: queueing: cleanup ptr_ring in error path of + packet_queue_init + +commit 130c58606171326c81841a49cc913cd354113dd9 upstream. + +Prior, if the alloc_percpu of packet_percpu_multicore_worker_alloc +failed, the previously allocated ptr_ring wouldn't be freed. This commit +adds the missing call to ptr_ring_cleanup in the error case. + +Reported-by: Sultan Alsawaf +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/queueing.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireguard/queueing.c ++++ b/drivers/net/wireguard/queueing.c +@@ -35,8 +35,10 @@ int wg_packet_queue_init(struct crypt_qu + if (multicore) { + queue->worker = wg_packet_percpu_multicore_worker_alloc( + function, queue); +- if (!queue->worker) ++ if (!queue->worker) { ++ ptr_ring_cleanup(&queue->ring, NULL); + return -ENOMEM; ++ } + } else { + INIT_WORK(&queue->work, function); + } diff --git a/ipq806x/backport-5.4/080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch b/ipq806x/backport-5.4/080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch new file mode 100644 index 0000000..a72358c --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0096-wireguard-receive-use-tunnel-helpers-for-decapsulati.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= +Date: Wed, 29 Apr 2020 14:59:22 -0600 +Subject: [PATCH] wireguard: receive: use tunnel helpers for decapsulating ECN + markings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit eebabcb26ea1e3295704477c6cd4e772c96a9559 upstream. + +WireGuard currently only propagates ECN markings on tunnel decap according +to the old RFC3168 specification. However, the spec has since been updated +in RFC6040 to recommend slightly different decapsulation semantics. This +was implemented in the kernel as a set of common helpers for ECN +decapsulation, so let's just switch over WireGuard to using those, so it +can benefit from this enhancement and any future tweaks. We do not drop +packets with invalid ECN marking combinations, because WireGuard is +frequently used to work around broken ISPs, which could be doing that. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Reported-by: Olivier Tilmans +Cc: Dave Taht +Cc: Rodney W. Grimes +Signed-off-by: Toke Høiland-Jørgensen +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/receive.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -393,13 +393,11 @@ static void wg_packet_consume_data_done( + len = ntohs(ip_hdr(skb)->tot_len); + if (unlikely(len < sizeof(struct iphdr))) + goto dishonest_packet_size; +- if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) +- IP_ECN_set_ce(ip_hdr(skb)); ++ INET_ECN_decapsulate(skb, PACKET_CB(skb)->ds, ip_hdr(skb)->tos); + } else if (skb->protocol == htons(ETH_P_IPV6)) { + len = ntohs(ipv6_hdr(skb)->payload_len) + + sizeof(struct ipv6hdr); +- if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) +- IP6_ECN_set_ce(skb, ipv6_hdr(skb)); ++ INET_ECN_decapsulate(skb, PACKET_CB(skb)->ds, ipv6_get_dsfield(ipv6_hdr(skb))); + } else { + goto dishonest_packet_type; + } diff --git a/ipq806x/backport-5.4/080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch b/ipq806x/backport-5.4/080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch new file mode 100644 index 0000000..f4543d2 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0097-wireguard-selftests-use-normal-kernel-stack-size-on-.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 6 May 2020 15:33:02 -0600 +Subject: [PATCH] wireguard: selftests: use normal kernel stack size on ppc64 + +commit a0fd7cc87a018df1a17f9d3f0bd994c1f22c6b34 upstream. + +While at some point it might have made sense to be running these tests +on ppc64 with 4k stacks, the kernel hasn't actually used 4k stacks on +64-bit powerpc in a long time, and more interesting things that we test +don't really work when we deviate from the default (16k). So, we stop +pushing our luck in this commit, and return to the default instead of +the minimum. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config | 1 + + 1 file changed, 1 insertion(+) + +--- a/tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config ++++ b/tools/testing/selftests/wireguard/qemu/arch/powerpc64le.config +@@ -10,3 +10,4 @@ CONFIG_CMDLINE_BOOL=y + CONFIG_CMDLINE="console=hvc0 wg.success=hvc1" + CONFIG_SECTION_MISMATCH_WARN_ONLY=y + CONFIG_FRAME_WARN=1280 ++CONFIG_THREAD_SHIFT=14 diff --git a/ipq806x/backport-5.4/080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch b/ipq806x/backport-5.4/080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch new file mode 100644 index 0000000..6dafa47 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0098-wireguard-socket-remove-errant-restriction-on-loopin.patch @@ -0,0 +1,162 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 6 May 2020 15:33:03 -0600 +Subject: [PATCH] wireguard: socket: remove errant restriction on looping to + self + +commit b673e24aad36981f327a6570412ffa7754de8911 upstream. + +It's already possible to create two different interfaces and loop +packets between them. This has always been possible with tunnels in the +kernel, and isn't specific to wireguard. Therefore, the networking stack +already needs to deal with that. At the very least, the packet winds up +exceeding the MTU and is discarded at that point. So, since this is +already something that happens, there's no need to forbid the not very +exceptional case of routing a packet back to the same interface; this +loop is no different than others, and we shouldn't special case it, but +rather rely on generic handling of loops in general. This also makes it +easier to do interesting things with wireguard such as onion routing. + +At the same time, we add a selftest for this, ensuring that both onion +routing works and infinite routing loops do not crash the kernel. We +also add a test case for wireguard interfaces nesting packets and +sending traffic between each other, as well as the loop in this case +too. We make sure to send some throughput-heavy traffic for this use +case, to stress out any possible recursion issues with the locks around +workqueues. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/socket.c | 12 ----- + tools/testing/selftests/wireguard/netns.sh | 54 ++++++++++++++++++++-- + 2 files changed, 51 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireguard/socket.c ++++ b/drivers/net/wireguard/socket.c +@@ -76,12 +76,6 @@ static int send4(struct wg_device *wg, s + net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n", + wg->dev->name, &endpoint->addr, ret); + goto err; +- } else if (unlikely(rt->dst.dev == skb->dev)) { +- ip_rt_put(rt); +- ret = -ELOOP; +- net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n", +- wg->dev->name, &endpoint->addr); +- goto err; + } + if (cache) + dst_cache_set_ip4(cache, &rt->dst, fl.saddr); +@@ -149,12 +143,6 @@ static int send6(struct wg_device *wg, s + net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n", + wg->dev->name, &endpoint->addr, ret); + goto err; +- } else if (unlikely(dst->dev == skb->dev)) { +- dst_release(dst); +- ret = -ELOOP; +- net_dbg_ratelimited("%s: Avoiding routing loop to %pISpfsc\n", +- wg->dev->name, &endpoint->addr); +- goto err; + } + if (cache) + dst_cache_set_ip6(cache, dst, &fl.saddr); +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -48,8 +48,11 @@ cleanup() { + exec 2>/dev/null + printf "$orig_message_cost" > /proc/sys/net/core/message_cost + ip0 link del dev wg0 ++ ip0 link del dev wg1 + ip1 link del dev wg0 ++ ip1 link del dev wg1 + ip2 link del dev wg0 ++ ip2 link del dev wg1 + local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)" + [[ -n $to_kill ]] && kill $to_kill + pp ip netns del $netns1 +@@ -77,18 +80,20 @@ ip0 link set wg0 netns $netns2 + key1="$(pp wg genkey)" + key2="$(pp wg genkey)" + key3="$(pp wg genkey)" ++key4="$(pp wg genkey)" + pub1="$(pp wg pubkey <<<"$key1")" + pub2="$(pp wg pubkey <<<"$key2")" + pub3="$(pp wg pubkey <<<"$key3")" ++pub4="$(pp wg pubkey <<<"$key4")" + psk="$(pp wg genpsk)" + [[ -n $key1 && -n $key2 && -n $psk ]] + + configure_peers() { + ip1 addr add 192.168.241.1/24 dev wg0 +- ip1 addr add fd00::1/24 dev wg0 ++ ip1 addr add fd00::1/112 dev wg0 + + ip2 addr add 192.168.241.2/24 dev wg0 +- ip2 addr add fd00::2/24 dev wg0 ++ ip2 addr add fd00::2/112 dev wg0 + + n1 wg set wg0 \ + private-key <(echo "$key1") \ +@@ -230,9 +235,38 @@ n1 ping -W 1 -c 1 192.168.241.2 + n1 wg set wg0 private-key <(echo "$key3") + n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove + n1 ping -W 1 -c 1 192.168.241.2 ++n2 wg set wg0 peer "$pub3" remove + +-ip1 link del wg0 ++# Test that we can route wg through wg ++ip1 addr flush dev wg0 ++ip2 addr flush dev wg0 ++ip1 addr add fd00::5:1/112 dev wg0 ++ip2 addr add fd00::5:2/112 dev wg0 ++n1 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") allowed-ips fd00::5:2/128 endpoint 127.0.0.1:2 ++n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips fd00::5:1/128 endpoint 127.212.121.99:9998 ++ip1 link add wg1 type wireguard ++ip2 link add wg1 type wireguard ++ip1 addr add 192.168.241.1/24 dev wg1 ++ip1 addr add fd00::1/112 dev wg1 ++ip2 addr add 192.168.241.2/24 dev wg1 ++ip2 addr add fd00::2/112 dev wg1 ++ip1 link set mtu 1340 up dev wg1 ++ip2 link set mtu 1340 up dev wg1 ++n1 wg set wg1 listen-port 5 private-key <(echo "$key3") peer "$pub4" allowed-ips 192.168.241.2/32,fd00::2/128 endpoint [fd00::5:2]:5 ++n2 wg set wg1 listen-port 5 private-key <(echo "$key4") peer "$pub3" allowed-ips 192.168.241.1/32,fd00::1/128 endpoint [fd00::5:1]:5 ++tests ++# Try to set up a routing loop between the two namespaces ++ip1 link set netns $netns0 dev wg1 ++ip0 addr add 192.168.241.1/24 dev wg1 ++ip0 link set up dev wg1 ++n0 ping -W 1 -c 1 192.168.241.2 ++n1 wg set wg0 peer "$pub2" endpoint 192.168.241.2:7 + ip2 link del wg0 ++ip2 link del wg1 ++! n0 ping -W 1 -c 10 -f 192.168.241.2 || false # Should not crash kernel ++ ++ip0 link del wg1 ++ip1 link del wg0 + + # Test using NAT. We now change the topology to this: + # ┌────────────────────────────────────────┐ ┌────────────────────────────────────────────────┐ ┌────────────────────────────────────────┐ +@@ -282,6 +316,20 @@ pp sleep 3 + n2 ping -W 1 -c 1 192.168.241.1 + n1 wg set wg0 peer "$pub2" persistent-keepalive 0 + ++# Test that onion routing works, even when it loops ++n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5 ++ip1 addr add 192.168.242.1/24 dev wg0 ++ip2 link add wg1 type wireguard ++ip2 addr add 192.168.242.2/24 dev wg1 ++n2 wg set wg1 private-key <(echo "$key3") listen-port 5 peer "$pub1" allowed-ips 192.168.242.1/32 ++ip2 link set wg1 up ++n1 ping -W 1 -c 1 192.168.242.2 ++ip2 link del wg1 ++n1 wg set wg0 peer "$pub3" endpoint 192.168.242.2:5 ++! n1 ping -W 1 -c 1 192.168.242.2 || false # Should not crash kernel ++n1 wg set wg0 peer "$pub3" remove ++ip1 addr del 192.168.242.1/24 dev wg0 ++ + # Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs. + ip1 -6 addr add fc00::9/96 dev vethc + ip1 -6 route add default via fc00::1 diff --git a/ipq806x/backport-5.4/080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch b/ipq806x/backport-5.4/080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch new file mode 100644 index 0000000..499b36b --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0099-wireguard-send-receive-cond_resched-when-processing-.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 6 May 2020 15:33:04 -0600 +Subject: [PATCH] wireguard: send/receive: cond_resched() when processing + worker ringbuffers + +commit 4005f5c3c9d006157ba716594e0d70c88a235c5e upstream. + +Users with pathological hardware reported CPU stalls on CONFIG_ +PREEMPT_VOLUNTARY=y, because the ringbuffers would stay full, meaning +these workers would never terminate. That turned out not to be okay on +systems without forced preemption, which Sultan observed. This commit +adds a cond_resched() to the bottom of each loop iteration, so that +these workers don't hog the core. Note that we don't need this on the +napi poll worker, since that terminates after its budget is expended. + +Suggested-by: Sultan Alsawaf +Reported-by: Wang Jian +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/receive.c | 2 ++ + drivers/net/wireguard/send.c | 4 ++++ + 2 files changed, 6 insertions(+) + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -516,6 +516,8 @@ void wg_packet_decrypt_worker(struct wor + &PACKET_CB(skb)->keypair->receiving)) ? + PACKET_STATE_CRYPTED : PACKET_STATE_DEAD; + wg_queue_enqueue_per_peer_napi(skb, state); ++ if (need_resched()) ++ cond_resched(); + } + } + +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -281,6 +281,8 @@ void wg_packet_tx_worker(struct work_str + + wg_noise_keypair_put(keypair, false); + wg_peer_put(peer); ++ if (need_resched()) ++ cond_resched(); + } + } + +@@ -304,6 +306,8 @@ void wg_packet_encrypt_worker(struct wor + } + wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first, + state); ++ if (need_resched()) ++ cond_resched(); + } + } + diff --git a/ipq806x/backport-5.4/080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch b/ipq806x/backport-5.4/080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch new file mode 100644 index 0000000..c1124be --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0100-wireguard-selftests-initalize-ipv6-members-to-NULL-t.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 6 May 2020 15:33:05 -0600 +Subject: [PATCH] wireguard: selftests: initalize ipv6 members to NULL to + squelch clang warning + +commit 4fed818ef54b08d4b29200e416cce65546ad5312 upstream. + +Without setting these to NULL, clang complains in certain +configurations that have CONFIG_IPV6=n: + +In file included from drivers/net/wireguard/ratelimiter.c:223: +drivers/net/wireguard/selftest/ratelimiter.c:173:34: error: variable 'skb6' is uninitialized when used here [-Werror,-Wuninitialized] + ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count); + ^~~~ +drivers/net/wireguard/selftest/ratelimiter.c:123:29: note: initialize the variable 'skb6' to silence this warning + struct sk_buff *skb4, *skb6; + ^ + = NULL +drivers/net/wireguard/selftest/ratelimiter.c:173:40: error: variable 'hdr6' is uninitialized when used here [-Werror,-Wuninitialized] + ret = timings_test(skb4, hdr4, skb6, hdr6, &test_count); + ^~~~ +drivers/net/wireguard/selftest/ratelimiter.c:125:22: note: initialize the variable 'hdr6' to silence this warning + struct ipv6hdr *hdr6; + ^ + +We silence this warning by setting the variables to NULL as the warning +suggests. + +Reported-by: Arnd Bergmann +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/selftest/ratelimiter.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireguard/selftest/ratelimiter.c ++++ b/drivers/net/wireguard/selftest/ratelimiter.c +@@ -120,9 +120,9 @@ bool __init wg_ratelimiter_selftest(void + enum { TRIALS_BEFORE_GIVING_UP = 5000 }; + bool success = false; + int test = 0, trials; +- struct sk_buff *skb4, *skb6; ++ struct sk_buff *skb4, *skb6 = NULL; + struct iphdr *hdr4; +- struct ipv6hdr *hdr6; ++ struct ipv6hdr *hdr6 = NULL; + + if (IS_ENABLED(CONFIG_KASAN) || IS_ENABLED(CONFIG_UBSAN)) + return true; diff --git a/ipq806x/backport-5.4/080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch b/ipq806x/backport-5.4/080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch new file mode 100644 index 0000000..900e2f2 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0101-wireguard-send-receive-use-explicit-unlikely-branch-.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 6 May 2020 15:33:06 -0600 +Subject: [PATCH] wireguard: send/receive: use explicit unlikely branch instead + of implicit coalescing + +commit 243f2148937adc72bcaaa590d482d599c936efde upstream. + +It's very unlikely that send will become true. It's nearly always false +between 0 and 120 seconds of a session, and in most cases becomes true +only between 120 and 121 seconds before becoming false again. So, +unlikely(send) is clearly the right option here. + +What happened before was that we had this complex boolean expression +with multiple likely and unlikely clauses nested. Since this is +evaluated left-to-right anyway, the whole thing got converted to +unlikely. So, we can clean this up to better represent what's going on. + +The generated code is the same. + +Suggested-by: Sultan Alsawaf +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/receive.c | 13 ++++++------- + drivers/net/wireguard/send.c | 15 ++++++--------- + 2 files changed, 12 insertions(+), 16 deletions(-) + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -226,21 +226,20 @@ void wg_packet_handshake_receive_worker( + static void keep_key_fresh(struct wg_peer *peer) + { + struct noise_keypair *keypair; +- bool send = false; ++ bool send; + + if (peer->sent_lastminute_handshake) + return; + + rcu_read_lock_bh(); + keypair = rcu_dereference_bh(peer->keypairs.current_keypair); +- if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) && +- keypair->i_am_the_initiator && +- unlikely(wg_birthdate_has_expired(keypair->sending.birthdate, +- REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT))) +- send = true; ++ send = keypair && READ_ONCE(keypair->sending.is_valid) && ++ keypair->i_am_the_initiator && ++ wg_birthdate_has_expired(keypair->sending.birthdate, ++ REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT); + rcu_read_unlock_bh(); + +- if (send) { ++ if (unlikely(send)) { + peer->sent_lastminute_handshake = true; + wg_packet_send_queued_handshake_initiation(peer, false); + } +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -124,20 +124,17 @@ void wg_packet_send_handshake_cookie(str + static void keep_key_fresh(struct wg_peer *peer) + { + struct noise_keypair *keypair; +- bool send = false; ++ bool send; + + rcu_read_lock_bh(); + keypair = rcu_dereference_bh(peer->keypairs.current_keypair); +- if (likely(keypair && READ_ONCE(keypair->sending.is_valid)) && +- (unlikely(atomic64_read(&keypair->sending.counter.counter) > +- REKEY_AFTER_MESSAGES) || +- (keypair->i_am_the_initiator && +- unlikely(wg_birthdate_has_expired(keypair->sending.birthdate, +- REKEY_AFTER_TIME))))) +- send = true; ++ send = keypair && READ_ONCE(keypair->sending.is_valid) && ++ (atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES || ++ (keypair->i_am_the_initiator && ++ wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME))); + rcu_read_unlock_bh(); + +- if (send) ++ if (unlikely(send)) + wg_packet_send_queued_handshake_initiation(peer, false); + } + diff --git a/ipq806x/backport-5.4/080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch b/ipq806x/backport-5.4/080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch new file mode 100644 index 0000000..d4efe37 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0102-wireguard-selftests-use-newer-iproute2-for-gcc-10.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 19 May 2020 22:49:27 -0600 +Subject: [PATCH] wireguard: selftests: use newer iproute2 for gcc-10 + +commit ee3c1aa3f34b7842c1557cfe5d8c3f7b8c692de8 upstream. + +gcc-10 switched to defaulting to -fno-common, which broke iproute2-5.4. +This was fixed in iproute-5.6, so switch to that. Because we're after a +stable testing surface, we generally don't like to bump these +unnecessarily, but in this case, being able to actually build is a basic +necessity. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/qemu/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/tools/testing/selftests/wireguard/qemu/Makefile ++++ b/tools/testing/selftests/wireguard/qemu/Makefile +@@ -44,7 +44,7 @@ endef + $(eval $(call tar_download,MUSL,musl,1.1.24,.tar.gz,https://www.musl-libc.org/releases/,1370c9a812b2cf2a7d92802510cca0058cc37e66a7bedd70051f0a34015022a3)) + $(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c)) + $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d)) +-$(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae)) ++$(eval $(call tar_download,IPROUTE2,iproute2,5.6.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,1b5b0e25ce6e23da7526ea1da044e814ad85ba761b10dd29c2b027c056b04692)) + $(eval $(call tar_download,IPTABLES,iptables,1.8.4,.tar.bz2,https://www.netfilter.org/projects/iptables/files/,993a3a5490a544c2cbf2ef15cf7e7ed21af1845baf228318d5c36ef8827e157c)) + $(eval $(call tar_download,NMAP,nmap,7.80,.tar.bz2,https://nmap.org/dist/,fcfa5a0e42099e12e4bf7a68ebe6fde05553383a682e816a7ec9256ab4773faa)) + $(eval $(call tar_download,IPUTILS,iputils,s20190709,.tar.gz,https://github.com/iputils/iputils/archive/s20190709.tar.gz/#,a15720dd741d7538dd2645f9f516d193636ae4300ff7dbc8bfca757bf166490a)) diff --git a/ipq806x/backport-5.4/080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch b/ipq806x/backport-5.4/080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch new file mode 100644 index 0000000..2dac4b7 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0103-wireguard-noise-read-preshared-key-while-taking-lock.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 19 May 2020 22:49:28 -0600 +Subject: [PATCH] wireguard: noise: read preshared key while taking lock + +commit bc67d371256f5c47d824e2eec51e46c8d62d022e upstream. + +Prior we read the preshared key after dropping the handshake lock, which +isn't an actual crypto issue if it races, but it's still not quite +correct. So copy that part of the state into a temporary like we do with +the rest of the handshake state variables. Then we can release the lock, +operate on the temporary, and zero it out at the end of the function. In +performance tests, the impact of this was entirely unnoticable, probably +because those bytes are coming from the same cacheline as other things +that are being copied out in the same manner. + +Reported-by: Matt Dunwoodie +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/noise.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireguard/noise.c ++++ b/drivers/net/wireguard/noise.c +@@ -715,6 +715,7 @@ wg_noise_handshake_consume_response(stru + u8 e[NOISE_PUBLIC_KEY_LEN]; + u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; + u8 static_private[NOISE_PUBLIC_KEY_LEN]; ++ u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]; + + down_read(&wg->static_identity.lock); + +@@ -733,6 +734,8 @@ wg_noise_handshake_consume_response(stru + memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN); + memcpy(ephemeral_private, handshake->ephemeral_private, + NOISE_PUBLIC_KEY_LEN); ++ memcpy(preshared_key, handshake->preshared_key, ++ NOISE_SYMMETRIC_KEY_LEN); + up_read(&handshake->lock); + + if (state != HANDSHAKE_CREATED_INITIATION) +@@ -750,7 +753,7 @@ wg_noise_handshake_consume_response(stru + goto fail; + + /* psk */ +- mix_psk(chaining_key, hash, key, handshake->preshared_key); ++ mix_psk(chaining_key, hash, key, preshared_key); + + /* {} */ + if (!message_decrypt(NULL, src->encrypted_nothing, +@@ -783,6 +786,7 @@ out: + memzero_explicit(chaining_key, NOISE_HASH_LEN); + memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN); + memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN); ++ memzero_explicit(preshared_key, NOISE_SYMMETRIC_KEY_LEN); + up_read(&wg->static_identity.lock); + return ret_peer; + } diff --git a/ipq806x/backport-5.4/080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch b/ipq806x/backport-5.4/080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch new file mode 100644 index 0000000..31deadb --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0104-wireguard-queueing-preserve-flow-hash-across-packet-.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 19 May 2020 22:49:29 -0600 +Subject: [PATCH] wireguard: queueing: preserve flow hash across packet + scrubbing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit c78a0b4a78839d572d8a80f6a62221c0d7843135 upstream. + +It's important that we clear most header fields during encapsulation and +decapsulation, because the packet is substantially changed, and we don't +want any info leak or logic bug due to an accidental correlation. But, +for encapsulation, it's wrong to clear skb->hash, since it's used by +fq_codel and flow dissection in general. Without it, classification does +not proceed as usual. This change might make it easier to estimate the +number of innerflows by examining clustering of out of order packets, +but this shouldn't open up anything that can't already be inferred +otherwise (e.g. syn packet size inference), and fq_codel can be disabled +anyway. + +Furthermore, it might be the case that the hash isn't used or queried at +all until after wireguard transmits the encrypted UDP packet, which +means skb->hash might still be zero at this point, and thus no hash +taken over the inner packet data. In order to address this situation, we +force a calculation of skb->hash before encrypting packet data. + +Of course this means that fq_codel might transmit packets slightly more +out of order than usual. Toke did some testing on beefy machines with +high quantities of parallel flows and found that increasing the +reply-attack counter to 8192 takes care of the most pathological cases +pretty well. + +Reported-by: Dave Taht +Reviewed-and-tested-by: Toke Høiland-Jørgensen +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/messages.h | 2 +- + drivers/net/wireguard/queueing.h | 10 +++++++++- + drivers/net/wireguard/receive.c | 2 +- + drivers/net/wireguard/send.c | 7 ++++++- + 4 files changed, 17 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireguard/messages.h ++++ b/drivers/net/wireguard/messages.h +@@ -32,7 +32,7 @@ enum cookie_values { + }; + + enum counter_values { +- COUNTER_BITS_TOTAL = 2048, ++ COUNTER_BITS_TOTAL = 8192, + COUNTER_REDUNDANT_BITS = BITS_PER_LONG, + COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS + }; +--- a/drivers/net/wireguard/queueing.h ++++ b/drivers/net/wireguard/queueing.h +@@ -87,12 +87,20 @@ static inline bool wg_check_packet_proto + return real_protocol && skb->protocol == real_protocol; + } + +-static inline void wg_reset_packet(struct sk_buff *skb) ++static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating) + { ++ u8 l4_hash = skb->l4_hash; ++ u8 sw_hash = skb->sw_hash; ++ u32 hash = skb->hash; + skb_scrub_packet(skb, true); + memset(&skb->headers_start, 0, + offsetof(struct sk_buff, headers_end) - + offsetof(struct sk_buff, headers_start)); ++ if (encapsulating) { ++ skb->l4_hash = l4_hash; ++ skb->sw_hash = sw_hash; ++ skb->hash = hash; ++ } + skb->queue_mapping = 0; + skb->nohdr = 0; + skb->peeked = 0; +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -484,7 +484,7 @@ int wg_packet_rx_poll(struct napi_struct + if (unlikely(wg_socket_endpoint_from_skb(&endpoint, skb))) + goto next; + +- wg_reset_packet(skb); ++ wg_reset_packet(skb, false); + wg_packet_consume_data_done(peer, skb, &endpoint); + free = false; + +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -167,6 +167,11 @@ static bool encrypt_packet(struct sk_buf + struct sk_buff *trailer; + int num_frags; + ++ /* Force hash calculation before encryption so that flow analysis is ++ * consistent over the inner packet. ++ */ ++ skb_get_hash(skb); ++ + /* Calculate lengths. */ + padding_len = calculate_skb_padding(skb); + trailer_len = padding_len + noise_encrypted_len(0); +@@ -295,7 +300,7 @@ void wg_packet_encrypt_worker(struct wor + skb_list_walk_safe(first, skb, next) { + if (likely(encrypt_packet(skb, + PACKET_CB(first)->keypair))) { +- wg_reset_packet(skb); ++ wg_reset_packet(skb, true); + } else { + state = PACKET_STATE_DEAD; + break; diff --git a/ipq806x/backport-5.4/080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch b/ipq806x/backport-5.4/080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch new file mode 100644 index 0000000..87d38d3 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0105-wireguard-noise-separate-receive-counter-from-send-c.patch @@ -0,0 +1,330 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 19 May 2020 22:49:30 -0600 +Subject: [PATCH] wireguard: noise: separate receive counter from send counter + +commit a9e90d9931f3a474f04bab782ccd9d77904941e9 upstream. + +In "wireguard: queueing: preserve flow hash across packet scrubbing", we +were required to slightly increase the size of the receive replay +counter to something still fairly small, but an increase nonetheless. +It turns out that we can recoup some of the additional memory overhead +by splitting up the prior union type into two distinct types. Before, we +used the same "noise_counter" union for both sending and receiving, with +sending just using a simple atomic64_t, while receiving used the full +replay counter checker. This meant that most of the memory being +allocated for the sending counter was being wasted. Since the old +"noise_counter" type increased in size in the prior commit, now is a +good time to split up that union type into a distinct "noise_replay_ +counter" for receiving and a boring atomic64_t for sending, each using +neither more nor less memory than required. + +Also, since sometimes the replay counter is accessed without +necessitating additional accesses to the bitmap, we can reduce cache +misses by hoisting the always-necessary lock above the bitmap in the +struct layout. We also change a "noise_replay_counter" stack allocation +to kmalloc in a -DDEBUG selftest so that KASAN doesn't trigger a stack +frame warning. + +All and all, removing a bit of abstraction in this commit makes the code +simpler and smaller, in addition to the motivating memory usage +recuperation. For example, passing around raw "noise_symmetric_key" +structs is something that really only makes sense within noise.c, in the +one place where the sending and receiving keys can safely be thought of +as the same type of object; subsequent to that, it's important that we +uniformly access these through keypair->{sending,receiving}, where their +distinct roles are always made explicit. So this patch allows us to draw +that distinction clearly as well. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/noise.c | 16 +++------ + drivers/net/wireguard/noise.h | 14 ++++---- + drivers/net/wireguard/receive.c | 42 ++++++++++++------------ + drivers/net/wireguard/selftest/counter.c | 17 +++++++--- + drivers/net/wireguard/send.c | 12 +++---- + 5 files changed, 48 insertions(+), 53 deletions(-) + +--- a/drivers/net/wireguard/noise.c ++++ b/drivers/net/wireguard/noise.c +@@ -104,6 +104,7 @@ static struct noise_keypair *keypair_cre + + if (unlikely(!keypair)) + return NULL; ++ spin_lock_init(&keypair->receiving_counter.lock); + keypair->internal_id = atomic64_inc_return(&keypair_counter); + keypair->entry.type = INDEX_HASHTABLE_KEYPAIR; + keypair->entry.peer = peer; +@@ -358,25 +359,16 @@ out: + memzero_explicit(output, BLAKE2S_HASH_SIZE + 1); + } + +-static void symmetric_key_init(struct noise_symmetric_key *key) +-{ +- spin_lock_init(&key->counter.receive.lock); +- atomic64_set(&key->counter.counter, 0); +- memset(key->counter.receive.backtrack, 0, +- sizeof(key->counter.receive.backtrack)); +- key->birthdate = ktime_get_coarse_boottime_ns(); +- key->is_valid = true; +-} +- + static void derive_keys(struct noise_symmetric_key *first_dst, + struct noise_symmetric_key *second_dst, + const u8 chaining_key[NOISE_HASH_LEN]) + { ++ u64 birthdate = ktime_get_coarse_boottime_ns(); + kdf(first_dst->key, second_dst->key, NULL, NULL, + NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0, + chaining_key); +- symmetric_key_init(first_dst); +- symmetric_key_init(second_dst); ++ first_dst->birthdate = second_dst->birthdate = birthdate; ++ first_dst->is_valid = second_dst->is_valid = true; + } + + static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN], +--- a/drivers/net/wireguard/noise.h ++++ b/drivers/net/wireguard/noise.h +@@ -15,18 +15,14 @@ + #include + #include + +-union noise_counter { +- struct { +- u64 counter; +- unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG]; +- spinlock_t lock; +- } receive; +- atomic64_t counter; ++struct noise_replay_counter { ++ u64 counter; ++ spinlock_t lock; ++ unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG]; + }; + + struct noise_symmetric_key { + u8 key[NOISE_SYMMETRIC_KEY_LEN]; +- union noise_counter counter; + u64 birthdate; + bool is_valid; + }; +@@ -34,7 +30,9 @@ struct noise_symmetric_key { + struct noise_keypair { + struct index_hashtable_entry entry; + struct noise_symmetric_key sending; ++ atomic64_t sending_counter; + struct noise_symmetric_key receiving; ++ struct noise_replay_counter receiving_counter; + __le32 remote_index; + bool i_am_the_initiator; + struct kref refcount; +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -245,20 +245,20 @@ static void keep_key_fresh(struct wg_pee + } + } + +-static bool decrypt_packet(struct sk_buff *skb, struct noise_symmetric_key *key) ++static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair) + { + struct scatterlist sg[MAX_SKB_FRAGS + 8]; + struct sk_buff *trailer; + unsigned int offset; + int num_frags; + +- if (unlikely(!key)) ++ if (unlikely(!keypair)) + return false; + +- if (unlikely(!READ_ONCE(key->is_valid) || +- wg_birthdate_has_expired(key->birthdate, REJECT_AFTER_TIME) || +- key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) { +- WRITE_ONCE(key->is_valid, false); ++ if (unlikely(!READ_ONCE(keypair->receiving.is_valid) || ++ wg_birthdate_has_expired(keypair->receiving.birthdate, REJECT_AFTER_TIME) || ++ keypair->receiving_counter.counter >= REJECT_AFTER_MESSAGES)) { ++ WRITE_ONCE(keypair->receiving.is_valid, false); + return false; + } + +@@ -283,7 +283,7 @@ static bool decrypt_packet(struct sk_buf + + if (!chacha20poly1305_decrypt_sg_inplace(sg, skb->len, NULL, 0, + PACKET_CB(skb)->nonce, +- key->key)) ++ keypair->receiving.key)) + return false; + + /* Another ugly situation of pushing and pulling the header so as to +@@ -298,41 +298,41 @@ static bool decrypt_packet(struct sk_buf + } + + /* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */ +-static bool counter_validate(union noise_counter *counter, u64 their_counter) ++static bool counter_validate(struct noise_replay_counter *counter, u64 their_counter) + { + unsigned long index, index_current, top, i; + bool ret = false; + +- spin_lock_bh(&counter->receive.lock); ++ spin_lock_bh(&counter->lock); + +- if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 || ++ if (unlikely(counter->counter >= REJECT_AFTER_MESSAGES + 1 || + their_counter >= REJECT_AFTER_MESSAGES)) + goto out; + + ++their_counter; + + if (unlikely((COUNTER_WINDOW_SIZE + their_counter) < +- counter->receive.counter)) ++ counter->counter)) + goto out; + + index = their_counter >> ilog2(BITS_PER_LONG); + +- if (likely(their_counter > counter->receive.counter)) { +- index_current = counter->receive.counter >> ilog2(BITS_PER_LONG); ++ if (likely(their_counter > counter->counter)) { ++ index_current = counter->counter >> ilog2(BITS_PER_LONG); + top = min_t(unsigned long, index - index_current, + COUNTER_BITS_TOTAL / BITS_PER_LONG); + for (i = 1; i <= top; ++i) +- counter->receive.backtrack[(i + index_current) & ++ counter->backtrack[(i + index_current) & + ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0; +- counter->receive.counter = their_counter; ++ counter->counter = their_counter; + } + + index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1; + ret = !test_and_set_bit(their_counter & (BITS_PER_LONG - 1), +- &counter->receive.backtrack[index]); ++ &counter->backtrack[index]); + + out: +- spin_unlock_bh(&counter->receive.lock); ++ spin_unlock_bh(&counter->lock); + return ret; + } + +@@ -472,12 +472,12 @@ int wg_packet_rx_poll(struct napi_struct + if (unlikely(state != PACKET_STATE_CRYPTED)) + goto next; + +- if (unlikely(!counter_validate(&keypair->receiving.counter, ++ if (unlikely(!counter_validate(&keypair->receiving_counter, + PACKET_CB(skb)->nonce))) { + net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n", + peer->device->dev->name, + PACKET_CB(skb)->nonce, +- keypair->receiving.counter.receive.counter); ++ keypair->receiving_counter.counter); + goto next; + } + +@@ -511,8 +511,8 @@ void wg_packet_decrypt_worker(struct wor + struct sk_buff *skb; + + while ((skb = ptr_ring_consume_bh(&queue->ring)) != NULL) { +- enum packet_state state = likely(decrypt_packet(skb, +- &PACKET_CB(skb)->keypair->receiving)) ? ++ enum packet_state state = ++ likely(decrypt_packet(skb, PACKET_CB(skb)->keypair)) ? + PACKET_STATE_CRYPTED : PACKET_STATE_DEAD; + wg_queue_enqueue_per_peer_napi(skb, state); + if (need_resched()) +--- a/drivers/net/wireguard/selftest/counter.c ++++ b/drivers/net/wireguard/selftest/counter.c +@@ -6,18 +6,24 @@ + #ifdef DEBUG + bool __init wg_packet_counter_selftest(void) + { ++ struct noise_replay_counter *counter; + unsigned int test_num = 0, i; +- union noise_counter counter; + bool success = true; + +-#define T_INIT do { \ +- memset(&counter, 0, sizeof(union noise_counter)); \ +- spin_lock_init(&counter.receive.lock); \ ++ counter = kmalloc(sizeof(*counter), GFP_KERNEL); ++ if (unlikely(!counter)) { ++ pr_err("nonce counter self-test malloc: FAIL\n"); ++ return false; ++ } ++ ++#define T_INIT do { \ ++ memset(counter, 0, sizeof(*counter)); \ ++ spin_lock_init(&counter->lock); \ + } while (0) + #define T_LIM (COUNTER_WINDOW_SIZE + 1) + #define T(n, v) do { \ + ++test_num; \ +- if (counter_validate(&counter, n) != (v)) { \ ++ if (counter_validate(counter, n) != (v)) { \ + pr_err("nonce counter self-test %u: FAIL\n", \ + test_num); \ + success = false; \ +@@ -99,6 +105,7 @@ bool __init wg_packet_counter_selftest(v + + if (success) + pr_info("nonce counter self-tests: pass\n"); ++ kfree(counter); + return success; + } + #endif +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -129,7 +129,7 @@ static void keep_key_fresh(struct wg_pee + rcu_read_lock_bh(); + keypair = rcu_dereference_bh(peer->keypairs.current_keypair); + send = keypair && READ_ONCE(keypair->sending.is_valid) && +- (atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES || ++ (atomic64_read(&keypair->sending_counter) > REKEY_AFTER_MESSAGES || + (keypair->i_am_the_initiator && + wg_birthdate_has_expired(keypair->sending.birthdate, REKEY_AFTER_TIME))); + rcu_read_unlock_bh(); +@@ -349,7 +349,6 @@ void wg_packet_purge_staged_packets(stru + + void wg_packet_send_staged_packets(struct wg_peer *peer) + { +- struct noise_symmetric_key *key; + struct noise_keypair *keypair; + struct sk_buff_head packets; + struct sk_buff *skb; +@@ -369,10 +368,9 @@ void wg_packet_send_staged_packets(struc + rcu_read_unlock_bh(); + if (unlikely(!keypair)) + goto out_nokey; +- key = &keypair->sending; +- if (unlikely(!READ_ONCE(key->is_valid))) ++ if (unlikely(!READ_ONCE(keypair->sending.is_valid))) + goto out_nokey; +- if (unlikely(wg_birthdate_has_expired(key->birthdate, ++ if (unlikely(wg_birthdate_has_expired(keypair->sending.birthdate, + REJECT_AFTER_TIME))) + goto out_invalid; + +@@ -387,7 +385,7 @@ void wg_packet_send_staged_packets(struc + */ + PACKET_CB(skb)->ds = ip_tunnel_ecn_encap(0, ip_hdr(skb), skb); + PACKET_CB(skb)->nonce = +- atomic64_inc_return(&key->counter.counter) - 1; ++ atomic64_inc_return(&keypair->sending_counter) - 1; + if (unlikely(PACKET_CB(skb)->nonce >= REJECT_AFTER_MESSAGES)) + goto out_invalid; + } +@@ -399,7 +397,7 @@ void wg_packet_send_staged_packets(struc + return; + + out_invalid: +- WRITE_ONCE(key->is_valid, false); ++ WRITE_ONCE(keypair->sending.is_valid, false); + out_nokey: + wg_noise_keypair_put(keypair, false); + diff --git a/ipq806x/backport-5.4/080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch b/ipq806x/backport-5.4/080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch new file mode 100644 index 0000000..a53c764 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0106-wireguard-noise-do-not-assign-initiation-time-in-if-.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Frank Werner-Krippendorf +Date: Tue, 23 Jun 2020 03:59:44 -0600 +Subject: [PATCH] wireguard: noise: do not assign initiation time in if + condition + +commit 558b353c9c2a717509f291c066c6bd8f5f5e21be upstream. + +Fixes an error condition reported by checkpatch.pl which caused by +assigning a variable in an if condition in wg_noise_handshake_consume_ +initiation(). + +Signed-off-by: Frank Werner-Krippendorf +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/noise.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireguard/noise.c ++++ b/drivers/net/wireguard/noise.c +@@ -617,8 +617,8 @@ wg_noise_handshake_consume_initiation(st + memcpy(handshake->hash, hash, NOISE_HASH_LEN); + memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN); + handshake->remote_index = src->sender_index; +- if ((s64)(handshake->last_initiation_consumption - +- (initiation_consumption = ktime_get_coarse_boottime_ns())) < 0) ++ initiation_consumption = ktime_get_coarse_boottime_ns(); ++ if ((s64)(handshake->last_initiation_consumption - initiation_consumption) < 0) + handshake->last_initiation_consumption = initiation_consumption; + handshake->state = HANDSHAKE_CONSUMED_INITIATION; + up_write(&handshake->lock); diff --git a/ipq806x/backport-5.4/080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch b/ipq806x/backport-5.4/080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch new file mode 100644 index 0000000..013023a --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0107-wireguard-device-avoid-circular-netns-references.patch @@ -0,0 +1,296 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 23 Jun 2020 03:59:45 -0600 +Subject: [PATCH] wireguard: device: avoid circular netns references + +commit 900575aa33a3eaaef802b31de187a85c4a4b4bd0 upstream. + +Before, we took a reference to the creating netns if the new netns was +different. This caused issues with circular references, with two +wireguard interfaces swapping namespaces. The solution is to rather not +take any extra references at all, but instead simply invalidate the +creating netns pointer when that netns is deleted. + +In order to prevent this from happening again, this commit improves the +rough object leak tracking by allowing it to account for created and +destroyed interfaces, aside from just peers and keys. That then makes it +possible to check for the object leak when having two interfaces take a +reference to each others' namespaces. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 58 ++++++++++------------ + drivers/net/wireguard/device.h | 3 +- + drivers/net/wireguard/netlink.c | 14 ++++-- + drivers/net/wireguard/socket.c | 25 +++++++--- + tools/testing/selftests/wireguard/netns.sh | 13 ++++- + 5 files changed, 67 insertions(+), 46 deletions(-) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -45,17 +45,18 @@ static int wg_open(struct net_device *de + if (dev_v6) + dev_v6->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_NONE; + ++ mutex_lock(&wg->device_update_lock); + ret = wg_socket_init(wg, wg->incoming_port); + if (ret < 0) +- return ret; +- mutex_lock(&wg->device_update_lock); ++ goto out; + list_for_each_entry(peer, &wg->peer_list, peer_list) { + wg_packet_send_staged_packets(peer); + if (peer->persistent_keepalive_interval) + wg_packet_send_keepalive(peer); + } ++out: + mutex_unlock(&wg->device_update_lock); +- return 0; ++ return ret; + } + + #ifdef CONFIG_PM_SLEEP +@@ -225,6 +226,7 @@ static void wg_destruct(struct net_devic + list_del(&wg->device_list); + rtnl_unlock(); + mutex_lock(&wg->device_update_lock); ++ rcu_assign_pointer(wg->creating_net, NULL); + wg->incoming_port = 0; + wg_socket_reinit(wg, NULL, NULL); + /* The final references are cleared in the below calls to destroy_workqueue. */ +@@ -240,13 +242,11 @@ static void wg_destruct(struct net_devic + skb_queue_purge(&wg->incoming_handshakes); + free_percpu(dev->tstats); + free_percpu(wg->incoming_handshakes_worker); +- if (wg->have_creating_net_ref) +- put_net(wg->creating_net); + kvfree(wg->index_hashtable); + kvfree(wg->peer_hashtable); + mutex_unlock(&wg->device_update_lock); + +- pr_debug("%s: Interface deleted\n", dev->name); ++ pr_debug("%s: Interface destroyed\n", dev->name); + free_netdev(dev); + } + +@@ -292,7 +292,7 @@ static int wg_newlink(struct net *src_ne + struct wg_device *wg = netdev_priv(dev); + int ret = -ENOMEM; + +- wg->creating_net = src_net; ++ rcu_assign_pointer(wg->creating_net, src_net); + init_rwsem(&wg->static_identity.lock); + mutex_init(&wg->socket_update_lock); + mutex_init(&wg->device_update_lock); +@@ -393,30 +393,26 @@ static struct rtnl_link_ops link_ops __r + .newlink = wg_newlink, + }; + +-static int wg_netdevice_notification(struct notifier_block *nb, +- unsigned long action, void *data) ++static void wg_netns_pre_exit(struct net *net) + { +- struct net_device *dev = ((struct netdev_notifier_info *)data)->dev; +- struct wg_device *wg = netdev_priv(dev); +- +- ASSERT_RTNL(); +- +- if (action != NETDEV_REGISTER || dev->netdev_ops != &netdev_ops) +- return 0; ++ struct wg_device *wg; + +- if (dev_net(dev) == wg->creating_net && wg->have_creating_net_ref) { +- put_net(wg->creating_net); +- wg->have_creating_net_ref = false; +- } else if (dev_net(dev) != wg->creating_net && +- !wg->have_creating_net_ref) { +- wg->have_creating_net_ref = true; +- get_net(wg->creating_net); ++ rtnl_lock(); ++ list_for_each_entry(wg, &device_list, device_list) { ++ if (rcu_access_pointer(wg->creating_net) == net) { ++ pr_debug("%s: Creating namespace exiting\n", wg->dev->name); ++ netif_carrier_off(wg->dev); ++ mutex_lock(&wg->device_update_lock); ++ rcu_assign_pointer(wg->creating_net, NULL); ++ wg_socket_reinit(wg, NULL, NULL); ++ mutex_unlock(&wg->device_update_lock); ++ } + } +- return 0; ++ rtnl_unlock(); + } + +-static struct notifier_block netdevice_notifier = { +- .notifier_call = wg_netdevice_notification ++static struct pernet_operations pernet_ops = { ++ .pre_exit = wg_netns_pre_exit + }; + + int __init wg_device_init(void) +@@ -429,18 +425,18 @@ int __init wg_device_init(void) + return ret; + #endif + +- ret = register_netdevice_notifier(&netdevice_notifier); ++ ret = register_pernet_device(&pernet_ops); + if (ret) + goto error_pm; + + ret = rtnl_link_register(&link_ops); + if (ret) +- goto error_netdevice; ++ goto error_pernet; + + return 0; + +-error_netdevice: +- unregister_netdevice_notifier(&netdevice_notifier); ++error_pernet: ++ unregister_pernet_device(&pernet_ops); + error_pm: + #ifdef CONFIG_PM_SLEEP + unregister_pm_notifier(&pm_notifier); +@@ -451,7 +447,7 @@ error_pm: + void wg_device_uninit(void) + { + rtnl_link_unregister(&link_ops); +- unregister_netdevice_notifier(&netdevice_notifier); ++ unregister_pernet_device(&pernet_ops); + #ifdef CONFIG_PM_SLEEP + unregister_pm_notifier(&pm_notifier); + #endif +--- a/drivers/net/wireguard/device.h ++++ b/drivers/net/wireguard/device.h +@@ -40,7 +40,7 @@ struct wg_device { + struct net_device *dev; + struct crypt_queue encrypt_queue, decrypt_queue; + struct sock __rcu *sock4, *sock6; +- struct net *creating_net; ++ struct net __rcu *creating_net; + struct noise_static_identity static_identity; + struct workqueue_struct *handshake_receive_wq, *handshake_send_wq; + struct workqueue_struct *packet_crypt_wq; +@@ -56,7 +56,6 @@ struct wg_device { + unsigned int num_peers, device_update_gen; + u32 fwmark; + u16 incoming_port; +- bool have_creating_net_ref; + }; + + int wg_device_init(void); +--- a/drivers/net/wireguard/netlink.c ++++ b/drivers/net/wireguard/netlink.c +@@ -517,11 +517,15 @@ static int wg_set_device(struct sk_buff + if (flags & ~__WGDEVICE_F_ALL) + goto out; + +- ret = -EPERM; +- if ((info->attrs[WGDEVICE_A_LISTEN_PORT] || +- info->attrs[WGDEVICE_A_FWMARK]) && +- !ns_capable(wg->creating_net->user_ns, CAP_NET_ADMIN)) +- goto out; ++ if (info->attrs[WGDEVICE_A_LISTEN_PORT] || info->attrs[WGDEVICE_A_FWMARK]) { ++ struct net *net; ++ rcu_read_lock(); ++ net = rcu_dereference(wg->creating_net); ++ ret = !net || !ns_capable(net->user_ns, CAP_NET_ADMIN) ? -EPERM : 0; ++ rcu_read_unlock(); ++ if (ret) ++ goto out; ++ } + + ++wg->device_update_gen; + +--- a/drivers/net/wireguard/socket.c ++++ b/drivers/net/wireguard/socket.c +@@ -347,6 +347,7 @@ static void set_sock_opts(struct socket + + int wg_socket_init(struct wg_device *wg, u16 port) + { ++ struct net *net; + int ret; + struct udp_tunnel_sock_cfg cfg = { + .sk_user_data = wg, +@@ -371,37 +372,47 @@ int wg_socket_init(struct wg_device *wg, + }; + #endif + ++ rcu_read_lock(); ++ net = rcu_dereference(wg->creating_net); ++ net = net ? maybe_get_net(net) : NULL; ++ rcu_read_unlock(); ++ if (unlikely(!net)) ++ return -ENONET; ++ + #if IS_ENABLED(CONFIG_IPV6) + retry: + #endif + +- ret = udp_sock_create(wg->creating_net, &port4, &new4); ++ ret = udp_sock_create(net, &port4, &new4); + if (ret < 0) { + pr_err("%s: Could not create IPv4 socket\n", wg->dev->name); +- return ret; ++ goto out; + } + set_sock_opts(new4); +- setup_udp_tunnel_sock(wg->creating_net, new4, &cfg); ++ setup_udp_tunnel_sock(net, new4, &cfg); + + #if IS_ENABLED(CONFIG_IPV6) + if (ipv6_mod_enabled()) { + port6.local_udp_port = inet_sk(new4->sk)->inet_sport; +- ret = udp_sock_create(wg->creating_net, &port6, &new6); ++ ret = udp_sock_create(net, &port6, &new6); + if (ret < 0) { + udp_tunnel_sock_release(new4); + if (ret == -EADDRINUSE && !port && retries++ < 100) + goto retry; + pr_err("%s: Could not create IPv6 socket\n", + wg->dev->name); +- return ret; ++ goto out; + } + set_sock_opts(new6); +- setup_udp_tunnel_sock(wg->creating_net, new6, &cfg); ++ setup_udp_tunnel_sock(net, new6, &cfg); + } + #endif + + wg_socket_reinit(wg, new4->sk, new6 ? new6->sk : NULL); +- return 0; ++ ret = 0; ++out: ++ put_net(net); ++ return ret; + } + + void wg_socket_reinit(struct wg_device *wg, struct sock *new4, +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -587,9 +587,20 @@ ip0 link set wg0 up + kill $ncat_pid + ip0 link del wg0 + ++# Ensure there aren't circular reference loops ++ip1 link add wg1 type wireguard ++ip2 link add wg2 type wireguard ++ip1 link set wg1 netns $netns2 ++ip2 link set wg2 netns $netns1 ++pp ip netns delete $netns1 ++pp ip netns delete $netns2 ++pp ip netns add $netns1 ++pp ip netns add $netns2 ++ ++sleep 2 # Wait for cleanup and grace periods + declare -A objects + while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do +- [[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue ++ [[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ ?[0-9]*)\ .*(created|destroyed).* ]] || continue + objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}" + done < /dev/kmsg + alldeleted=1 diff --git a/ipq806x/backport-5.4/080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch b/ipq806x/backport-5.4/080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch new file mode 100644 index 0000000..eceb0b9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0108-wireguard-receive-account-for-napi_gro_receive-never.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 24 Jun 2020 16:06:03 -0600 +Subject: [PATCH] wireguard: receive: account for napi_gro_receive never + returning GRO_DROP + +commit df08126e3833e9dca19e2407db5f5860a7c194fb upstream. + +The napi_gro_receive function no longer returns GRO_DROP ever, making +handling GRO_DROP dead code. This commit removes that dead code. +Further, it's not even clear that device drivers have any business in +taking action after passing off received packets; that's arguably out of +their hands. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Fixes: 6570bc79c0df ("net: core: use listified Rx for GRO_NORMAL in napi_gro_receive()") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/receive.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -414,14 +414,8 @@ static void wg_packet_consume_data_done( + if (unlikely(routed_peer != peer)) + goto dishonest_packet_peer; + +- if (unlikely(napi_gro_receive(&peer->napi, skb) == GRO_DROP)) { +- ++dev->stats.rx_dropped; +- net_dbg_ratelimited("%s: Failed to give packet to userspace from peer %llu (%pISpfsc)\n", +- dev->name, peer->internal_id, +- &peer->endpoint.addr); +- } else { +- update_rx_stats(peer, message_data_len(len_before_trim)); +- } ++ napi_gro_receive(&peer->napi, skb); ++ update_rx_stats(peer, message_data_len(len_before_trim)); + return; + + dishonest_packet_peer: diff --git a/ipq806x/backport-5.4/080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch b/ipq806x/backport-5.4/080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch new file mode 100644 index 0000000..cfd6b14 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0109-net-ip_tunnel-add-header_ops-for-layer-3-devices.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 29 Jun 2020 19:06:18 -0600 +Subject: [PATCH] net: ip_tunnel: add header_ops for layer 3 devices + +commit 2606aff916854b61234bf85001be9777bab2d5f8 upstream. + +Some devices that take straight up layer 3 packets benefit from having a +shared header_ops so that AF_PACKET sockets can inject packets that are +recognized. This shared infrastructure will be used by other drivers +that currently can't inject packets using AF_PACKET. It also exposes the +parser function, as it is useful in standalone form too. + +Signed-off-by: Jason A. Donenfeld +Acked-by: Willem de Bruijn +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + include/net/ip_tunnels.h | 3 +++ + net/ipv4/ip_tunnel_core.c | 18 ++++++++++++++++++ + 2 files changed, 21 insertions(+) + +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -289,6 +289,9 @@ int ip_tunnel_newlink(struct net_device + struct ip_tunnel_parm *p, __u32 fwmark); + void ip_tunnel_setup(struct net_device *dev, unsigned int net_id); + ++extern const struct header_ops ip_tunnel_header_ops; ++__be16 ip_tunnel_parse_protocol(const struct sk_buff *skb); ++ + struct ip_tunnel_encap_ops { + size_t (*encap_hlen)(struct ip_tunnel_encap *e); + int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e, +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -446,3 +446,21 @@ void ip_tunnel_unneed_metadata(void) + static_branch_dec(&ip_tunnel_metadata_cnt); + } + EXPORT_SYMBOL_GPL(ip_tunnel_unneed_metadata); ++ ++/* Returns either the correct skb->protocol value, or 0 if invalid. */ ++__be16 ip_tunnel_parse_protocol(const struct sk_buff *skb) ++{ ++ if (skb_network_header(skb) >= skb->head && ++ (skb_network_header(skb) + sizeof(struct iphdr)) <= skb_tail_pointer(skb) && ++ ip_hdr(skb)->version == 4) ++ return htons(ETH_P_IP); ++ if (skb_network_header(skb) >= skb->head && ++ (skb_network_header(skb) + sizeof(struct ipv6hdr)) <= skb_tail_pointer(skb) && ++ ipv6_hdr(skb)->version == 6) ++ return htons(ETH_P_IPV6); ++ return 0; ++} ++EXPORT_SYMBOL(ip_tunnel_parse_protocol); ++ ++const struct header_ops ip_tunnel_header_ops = { .parse_protocol = ip_tunnel_parse_protocol }; ++EXPORT_SYMBOL(ip_tunnel_header_ops); diff --git a/ipq806x/backport-5.4/080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch b/ipq806x/backport-5.4/080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch new file mode 100644 index 0000000..415ecff --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0110-wireguard-implement-header_ops-parse_protocol-for-AF.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 29 Jun 2020 19:06:20 -0600 +Subject: [PATCH] wireguard: implement header_ops->parse_protocol for AF_PACKET + +commit 01a4967c71c004f8ecad4ab57021348636502fa9 upstream. + +WireGuard uses skb->protocol to determine packet type, and bails out if +it's not set or set to something it's not expecting. For AF_PACKET +injection, we need to support its call chain of: + + packet_sendmsg -> packet_snd -> packet_parse_headers -> + dev_parse_header_protocol -> parse_protocol + +Without a valid parse_protocol, this returns zero, and wireguard then +rejects the skb. So, this wires up the ip_tunnel handler for layer 3 +packets for that case. + +Reported-by: Hans Wippel +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -262,6 +262,7 @@ static void wg_setup(struct net_device * + max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); + + dev->netdev_ops = &netdev_ops; ++ dev->header_ops = &ip_tunnel_header_ops; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->needed_headroom = DATA_PACKET_HEAD_ROOM; diff --git a/ipq806x/backport-5.4/080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch b/ipq806x/backport-5.4/080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch new file mode 100644 index 0000000..a777732 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0111-wireguard-queueing-make-use-of-ip_tunnel_parse_proto.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 29 Jun 2020 19:06:21 -0600 +Subject: [PATCH] wireguard: queueing: make use of ip_tunnel_parse_protocol + +commit 1a574074ae7d1d745c16f7710655f38a53174c27 upstream. + +Now that wg_examine_packet_protocol has been added for general +consumption as ip_tunnel_parse_protocol, it's possible to remove +wg_examine_packet_protocol and simply use the new +ip_tunnel_parse_protocol function directly. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/queueing.h | 19 ++----------------- + drivers/net/wireguard/receive.c | 2 +- + 2 files changed, 3 insertions(+), 18 deletions(-) + +--- a/drivers/net/wireguard/queueing.h ++++ b/drivers/net/wireguard/queueing.h +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + struct wg_device; + struct wg_peer; +@@ -65,25 +66,9 @@ struct packet_cb { + #define PACKET_CB(skb) ((struct packet_cb *)((skb)->cb)) + #define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer) + +-/* Returns either the correct skb->protocol value, or 0 if invalid. */ +-static inline __be16 wg_examine_packet_protocol(struct sk_buff *skb) +-{ +- if (skb_network_header(skb) >= skb->head && +- (skb_network_header(skb) + sizeof(struct iphdr)) <= +- skb_tail_pointer(skb) && +- ip_hdr(skb)->version == 4) +- return htons(ETH_P_IP); +- if (skb_network_header(skb) >= skb->head && +- (skb_network_header(skb) + sizeof(struct ipv6hdr)) <= +- skb_tail_pointer(skb) && +- ipv6_hdr(skb)->version == 6) +- return htons(ETH_P_IPV6); +- return 0; +-} +- + static inline bool wg_check_packet_protocol(struct sk_buff *skb) + { +- __be16 real_protocol = wg_examine_packet_protocol(skb); ++ __be16 real_protocol = ip_tunnel_parse_protocol(skb); + return real_protocol && skb->protocol == real_protocol; + } + +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -387,7 +387,7 @@ static void wg_packet_consume_data_done( + */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->csum_level = ~0; /* All levels */ +- skb->protocol = wg_examine_packet_protocol(skb); ++ skb->protocol = ip_tunnel_parse_protocol(skb); + if (skb->protocol == htons(ETH_P_IP)) { + len = ntohs(ip_hdr(skb)->tot_len); + if (unlikely(len < sizeof(struct iphdr))) diff --git a/ipq806x/backport-5.4/080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch b/ipq806x/backport-5.4/080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch new file mode 100644 index 0000000..4b2712b --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0112-netlink-consistently-use-NLA_POLICY_EXACT_LEN.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Tue, 18 Aug 2020 10:17:31 +0200 +Subject: [PATCH] netlink: consistently use NLA_POLICY_EXACT_LEN() + +commit 8140860c817f3e9f78bcd1e420b9777ddcbaa629 upstream. + +Change places that open-code NLA_POLICY_EXACT_LEN() to +use the macro instead, giving us flexibility in how we +handle the details of the macro. + +Signed-off-by: Johannes Berg +Acked-by: Matthieu Baerts +Signed-off-by: David S. Miller +[Jason: only picked the drivers/net/wireguard/* part] +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/netlink.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireguard/netlink.c ++++ b/drivers/net/wireguard/netlink.c +@@ -22,8 +22,8 @@ static struct genl_family genl_family; + static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = { + [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, + [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, +- [WGDEVICE_A_PRIVATE_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN }, +- [WGDEVICE_A_PUBLIC_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN }, ++ [WGDEVICE_A_PRIVATE_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN), ++ [WGDEVICE_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN), + [WGDEVICE_A_FLAGS] = { .type = NLA_U32 }, + [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 }, + [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, +@@ -31,12 +31,12 @@ static const struct nla_policy device_po + }; + + static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = { +- [WGPEER_A_PUBLIC_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_PUBLIC_KEY_LEN }, +- [WGPEER_A_PRESHARED_KEY] = { .type = NLA_EXACT_LEN, .len = NOISE_SYMMETRIC_KEY_LEN }, ++ [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN), ++ [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN), + [WGPEER_A_FLAGS] = { .type = NLA_U32 }, + [WGPEER_A_ENDPOINT] = { .type = NLA_MIN_LEN, .len = sizeof(struct sockaddr) }, + [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 }, +- [WGPEER_A_LAST_HANDSHAKE_TIME] = { .type = NLA_EXACT_LEN, .len = sizeof(struct __kernel_timespec) }, ++ [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)), + [WGPEER_A_RX_BYTES] = { .type = NLA_U64 }, + [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, + [WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED }, diff --git a/ipq806x/backport-5.4/080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch b/ipq806x/backport-5.4/080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch new file mode 100644 index 0000000..4b414bc --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0113-netlink-consistently-use-NLA_POLICY_MIN_LEN.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Tue, 18 Aug 2020 10:17:32 +0200 +Subject: [PATCH] netlink: consistently use NLA_POLICY_MIN_LEN() + +commit bc0435855041d7fff0b83dd992fc4be34aa11afb upstream. + +Change places that open-code NLA_POLICY_MIN_LEN() to +use the macro instead, giving us flexibility in how we +handle the details of the macro. + +Signed-off-by: Johannes Berg +Signed-off-by: David S. Miller +[Jason: only picked the drivers/net/wireguard/* part] +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/netlink.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireguard/netlink.c ++++ b/drivers/net/wireguard/netlink.c +@@ -34,7 +34,7 @@ static const struct nla_policy peer_poli + [WGPEER_A_PUBLIC_KEY] = NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN), + [WGPEER_A_PRESHARED_KEY] = NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN), + [WGPEER_A_FLAGS] = { .type = NLA_U32 }, +- [WGPEER_A_ENDPOINT] = { .type = NLA_MIN_LEN, .len = sizeof(struct sockaddr) }, ++ [WGPEER_A_ENDPOINT] = NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)), + [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 }, + [WGPEER_A_LAST_HANDSHAKE_TIME] = NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)), + [WGPEER_A_RX_BYTES] = { .type = NLA_U64 }, +@@ -45,7 +45,7 @@ static const struct nla_policy peer_poli + + static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = { + [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, +- [WGALLOWEDIP_A_IPADDR] = { .type = NLA_MIN_LEN, .len = sizeof(struct in_addr) }, ++ [WGALLOWEDIP_A_IPADDR] = NLA_POLICY_MIN_LEN(sizeof(struct in_addr)), + [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 } + }; + diff --git a/ipq806x/backport-5.4/080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch b/ipq806x/backport-5.4/080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch new file mode 100644 index 0000000..e80528c --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0114-wireguard-noise-take-lock-when-removing-handshake-en.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 9 Sep 2020 13:58:14 +0200 +Subject: [PATCH] wireguard: noise: take lock when removing handshake entry + from table + +commit 9179ba31367bcf481c3c79b5f028c94faad9f30a upstream. + +Eric reported that syzkaller found a race of this variety: + +CPU 1 CPU 2 +-------------------------------------------|--------------------------------------- +wg_index_hashtable_replace(old, ...) | + if (hlist_unhashed(&old->index_hash)) | + | wg_index_hashtable_remove(old) + | hlist_del_init_rcu(&old->index_hash) + | old->index_hash.pprev = NULL + hlist_replace_rcu(&old->index_hash, ...) | + *old->index_hash.pprev | + +Syzbot wasn't actually able to reproduce this more than once or create a +reproducer, because the race window between checking "hlist_unhashed" and +calling "hlist_replace_rcu" is just so small. Adding an mdelay(5) or +similar there helps make this demonstrable using this simple script: + + #!/bin/bash + set -ex + trap 'kill $pid1; kill $pid2; ip link del wg0; ip link del wg1' EXIT + ip link add wg0 type wireguard + ip link add wg1 type wireguard + wg set wg0 private-key <(wg genkey) listen-port 9999 + wg set wg1 private-key <(wg genkey) peer $(wg show wg0 public-key) endpoint 127.0.0.1:9999 persistent-keepalive 1 + wg set wg0 peer $(wg show wg1 public-key) + ip link set wg0 up + yes link set wg1 up | ip -force -batch - & + pid1=$! + yes link set wg1 down | ip -force -batch - & + pid2=$! + wait + +The fundumental underlying problem is that we permit calls to wg_index_ +hashtable_remove(handshake.entry) without requiring the caller to take +the handshake mutex that is intended to protect members of handshake +during mutations. This is consistently the case with calls to wg_index_ +hashtable_insert(handshake.entry) and wg_index_hashtable_replace( +handshake.entry), but it's missing from a pertinent callsite of wg_ +index_hashtable_remove(handshake.entry). So, this patch makes sure that +mutex is taken. + +The original code was a little bit funky though, in the form of: + + remove(handshake.entry) + lock(), memzero(handshake.some_members), unlock() + remove(handshake.entry) + +The original intention of that double removal pattern outside the lock +appears to be some attempt to prevent insertions that might happen while +locks are dropped during expensive crypto operations, but actually, all +callers of wg_index_hashtable_insert(handshake.entry) take the write +lock and then explicitly check handshake.state, as they should, which +the aforementioned memzero clears, which means an insertion should +already be impossible. And regardless, the original intention was +necessarily racy, since it wasn't guaranteed that something else would +run after the unlock() instead of after the remove(). So, from a +soundness perspective, it seems positive to remove what looks like a +hack at best. + +The crash from both syzbot and from the script above is as follows: + + general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + CPU: 0 PID: 7395 Comm: kworker/0:3 Not tainted 5.9.0-rc4-syzkaller #0 + Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 + Workqueue: wg-kex-wg1 wg_packet_handshake_receive_worker + RIP: 0010:hlist_replace_rcu include/linux/rculist.h:505 [inline] + RIP: 0010:wg_index_hashtable_replace+0x176/0x330 drivers/net/wireguard/peerlookup.c:174 + Code: 00 fc ff df 48 89 f9 48 c1 e9 03 80 3c 01 00 0f 85 44 01 00 00 48 b9 00 00 00 00 00 fc ff df 48 8b 45 10 48 89 c6 48 c1 ee 03 <80> 3c 0e 00 0f 85 06 01 00 00 48 85 d2 4c 89 28 74 47 e8 a3 4f b5 + RSP: 0018:ffffc90006a97bf8 EFLAGS: 00010246 + RAX: 0000000000000000 RBX: ffff888050ffc4f8 RCX: dffffc0000000000 + RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88808e04e010 + RBP: ffff88808e04e000 R08: 0000000000000001 R09: ffff8880543d0000 + R10: ffffed100a87a000 R11: 000000000000016e R12: ffff8880543d0000 + R13: ffff88808e04e008 R14: ffff888050ffc508 R15: ffff888050ffc500 + FS: 0000000000000000(0000) GS:ffff8880ae600000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00000000f5505db0 CR3: 0000000097cf7000 CR4: 00000000001526f0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + Call Trace: + wg_noise_handshake_begin_session+0x752/0xc9a drivers/net/wireguard/noise.c:820 + wg_receive_handshake_packet drivers/net/wireguard/receive.c:183 [inline] + wg_packet_handshake_receive_worker+0x33b/0x730 drivers/net/wireguard/receive.c:220 + process_one_work+0x94c/0x1670 kernel/workqueue.c:2269 + worker_thread+0x64c/0x1120 kernel/workqueue.c:2415 + kthread+0x3b5/0x4a0 kernel/kthread.c:292 + ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:294 + +Reported-by: syzbot +Reported-by: Eric Dumazet +Link: https://lore.kernel.org/wireguard/20200908145911.4090480-1-edumazet@google.com/ +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/noise.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +--- a/drivers/net/wireguard/noise.c ++++ b/drivers/net/wireguard/noise.c +@@ -87,15 +87,12 @@ static void handshake_zero(struct noise_ + + void wg_noise_handshake_clear(struct noise_handshake *handshake) + { ++ down_write(&handshake->lock); + wg_index_hashtable_remove( + handshake->entry.peer->device->index_hashtable, + &handshake->entry); +- down_write(&handshake->lock); + handshake_zero(handshake); + up_write(&handshake->lock); +- wg_index_hashtable_remove( +- handshake->entry.peer->device->index_hashtable, +- &handshake->entry); + } + + static struct noise_keypair *keypair_create(struct wg_peer *peer) diff --git a/ipq806x/backport-5.4/080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch b/ipq806x/backport-5.4/080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch new file mode 100644 index 0000000..e7f46dd --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0115-wireguard-peerlookup-take-lock-before-checking-hash-.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Wed, 9 Sep 2020 13:58:15 +0200 +Subject: [PATCH] wireguard: peerlookup: take lock before checking hash in + replace operation + +commit 6147f7b1e90ff09bd52afc8b9206a7fcd133daf7 upstream. + +Eric's suggested fix for the previous commit's mentioned race condition +was to simply take the table->lock in wg_index_hashtable_replace(). The +table->lock of the hash table is supposed to protect the bucket heads, +not the entires, but actually, since all the mutator functions are +already taking it, it makes sense to take it too for the test to +hlist_unhashed, as a defense in depth measure, so that it no longer +races with deletions, regardless of what other locks are protecting +individual entries. This is sensible from a performance perspective +because, as Eric pointed out, the case of being unhashed is already the +unlikely case, so this won't add common contention. And comparing +instructions, this basically doesn't make much of a difference other +than pushing and popping %r13, used by the new `bool ret`. More +generally, I like the idea of locking consistency across table mutator +functions, and this might let me rest slightly easier at night. + +Suggested-by: Eric Dumazet +Link: https://lore.kernel.org/wireguard/20200908145911.4090480-1-edumazet@google.com/ +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/peerlookup.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireguard/peerlookup.c ++++ b/drivers/net/wireguard/peerlookup.c +@@ -167,9 +167,13 @@ bool wg_index_hashtable_replace(struct i + struct index_hashtable_entry *old, + struct index_hashtable_entry *new) + { +- if (unlikely(hlist_unhashed(&old->index_hash))) +- return false; ++ bool ret; ++ + spin_lock_bh(&table->lock); ++ ret = !hlist_unhashed(&old->index_hash); ++ if (unlikely(!ret)) ++ goto out; ++ + new->index = old->index; + hlist_replace_rcu(&old->index_hash, &new->index_hash); + +@@ -180,8 +184,9 @@ bool wg_index_hashtable_replace(struct i + * simply gets dropped, which isn't terrible. + */ + INIT_HLIST_NODE(&old->index_hash); ++out: + spin_unlock_bh(&table->lock); +- return true; ++ return ret; + } + + void wg_index_hashtable_remove(struct index_hashtable *table, diff --git a/ipq806x/backport-5.4/080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch b/ipq806x/backport-5.4/080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch new file mode 100644 index 0000000..09c1b0b --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0116-wireguard-selftests-check-that-route_me_harder-packe.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Thu, 29 Oct 2020 03:56:05 +0100 +Subject: [PATCH] wireguard: selftests: check that route_me_harder packets use + the right sk + +commit af8afcf1fdd5f365f70e2386c2d8c7a1abd853d7 upstream. + +If netfilter changes the packet mark, the packet is rerouted. The +ip_route_me_harder family of functions fails to use the right sk, opting +to instead use skb->sk, resulting in a routing loop when used with +tunnels. With the next change fixing this issue in netfilter, test for +the relevant condition inside our test suite, since wireguard was where +the bug was discovered. + +Reported-by: Chen Minqiang +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/netns.sh | 8 ++++++++ + tools/testing/selftests/wireguard/qemu/kernel.config | 2 ++ + 2 files changed, 10 insertions(+) + +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -316,6 +316,14 @@ pp sleep 3 + n2 ping -W 1 -c 1 192.168.241.1 + n1 wg set wg0 peer "$pub2" persistent-keepalive 0 + ++# Test that sk_bound_dev_if works ++n1 ping -I wg0 -c 1 -W 1 192.168.241.2 ++# What about when the mark changes and the packet must be rerouted? ++n1 iptables -t mangle -I OUTPUT -j MARK --set-xmark 1 ++n1 ping -c 1 -W 1 192.168.241.2 # First the boring case ++n1 ping -I wg0 -c 1 -W 1 192.168.241.2 # Then the sk_bound_dev_if case ++n1 iptables -t mangle -D OUTPUT -j MARK --set-xmark 1 ++ + # Test that onion routing works, even when it loops + n1 wg set wg0 peer "$pub3" allowed-ips 192.168.242.2/32 endpoint 192.168.241.2:5 + ip1 addr add 192.168.242.1/24 dev wg0 +--- a/tools/testing/selftests/wireguard/qemu/kernel.config ++++ b/tools/testing/selftests/wireguard/qemu/kernel.config +@@ -18,10 +18,12 @@ CONFIG_NF_NAT=y + CONFIG_NETFILTER_XTABLES=y + CONFIG_NETFILTER_XT_NAT=y + CONFIG_NETFILTER_XT_MATCH_LENGTH=y ++CONFIG_NETFILTER_XT_MARK=y + CONFIG_NF_CONNTRACK_IPV4=y + CONFIG_NF_NAT_IPV4=y + CONFIG_IP_NF_IPTABLES=y + CONFIG_IP_NF_FILTER=y ++CONFIG_IP_NF_MANGLE=y + CONFIG_IP_NF_NAT=y + CONFIG_IP_ADVANCED_ROUTER=y + CONFIG_IP_MULTIPLE_TABLES=y diff --git a/ipq806x/backport-5.4/080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch b/ipq806x/backport-5.4/080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch new file mode 100644 index 0000000..7dfc1bb --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0117-wireguard-avoid-double-unlikely-notation-when-using-.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antonio Quartulli +Date: Mon, 22 Feb 2021 17:25:43 +0100 +Subject: [PATCH] wireguard: avoid double unlikely() notation when using + IS_ERR() + +commit 30ac4e2f54ec067b7b9ca0db27e75681581378d6 upstream. + +The definition of IS_ERR() already applies the unlikely() notation +when checking the error status of the passed pointer. For this +reason there is no need to have the same notation outside of +IS_ERR() itself. + +Clean up code by removing redundant notation. + +Signed-off-by: Antonio Quartulli +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Jakub Kicinski +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 2 +- + drivers/net/wireguard/socket.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -157,7 +157,7 @@ static netdev_tx_t wg_xmit(struct sk_buf + } else { + struct sk_buff *segs = skb_gso_segment(skb, 0); + +- if (unlikely(IS_ERR(segs))) { ++ if (IS_ERR(segs)) { + ret = PTR_ERR(segs); + goto err_peer; + } +--- a/drivers/net/wireguard/socket.c ++++ b/drivers/net/wireguard/socket.c +@@ -71,7 +71,7 @@ static int send4(struct wg_device *wg, s + ip_rt_put(rt); + rt = ip_route_output_flow(sock_net(sock), &fl, sock); + } +- if (unlikely(IS_ERR(rt))) { ++ if (IS_ERR(rt)) { + ret = PTR_ERR(rt); + net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n", + wg->dev->name, &endpoint->addr, ret); +@@ -138,7 +138,7 @@ static int send6(struct wg_device *wg, s + } + dst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sock), sock, &fl, + NULL); +- if (unlikely(IS_ERR(dst))) { ++ if (IS_ERR(dst)) { + ret = PTR_ERR(dst); + net_dbg_ratelimited("%s: No route to %pISpfsc, error %d\n", + wg->dev->name, &endpoint->addr, ret); diff --git a/ipq806x/backport-5.4/080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch b/ipq806x/backport-5.4/080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch new file mode 100644 index 0000000..1796f54 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0118-wireguard-socket-remove-bogus-__be32-annotation.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Mon, 22 Feb 2021 17:25:44 +0100 +Subject: [PATCH] wireguard: socket: remove bogus __be32 annotation + +commit 7f57bd8dc22de35ddd895294aa554003e4f19a72 upstream. + +The endpoint->src_if4 has nothing to do with fixed-endian numbers; remove +the bogus annotation. + +This was introduced in +https://git.zx2c4.com/wireguard-monolithic-historical/commit?id=14e7d0a499a676ec55176c0de2f9fcbd34074a82 +in the historical WireGuard repo because the old code used to +zero-initialize multiple members as follows: + + endpoint->src4.s_addr = endpoint->src_if4 = fl.saddr = 0; + +Because fl.saddr is fixed-endian and an assignment returns a value with the +type of its left operand, this meant that sparse detected an assignment +between values of different endianness. + +Since then, this assignment was already split up into separate statements; +just the cast survived. + +Signed-off-by: Jann Horn +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Jakub Kicinski +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/socket.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireguard/socket.c ++++ b/drivers/net/wireguard/socket.c +@@ -53,7 +53,7 @@ static int send4(struct wg_device *wg, s + if (unlikely(!inet_confirm_addr(sock_net(sock), NULL, 0, + fl.saddr, RT_SCOPE_HOST))) { + endpoint->src4.s_addr = 0; +- *(__force __be32 *)&endpoint->src_if4 = 0; ++ endpoint->src_if4 = 0; + fl.saddr = 0; + if (cache) + dst_cache_reset(cache); +@@ -63,7 +63,7 @@ static int send4(struct wg_device *wg, s + PTR_ERR(rt) == -EINVAL) || (!IS_ERR(rt) && + rt->dst.dev->ifindex != endpoint->src_if4)))) { + endpoint->src4.s_addr = 0; +- *(__force __be32 *)&endpoint->src_if4 = 0; ++ endpoint->src_if4 = 0; + fl.saddr = 0; + if (cache) + dst_cache_reset(cache); diff --git a/ipq806x/backport-5.4/080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch b/ipq806x/backport-5.4/080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch new file mode 100644 index 0000000..3093de4 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0119-wireguard-selftests-test-multiple-parallel-streams.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 22 Feb 2021 17:25:45 +0100 +Subject: [PATCH] wireguard: selftests: test multiple parallel streams + +commit d5a49aa6c3e264a93a7d08485d66e346be0969dd upstream. + +In order to test ndo_start_xmit being called in parallel, explicitly add +separate tests, which should all run on different cores. This should +help tease out bugs associated with queueing up packets from different +cores in parallel. Currently, it hasn't found those types of bugs, but +given future planned work, this is a useful regression to avoid. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Jakub Kicinski +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/netns.sh | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -39,7 +39,7 @@ ip0() { pretty 0 "ip $*"; ip -n $netns0 + ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; } + ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; } + sleep() { read -t "$1" -N 1 || true; } +-waitiperf() { pretty "${1//*-}" "wait for iperf:5201 pid $2"; while [[ $(ss -N "$1" -tlpH 'sport = 5201') != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; } ++waitiperf() { pretty "${1//*-}" "wait for iperf:${3:-5201} pid $2"; while [[ $(ss -N "$1" -tlpH "sport = ${3:-5201}") != *\"iperf3\",pid=$2,fd=* ]]; do sleep 0.1; done; } + waitncatudp() { pretty "${1//*-}" "wait for udp:1111 pid $2"; while [[ $(ss -N "$1" -ulpH 'sport = 1111') != *\"ncat\",pid=$2,fd=* ]]; do sleep 0.1; done; } + waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; } + +@@ -141,6 +141,19 @@ tests() { + n2 iperf3 -s -1 -B fd00::2 & + waitiperf $netns2 $! + n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2 ++ ++ # TCP over IPv4, in parallel ++ for max in 4 5 50; do ++ local pids=( ) ++ for ((i=0; i < max; ++i)) do ++ n2 iperf3 -p $(( 5200 + i )) -s -1 -B 192.168.241.2 & ++ pids+=( $! ); waitiperf $netns2 $! $(( 5200 + i )) ++ done ++ for ((i=0; i < max; ++i)) do ++ n1 iperf3 -Z -t 3 -p $(( 5200 + i )) -c 192.168.241.2 & ++ done ++ wait "${pids[@]}" ++ done + } + + [[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}" diff --git a/ipq806x/backport-5.4/080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch b/ipq806x/backport-5.4/080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch new file mode 100644 index 0000000..69e76b9 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0120-wireguard-peer-put-frequently-used-members-above-cac.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 22 Feb 2021 17:25:46 +0100 +Subject: [PATCH] wireguard: peer: put frequently used members above cache + lines + +commit 5a0598695634a6bb4126818902dd9140cd9df8b6 upstream. + +The is_dead boolean is checked for every single packet, while the +internal_id member is used basically only for pr_debug messages. So it +makes sense to hoist up is_dead into some space formerly unused by a +struct hole, while demoting internal_api to below the lowest struct +cache line. + +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Jakub Kicinski +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/peer.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireguard/peer.h ++++ b/drivers/net/wireguard/peer.h +@@ -39,6 +39,7 @@ struct wg_peer { + struct crypt_queue tx_queue, rx_queue; + struct sk_buff_head staged_packet_queue; + int serial_work_cpu; ++ bool is_dead; + struct noise_keypairs keypairs; + struct endpoint endpoint; + struct dst_cache endpoint_cache; +@@ -61,9 +62,8 @@ struct wg_peer { + struct rcu_head rcu; + struct list_head peer_list; + struct list_head allowedips_list; +- u64 internal_id; + struct napi_struct napi; +- bool is_dead; ++ u64 internal_id; + }; + + struct wg_peer *wg_peer_create(struct wg_device *wg, diff --git a/ipq806x/backport-5.4/080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch b/ipq806x/backport-5.4/080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch new file mode 100644 index 0000000..073ee9b --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0121-wireguard-device-do-not-generate-ICMP-for-non-IP-pac.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 22 Feb 2021 17:25:47 +0100 +Subject: [PATCH] wireguard: device: do not generate ICMP for non-IP packets + +commit 99fff5264e7ab06f45b0ad60243475be0a8d0559 upstream. + +If skb->protocol doesn't match the actual skb->data header, it's +probably not a good idea to pass it off to icmp{,v6}_ndo_send, which is +expecting to reply to a valid IP packet. So this commit has that early +mismatch case jump to a later error label. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Jakub Kicinski +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -138,7 +138,7 @@ static netdev_tx_t wg_xmit(struct sk_buf + else if (skb->protocol == htons(ETH_P_IPV6)) + net_dbg_ratelimited("%s: No peer has allowed IPs matching %pI6\n", + dev->name, &ipv6_hdr(skb)->daddr); +- goto err; ++ goto err_icmp; + } + + family = READ_ONCE(peer->endpoint.addr.sa_family); +@@ -201,12 +201,13 @@ static netdev_tx_t wg_xmit(struct sk_buf + + err_peer: + wg_peer_put(peer); +-err: +- ++dev->stats.tx_errors; ++err_icmp: + if (skb->protocol == htons(ETH_P_IP)) + icmp_ndo_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); + else if (skb->protocol == htons(ETH_P_IPV6)) + icmpv6_ndo_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); ++err: ++ ++dev->stats.tx_errors; + kfree_skb(skb); + return ret; + } diff --git a/ipq806x/backport-5.4/080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch b/ipq806x/backport-5.4/080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch new file mode 100644 index 0000000..9dc7dda --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0122-wireguard-queueing-get-rid-of-per-peer-ring-buffers.patch @@ -0,0 +1,560 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 22 Feb 2021 17:25:48 +0100 +Subject: [PATCH] wireguard: queueing: get rid of per-peer ring buffers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 8b5553ace83cced775eefd0f3f18b5c6214ccf7a upstream. + +Having two ring buffers per-peer means that every peer results in two +massive ring allocations. On an 8-core x86_64 machine, this commit +reduces the per-peer allocation from 18,688 bytes to 1,856 bytes, which +is an 90% reduction. Ninety percent! With some single-machine +deployments approaching 500,000 peers, we're talking about a reduction +from 7 gigs of memory down to 700 megs of memory. + +In order to get rid of these per-peer allocations, this commit switches +to using a list-based queueing approach. Currently GSO fragments are +chained together using the skb->next pointer (the skb_list_* singly +linked list approach), so we form the per-peer queue around the unused +skb->prev pointer (which sort of makes sense because the links are +pointing backwards). Use of skb_queue_* is not possible here, because +that is based on doubly linked lists and spinlocks. Multiple cores can +write into the queue at any given time, because its writes occur in the +start_xmit path or in the udp_recv path. But reads happen in a single +workqueue item per-peer, amounting to a multi-producer, single-consumer +paradigm. + +The MPSC queue is implemented locklessly and never blocks. However, it +is not linearizable (though it is serializable), with a very tight and +unlikely race on writes, which, when hit (some tiny fraction of the +0.15% of partial adds on a fully loaded 16-core x86_64 system), causes +the queue reader to terminate early. However, because every packet sent +queues up the same workqueue item after it is fully added, the worker +resumes again, and stopping early isn't actually a problem, since at +that point the packet wouldn't have yet been added to the encryption +queue. These properties allow us to avoid disabling interrupts or +spinning. The design is based on Dmitry Vyukov's algorithm [1]. + +Performance-wise, ordinarily list-based queues aren't preferable to +ringbuffers, because of cache misses when following pointers around. +However, we *already* have to follow the adjacent pointers when working +through fragments, so there shouldn't actually be any change there. A +potential downside is that dequeueing is a bit more complicated, but the +ptr_ring structure used prior had a spinlock when dequeueing, so all and +all the difference appears to be a wash. + +Actually, from profiling, the biggest performance hit, by far, of this +commit winds up being atomic_add_unless(count, 1, max) and atomic_ +dec(count), which account for the majority of CPU time, according to +perf. In that sense, the previous ring buffer was superior in that it +could check if it was full by head==tail, which the list-based approach +cannot do. + +But all and all, this enables us to get massive memory savings, allowing +WireGuard to scale for real world deployments, without taking much of a +performance hit. + +[1] http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue + +Reviewed-by: Dmitry Vyukov +Reviewed-by: Toke Høiland-Jørgensen +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Jakub Kicinski +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/device.c | 12 ++--- + drivers/net/wireguard/device.h | 15 +++--- + drivers/net/wireguard/peer.c | 28 ++++------- + drivers/net/wireguard/peer.h | 4 +- + drivers/net/wireguard/queueing.c | 86 +++++++++++++++++++++++++------- + drivers/net/wireguard/queueing.h | 45 ++++++++++++----- + drivers/net/wireguard/receive.c | 16 +++--- + drivers/net/wireguard/send.c | 31 ++++-------- + 8 files changed, 144 insertions(+), 93 deletions(-) + +--- a/drivers/net/wireguard/device.c ++++ b/drivers/net/wireguard/device.c +@@ -235,8 +235,8 @@ static void wg_destruct(struct net_devic + destroy_workqueue(wg->handshake_receive_wq); + destroy_workqueue(wg->handshake_send_wq); + destroy_workqueue(wg->packet_crypt_wq); +- wg_packet_queue_free(&wg->decrypt_queue, true); +- wg_packet_queue_free(&wg->encrypt_queue, true); ++ wg_packet_queue_free(&wg->decrypt_queue); ++ wg_packet_queue_free(&wg->encrypt_queue); + rcu_barrier(); /* Wait for all the peers to be actually freed. */ + wg_ratelimiter_uninit(); + memzero_explicit(&wg->static_identity, sizeof(wg->static_identity)); +@@ -338,12 +338,12 @@ static int wg_newlink(struct net *src_ne + goto err_destroy_handshake_send; + + ret = wg_packet_queue_init(&wg->encrypt_queue, wg_packet_encrypt_worker, +- true, MAX_QUEUED_PACKETS); ++ MAX_QUEUED_PACKETS); + if (ret < 0) + goto err_destroy_packet_crypt; + + ret = wg_packet_queue_init(&wg->decrypt_queue, wg_packet_decrypt_worker, +- true, MAX_QUEUED_PACKETS); ++ MAX_QUEUED_PACKETS); + if (ret < 0) + goto err_free_encrypt_queue; + +@@ -368,9 +368,9 @@ static int wg_newlink(struct net *src_ne + err_uninit_ratelimiter: + wg_ratelimiter_uninit(); + err_free_decrypt_queue: +- wg_packet_queue_free(&wg->decrypt_queue, true); ++ wg_packet_queue_free(&wg->decrypt_queue); + err_free_encrypt_queue: +- wg_packet_queue_free(&wg->encrypt_queue, true); ++ wg_packet_queue_free(&wg->encrypt_queue); + err_destroy_packet_crypt: + destroy_workqueue(wg->packet_crypt_wq); + err_destroy_handshake_send: +--- a/drivers/net/wireguard/device.h ++++ b/drivers/net/wireguard/device.h +@@ -27,13 +27,14 @@ struct multicore_worker { + + struct crypt_queue { + struct ptr_ring ring; +- union { +- struct { +- struct multicore_worker __percpu *worker; +- int last_cpu; +- }; +- struct work_struct work; +- }; ++ struct multicore_worker __percpu *worker; ++ int last_cpu; ++}; ++ ++struct prev_queue { ++ struct sk_buff *head, *tail, *peeked; ++ struct { struct sk_buff *next, *prev; } empty; // Match first 2 members of struct sk_buff. ++ atomic_t count; + }; + + struct wg_device { +--- a/drivers/net/wireguard/peer.c ++++ b/drivers/net/wireguard/peer.c +@@ -32,27 +32,22 @@ struct wg_peer *wg_peer_create(struct wg + peer = kzalloc(sizeof(*peer), GFP_KERNEL); + if (unlikely(!peer)) + return ERR_PTR(ret); +- peer->device = wg; ++ if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) ++ goto err; + ++ peer->device = wg; + wg_noise_handshake_init(&peer->handshake, &wg->static_identity, + public_key, preshared_key, peer); +- if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) +- goto err_1; +- if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false, +- MAX_QUEUED_PACKETS)) +- goto err_2; +- if (wg_packet_queue_init(&peer->rx_queue, NULL, false, +- MAX_QUEUED_PACKETS)) +- goto err_3; +- + peer->internal_id = atomic64_inc_return(&peer_counter); + peer->serial_work_cpu = nr_cpumask_bits; + wg_cookie_init(&peer->latest_cookie); + wg_timers_init(peer); + wg_cookie_checker_precompute_peer_keys(peer); + spin_lock_init(&peer->keypairs.keypair_update_lock); +- INIT_WORK(&peer->transmit_handshake_work, +- wg_packet_handshake_send_worker); ++ INIT_WORK(&peer->transmit_handshake_work, wg_packet_handshake_send_worker); ++ INIT_WORK(&peer->transmit_packet_work, wg_packet_tx_worker); ++ wg_prev_queue_init(&peer->tx_queue); ++ wg_prev_queue_init(&peer->rx_queue); + rwlock_init(&peer->endpoint_lock); + kref_init(&peer->refcount); + skb_queue_head_init(&peer->staged_packet_queue); +@@ -68,11 +63,7 @@ struct wg_peer *wg_peer_create(struct wg + pr_debug("%s: Peer %llu created\n", wg->dev->name, peer->internal_id); + return peer; + +-err_3: +- wg_packet_queue_free(&peer->tx_queue, false); +-err_2: +- dst_cache_destroy(&peer->endpoint_cache); +-err_1: ++err: + kfree(peer); + return ERR_PTR(ret); + } +@@ -197,8 +188,7 @@ static void rcu_release(struct rcu_head + struct wg_peer *peer = container_of(rcu, struct wg_peer, rcu); + + dst_cache_destroy(&peer->endpoint_cache); +- wg_packet_queue_free(&peer->rx_queue, false); +- wg_packet_queue_free(&peer->tx_queue, false); ++ WARN_ON(wg_prev_queue_peek(&peer->tx_queue) || wg_prev_queue_peek(&peer->rx_queue)); + + /* The final zeroing takes care of clearing any remaining handshake key + * material and other potentially sensitive information. +--- a/drivers/net/wireguard/peer.h ++++ b/drivers/net/wireguard/peer.h +@@ -36,7 +36,7 @@ struct endpoint { + + struct wg_peer { + struct wg_device *device; +- struct crypt_queue tx_queue, rx_queue; ++ struct prev_queue tx_queue, rx_queue; + struct sk_buff_head staged_packet_queue; + int serial_work_cpu; + bool is_dead; +@@ -46,7 +46,7 @@ struct wg_peer { + rwlock_t endpoint_lock; + struct noise_handshake handshake; + atomic64_t last_sent_handshake; +- struct work_struct transmit_handshake_work, clear_peer_work; ++ struct work_struct transmit_handshake_work, clear_peer_work, transmit_packet_work; + struct cookie latest_cookie; + struct hlist_node pubkey_hash; + u64 rx_bytes, tx_bytes; +--- a/drivers/net/wireguard/queueing.c ++++ b/drivers/net/wireguard/queueing.c +@@ -9,8 +9,7 @@ struct multicore_worker __percpu * + wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr) + { + int cpu; +- struct multicore_worker __percpu *worker = +- alloc_percpu(struct multicore_worker); ++ struct multicore_worker __percpu *worker = alloc_percpu(struct multicore_worker); + + if (!worker) + return NULL; +@@ -23,7 +22,7 @@ wg_packet_percpu_multicore_worker_alloc( + } + + int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function, +- bool multicore, unsigned int len) ++ unsigned int len) + { + int ret; + +@@ -31,25 +30,78 @@ int wg_packet_queue_init(struct crypt_qu + ret = ptr_ring_init(&queue->ring, len, GFP_KERNEL); + if (ret) + return ret; +- if (function) { +- if (multicore) { +- queue->worker = wg_packet_percpu_multicore_worker_alloc( +- function, queue); +- if (!queue->worker) { +- ptr_ring_cleanup(&queue->ring, NULL); +- return -ENOMEM; +- } +- } else { +- INIT_WORK(&queue->work, function); +- } ++ queue->worker = wg_packet_percpu_multicore_worker_alloc(function, queue); ++ if (!queue->worker) { ++ ptr_ring_cleanup(&queue->ring, NULL); ++ return -ENOMEM; + } + return 0; + } + +-void wg_packet_queue_free(struct crypt_queue *queue, bool multicore) ++void wg_packet_queue_free(struct crypt_queue *queue) + { +- if (multicore) +- free_percpu(queue->worker); ++ free_percpu(queue->worker); + WARN_ON(!__ptr_ring_empty(&queue->ring)); + ptr_ring_cleanup(&queue->ring, NULL); + } ++ ++#define NEXT(skb) ((skb)->prev) ++#define STUB(queue) ((struct sk_buff *)&queue->empty) ++ ++void wg_prev_queue_init(struct prev_queue *queue) ++{ ++ NEXT(STUB(queue)) = NULL; ++ queue->head = queue->tail = STUB(queue); ++ queue->peeked = NULL; ++ atomic_set(&queue->count, 0); ++ BUILD_BUG_ON( ++ offsetof(struct sk_buff, next) != offsetof(struct prev_queue, empty.next) - ++ offsetof(struct prev_queue, empty) || ++ offsetof(struct sk_buff, prev) != offsetof(struct prev_queue, empty.prev) - ++ offsetof(struct prev_queue, empty)); ++} ++ ++static void __wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb) ++{ ++ WRITE_ONCE(NEXT(skb), NULL); ++ WRITE_ONCE(NEXT(xchg_release(&queue->head, skb)), skb); ++} ++ ++bool wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb) ++{ ++ if (!atomic_add_unless(&queue->count, 1, MAX_QUEUED_PACKETS)) ++ return false; ++ __wg_prev_queue_enqueue(queue, skb); ++ return true; ++} ++ ++struct sk_buff *wg_prev_queue_dequeue(struct prev_queue *queue) ++{ ++ struct sk_buff *tail = queue->tail, *next = smp_load_acquire(&NEXT(tail)); ++ ++ if (tail == STUB(queue)) { ++ if (!next) ++ return NULL; ++ queue->tail = next; ++ tail = next; ++ next = smp_load_acquire(&NEXT(next)); ++ } ++ if (next) { ++ queue->tail = next; ++ atomic_dec(&queue->count); ++ return tail; ++ } ++ if (tail != READ_ONCE(queue->head)) ++ return NULL; ++ __wg_prev_queue_enqueue(queue, STUB(queue)); ++ next = smp_load_acquire(&NEXT(tail)); ++ if (next) { ++ queue->tail = next; ++ atomic_dec(&queue->count); ++ return tail; ++ } ++ return NULL; ++} ++ ++#undef NEXT ++#undef STUB +--- a/drivers/net/wireguard/queueing.h ++++ b/drivers/net/wireguard/queueing.h +@@ -17,12 +17,13 @@ struct wg_device; + struct wg_peer; + struct multicore_worker; + struct crypt_queue; ++struct prev_queue; + struct sk_buff; + + /* queueing.c APIs: */ + int wg_packet_queue_init(struct crypt_queue *queue, work_func_t function, +- bool multicore, unsigned int len); +-void wg_packet_queue_free(struct crypt_queue *queue, bool multicore); ++ unsigned int len); ++void wg_packet_queue_free(struct crypt_queue *queue); + struct multicore_worker __percpu * + wg_packet_percpu_multicore_worker_alloc(work_func_t function, void *ptr); + +@@ -135,8 +136,31 @@ static inline int wg_cpumask_next_online + return cpu; + } + ++void wg_prev_queue_init(struct prev_queue *queue); ++ ++/* Multi producer */ ++bool wg_prev_queue_enqueue(struct prev_queue *queue, struct sk_buff *skb); ++ ++/* Single consumer */ ++struct sk_buff *wg_prev_queue_dequeue(struct prev_queue *queue); ++ ++/* Single consumer */ ++static inline struct sk_buff *wg_prev_queue_peek(struct prev_queue *queue) ++{ ++ if (queue->peeked) ++ return queue->peeked; ++ queue->peeked = wg_prev_queue_dequeue(queue); ++ return queue->peeked; ++} ++ ++/* Single consumer */ ++static inline void wg_prev_queue_drop_peeked(struct prev_queue *queue) ++{ ++ queue->peeked = NULL; ++} ++ + static inline int wg_queue_enqueue_per_device_and_peer( +- struct crypt_queue *device_queue, struct crypt_queue *peer_queue, ++ struct crypt_queue *device_queue, struct prev_queue *peer_queue, + struct sk_buff *skb, struct workqueue_struct *wq, int *next_cpu) + { + int cpu; +@@ -145,8 +169,9 @@ static inline int wg_queue_enqueue_per_d + /* We first queue this up for the peer ingestion, but the consumer + * will wait for the state to change to CRYPTED or DEAD before. + */ +- if (unlikely(ptr_ring_produce_bh(&peer_queue->ring, skb))) ++ if (unlikely(!wg_prev_queue_enqueue(peer_queue, skb))) + return -ENOSPC; ++ + /* Then we queue it up in the device queue, which consumes the + * packet as soon as it can. + */ +@@ -157,9 +182,7 @@ static inline int wg_queue_enqueue_per_d + return 0; + } + +-static inline void wg_queue_enqueue_per_peer(struct crypt_queue *queue, +- struct sk_buff *skb, +- enum packet_state state) ++static inline void wg_queue_enqueue_per_peer_tx(struct sk_buff *skb, enum packet_state state) + { + /* We take a reference, because as soon as we call atomic_set, the + * peer can be freed from below us. +@@ -167,14 +190,12 @@ static inline void wg_queue_enqueue_per_ + struct wg_peer *peer = wg_peer_get(PACKET_PEER(skb)); + + atomic_set_release(&PACKET_CB(skb)->state, state); +- queue_work_on(wg_cpumask_choose_online(&peer->serial_work_cpu, +- peer->internal_id), +- peer->device->packet_crypt_wq, &queue->work); ++ queue_work_on(wg_cpumask_choose_online(&peer->serial_work_cpu, peer->internal_id), ++ peer->device->packet_crypt_wq, &peer->transmit_packet_work); + wg_peer_put(peer); + } + +-static inline void wg_queue_enqueue_per_peer_napi(struct sk_buff *skb, +- enum packet_state state) ++static inline void wg_queue_enqueue_per_peer_rx(struct sk_buff *skb, enum packet_state state) + { + /* We take a reference, because as soon as we call atomic_set, the + * peer can be freed from below us. +--- a/drivers/net/wireguard/receive.c ++++ b/drivers/net/wireguard/receive.c +@@ -444,7 +444,6 @@ packet_processed: + int wg_packet_rx_poll(struct napi_struct *napi, int budget) + { + struct wg_peer *peer = container_of(napi, struct wg_peer, napi); +- struct crypt_queue *queue = &peer->rx_queue; + struct noise_keypair *keypair; + struct endpoint endpoint; + enum packet_state state; +@@ -455,11 +454,10 @@ int wg_packet_rx_poll(struct napi_struct + if (unlikely(budget <= 0)) + return 0; + +- while ((skb = __ptr_ring_peek(&queue->ring)) != NULL && ++ while ((skb = wg_prev_queue_peek(&peer->rx_queue)) != NULL && + (state = atomic_read_acquire(&PACKET_CB(skb)->state)) != + PACKET_STATE_UNCRYPTED) { +- __ptr_ring_discard_one(&queue->ring); +- peer = PACKET_PEER(skb); ++ wg_prev_queue_drop_peeked(&peer->rx_queue); + keypair = PACKET_CB(skb)->keypair; + free = true; + +@@ -508,7 +506,7 @@ void wg_packet_decrypt_worker(struct wor + enum packet_state state = + likely(decrypt_packet(skb, PACKET_CB(skb)->keypair)) ? + PACKET_STATE_CRYPTED : PACKET_STATE_DEAD; +- wg_queue_enqueue_per_peer_napi(skb, state); ++ wg_queue_enqueue_per_peer_rx(skb, state); + if (need_resched()) + cond_resched(); + } +@@ -531,12 +529,10 @@ static void wg_packet_consume_data(struc + if (unlikely(READ_ONCE(peer->is_dead))) + goto err; + +- ret = wg_queue_enqueue_per_device_and_peer(&wg->decrypt_queue, +- &peer->rx_queue, skb, +- wg->packet_crypt_wq, +- &wg->decrypt_queue.last_cpu); ++ ret = wg_queue_enqueue_per_device_and_peer(&wg->decrypt_queue, &peer->rx_queue, skb, ++ wg->packet_crypt_wq, &wg->decrypt_queue.last_cpu); + if (unlikely(ret == -EPIPE)) +- wg_queue_enqueue_per_peer_napi(skb, PACKET_STATE_DEAD); ++ wg_queue_enqueue_per_peer_rx(skb, PACKET_STATE_DEAD); + if (likely(!ret || ret == -EPIPE)) { + rcu_read_unlock_bh(); + return; +--- a/drivers/net/wireguard/send.c ++++ b/drivers/net/wireguard/send.c +@@ -239,8 +239,7 @@ void wg_packet_send_keepalive(struct wg_ + wg_packet_send_staged_packets(peer); + } + +-static void wg_packet_create_data_done(struct sk_buff *first, +- struct wg_peer *peer) ++static void wg_packet_create_data_done(struct wg_peer *peer, struct sk_buff *first) + { + struct sk_buff *skb, *next; + bool is_keepalive, data_sent = false; +@@ -262,22 +261,19 @@ static void wg_packet_create_data_done(s + + void wg_packet_tx_worker(struct work_struct *work) + { +- struct crypt_queue *queue = container_of(work, struct crypt_queue, +- work); ++ struct wg_peer *peer = container_of(work, struct wg_peer, transmit_packet_work); + struct noise_keypair *keypair; + enum packet_state state; + struct sk_buff *first; +- struct wg_peer *peer; + +- while ((first = __ptr_ring_peek(&queue->ring)) != NULL && ++ while ((first = wg_prev_queue_peek(&peer->tx_queue)) != NULL && + (state = atomic_read_acquire(&PACKET_CB(first)->state)) != + PACKET_STATE_UNCRYPTED) { +- __ptr_ring_discard_one(&queue->ring); +- peer = PACKET_PEER(first); ++ wg_prev_queue_drop_peeked(&peer->tx_queue); + keypair = PACKET_CB(first)->keypair; + + if (likely(state == PACKET_STATE_CRYPTED)) +- wg_packet_create_data_done(first, peer); ++ wg_packet_create_data_done(peer, first); + else + kfree_skb_list(first); + +@@ -306,16 +302,14 @@ void wg_packet_encrypt_worker(struct wor + break; + } + } +- wg_queue_enqueue_per_peer(&PACKET_PEER(first)->tx_queue, first, +- state); ++ wg_queue_enqueue_per_peer_tx(first, state); + if (need_resched()) + cond_resched(); + } + } + +-static void wg_packet_create_data(struct sk_buff *first) ++static void wg_packet_create_data(struct wg_peer *peer, struct sk_buff *first) + { +- struct wg_peer *peer = PACKET_PEER(first); + struct wg_device *wg = peer->device; + int ret = -EINVAL; + +@@ -323,13 +317,10 @@ static void wg_packet_create_data(struct + if (unlikely(READ_ONCE(peer->is_dead))) + goto err; + +- ret = wg_queue_enqueue_per_device_and_peer(&wg->encrypt_queue, +- &peer->tx_queue, first, +- wg->packet_crypt_wq, +- &wg->encrypt_queue.last_cpu); ++ ret = wg_queue_enqueue_per_device_and_peer(&wg->encrypt_queue, &peer->tx_queue, first, ++ wg->packet_crypt_wq, &wg->encrypt_queue.last_cpu); + if (unlikely(ret == -EPIPE)) +- wg_queue_enqueue_per_peer(&peer->tx_queue, first, +- PACKET_STATE_DEAD); ++ wg_queue_enqueue_per_peer_tx(first, PACKET_STATE_DEAD); + err: + rcu_read_unlock_bh(); + if (likely(!ret || ret == -EPIPE)) +@@ -393,7 +384,7 @@ void wg_packet_send_staged_packets(struc + packets.prev->next = NULL; + wg_peer_get(keypair->entry.peer); + PACKET_CB(packets.next)->keypair = keypair; +- wg_packet_create_data(packets.next); ++ wg_packet_create_data(peer, packets.next); + return; + + out_invalid: diff --git a/ipq806x/backport-5.4/080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch b/ipq806x/backport-5.4/080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch new file mode 100644 index 0000000..9a25149 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0123-wireguard-kconfig-use-arm-chacha-even-with-no-neon.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 22 Feb 2021 17:25:49 +0100 +Subject: [PATCH] wireguard: kconfig: use arm chacha even with no neon + +commit bce2473927af8de12ad131a743f55d69d358c0b9 upstream. + +The condition here was incorrect: a non-neon fallback implementation is +available on arm32 when NEON is not supported. + +Reported-by: Ilya Lipnitskiy +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Signed-off-by: Jason A. Donenfeld +Signed-off-by: Jakub Kicinski +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -87,7 +87,7 @@ config WIREGUARD + select CRYPTO_CURVE25519_X86 if X86 && 64BIT + select ARM_CRYPTO if ARM + select ARM64_CRYPTO if ARM64 +- select CRYPTO_CHACHA20_NEON if (ARM || ARM64) && KERNEL_MODE_NEON ++ select CRYPTO_CHACHA20_NEON if ARM || (ARM64 && KERNEL_MODE_NEON) + select CRYPTO_POLY1305_NEON if ARM64 && KERNEL_MODE_NEON + select CRYPTO_POLY1305_ARM if ARM + select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON diff --git a/ipq806x/backport-5.4/080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch b/ipq806x/backport-5.4/080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch new file mode 100644 index 0000000..c0ee841 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0124-crypto-mips-poly1305-enable-for-all-MIPS-processors.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Thu, 11 Mar 2021 21:50:47 -0700 +Subject: [PATCH] crypto: mips/poly1305 - enable for all MIPS processors + +commit 6c810cf20feef0d4338e9b424ab7f2644a8b353e upstream. + +The MIPS Poly1305 implementation is generic MIPS code written such as to +support down to the original MIPS I and MIPS III ISA for the 32-bit and +64-bit variant respectively. Lift the current limitation then to enable +code for MIPSr1 ISA or newer processors only and have it available for +all MIPS processors. + +Signed-off-by: Maciej W. Rozycki +Fixes: a11d055e7a64 ("crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS optimized implementation") +Cc: stable@vger.kernel.org # v5.5+ +Acked-by: Jason A. Donenfeld +Signed-off-by: Thomas Bogendoerfer +Signed-off-by: Jason A. Donenfeld +--- + arch/mips/crypto/Makefile | 4 ++-- + crypto/Kconfig | 2 +- + drivers/net/Kconfig | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/mips/crypto/Makefile ++++ b/arch/mips/crypto/Makefile +@@ -12,8 +12,8 @@ AFLAGS_chacha-core.o += -O2 # needed to + obj-$(CONFIG_CRYPTO_POLY1305_MIPS) += poly1305-mips.o + poly1305-mips-y := poly1305-core.o poly1305-glue.o + +-perlasm-flavour-$(CONFIG_CPU_MIPS32) := o32 +-perlasm-flavour-$(CONFIG_CPU_MIPS64) := 64 ++perlasm-flavour-$(CONFIG_32BIT) := o32 ++perlasm-flavour-$(CONFIG_64BIT) := 64 + + quiet_cmd_perlasm = PERLASM $@ + cmd_perlasm = $(PERL) $(<) $(perlasm-flavour-y) $(@) +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -740,7 +740,7 @@ config CRYPTO_POLY1305_X86_64 + + config CRYPTO_POLY1305_MIPS + tristate "Poly1305 authenticator algorithm (MIPS optimized)" +- depends on CPU_MIPS32 || (CPU_MIPS64 && 64BIT) ++ depends on MIPS + select CRYPTO_ARCH_HAVE_LIB_POLY1305 + + config CRYPTO_MD4 +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -92,7 +92,7 @@ config WIREGUARD + select CRYPTO_POLY1305_ARM if ARM + select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON + select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2 +- select CRYPTO_POLY1305_MIPS if CPU_MIPS32 || (CPU_MIPS64 && 64BIT) ++ select CRYPTO_POLY1305_MIPS if MIPS + help + WireGuard is a secure, fast, and easy to use replacement for IPSec + that uses modern cryptography and clever networking tricks. It's diff --git a/ipq806x/backport-5.4/080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch b/ipq806x/backport-5.4/080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch new file mode 100644 index 0000000..856d67d --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0125-crypto-mips-add-poly1305-core.S-to-.gitignore.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ilya Lipnitskiy +Date: Sat, 27 Mar 2021 19:39:43 -0700 +Subject: [PATCH] crypto: mips: add poly1305-core.S to .gitignore + +commit dc92d0df51dc61de88bf6f4884a17bf73d5c6326 upstream. + +poly1305-core.S is an auto-generated file, so it should be ignored. + +Fixes: a11d055e7a64 ("crypto: mips/poly1305 - incorporate OpenSSL/CRYPTOGAMS optimized implementation") +Signed-off-by: Ilya Lipnitskiy +Cc: Ard Biesheuvel +Signed-off-by: Thomas Bogendoerfer +Signed-off-by: Jason A. Donenfeld +--- + arch/mips/crypto/.gitignore | 2 ++ + 1 file changed, 2 insertions(+) + create mode 100644 arch/mips/crypto/.gitignore + +--- /dev/null ++++ b/arch/mips/crypto/.gitignore +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++poly1305-core.S diff --git a/ipq806x/backport-5.4/080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch b/ipq806x/backport-5.4/080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch new file mode 100644 index 0000000..ded6625 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0126-crypto-poly1305-fix-poly1305_core_setkey-declaration.patch @@ -0,0 +1,172 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Mon, 22 Mar 2021 18:05:15 +0100 +Subject: [PATCH] crypto: poly1305 - fix poly1305_core_setkey() declaration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 8d195e7a8ada68928f2aedb2c18302a4518fe68e upstream. + +gcc-11 points out a mismatch between the declaration and the definition +of poly1305_core_setkey(): + +lib/crypto/poly1305-donna32.c:13:67: error: argument 2 of type ‘const u8[16]’ {aka ‘const unsigned char[16]’} with mismatched bound [-Werror=array-parameter=] + 13 | void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16]) + | ~~~~~~~~~^~~~~~~~~~~ +In file included from lib/crypto/poly1305-donna32.c:11: +include/crypto/internal/poly1305.h:21:68: note: previously declared as ‘const u8 *’ {aka ‘const unsigned char *’} + 21 | void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key); + +This is harmless in principle, as the calling conventions are the same, +but the more specific prototype allows better type checking in the +caller. + +Change the declaration to match the actual function definition. +The poly1305_simd_init() is a bit suspicious here, as it previously +had a 32-byte argument type, but looks like it needs to take the +16-byte POLY1305_BLOCK_SIZE array instead. + +Fixes: 1c08a104360f ("crypto: poly1305 - add new 32 and 64-bit generic versions") +Signed-off-by: Arnd Bergmann +Reviewed-by: Ard Biesheuvel +Reviewed-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Jason A. Donenfeld +--- + arch/arm/crypto/poly1305-glue.c | 2 +- + arch/arm64/crypto/poly1305-glue.c | 2 +- + arch/mips/crypto/poly1305-glue.c | 2 +- + arch/x86/crypto/poly1305_glue.c | 6 +++--- + include/crypto/internal/poly1305.h | 3 ++- + include/crypto/poly1305.h | 6 ++++-- + lib/crypto/poly1305-donna32.c | 3 ++- + lib/crypto/poly1305-donna64.c | 3 ++- + lib/crypto/poly1305.c | 3 ++- + 9 files changed, 18 insertions(+), 12 deletions(-) + +--- a/arch/arm/crypto/poly1305-glue.c ++++ b/arch/arm/crypto/poly1305-glue.c +@@ -29,7 +29,7 @@ void __weak poly1305_blocks_neon(void *s + + static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); + +-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) + { + poly1305_init_arm(&dctx->h, key); + dctx->s[0] = get_unaligned_le32(key + 16); +--- a/arch/arm64/crypto/poly1305-glue.c ++++ b/arch/arm64/crypto/poly1305-glue.c +@@ -25,7 +25,7 @@ asmlinkage void poly1305_emit(void *stat + + static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon); + +-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) + { + poly1305_init_arm64(&dctx->h, key); + dctx->s[0] = get_unaligned_le32(key + 16); +--- a/arch/mips/crypto/poly1305-glue.c ++++ b/arch/mips/crypto/poly1305-glue.c +@@ -17,7 +17,7 @@ asmlinkage void poly1305_init_mips(void + asmlinkage void poly1305_blocks_mips(void *state, const u8 *src, u32 len, u32 hibit); + asmlinkage void poly1305_emit_mips(void *state, u8 *digest, const u32 *nonce); + +-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) + { + poly1305_init_mips(&dctx->h, key); + dctx->s[0] = get_unaligned_le32(key + 16); +--- a/arch/x86/crypto/poly1305_glue.c ++++ b/arch/x86/crypto/poly1305_glue.c +@@ -15,7 +15,7 @@ + #include + + asmlinkage void poly1305_init_x86_64(void *ctx, +- const u8 key[POLY1305_KEY_SIZE]); ++ const u8 key[POLY1305_BLOCK_SIZE]); + asmlinkage void poly1305_blocks_x86_64(void *ctx, const u8 *inp, + const size_t len, const u32 padbit); + asmlinkage void poly1305_emit_x86_64(void *ctx, u8 mac[POLY1305_DIGEST_SIZE], +@@ -80,7 +80,7 @@ static void convert_to_base2_64(void *ct + state->is_base2_26 = 0; + } + +-static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_KEY_SIZE]) ++static void poly1305_simd_init(void *ctx, const u8 key[POLY1305_BLOCK_SIZE]) + { + poly1305_init_x86_64(ctx, key); + } +@@ -128,7 +128,7 @@ static void poly1305_simd_emit(void *ctx + poly1305_emit_avx(ctx, mac, nonce); + } + +-void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 *key) ++void poly1305_init_arch(struct poly1305_desc_ctx *dctx, const u8 key[POLY1305_KEY_SIZE]) + { + poly1305_simd_init(&dctx->h, key); + dctx->s[0] = get_unaligned_le32(&key[16]); +--- a/include/crypto/internal/poly1305.h ++++ b/include/crypto/internal/poly1305.h +@@ -18,7 +18,8 @@ + * only the ε-almost-∆-universal hash function (not the full MAC) is computed. + */ + +-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 *raw_key); ++void poly1305_core_setkey(struct poly1305_core_key *key, ++ const u8 raw_key[POLY1305_BLOCK_SIZE]); + static inline void poly1305_core_init(struct poly1305_state *state) + { + *state = (struct poly1305_state){}; +--- a/include/crypto/poly1305.h ++++ b/include/crypto/poly1305.h +@@ -58,8 +58,10 @@ struct poly1305_desc_ctx { + }; + }; + +-void poly1305_init_arch(struct poly1305_desc_ctx *desc, const u8 *key); +-void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key); ++void poly1305_init_arch(struct poly1305_desc_ctx *desc, ++ const u8 key[POLY1305_KEY_SIZE]); ++void poly1305_init_generic(struct poly1305_desc_ctx *desc, ++ const u8 key[POLY1305_KEY_SIZE]); + + static inline void poly1305_init(struct poly1305_desc_ctx *desc, const u8 *key) + { +--- a/lib/crypto/poly1305-donna32.c ++++ b/lib/crypto/poly1305-donna32.c +@@ -10,7 +10,8 @@ + #include + #include + +-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16]) ++void poly1305_core_setkey(struct poly1305_core_key *key, ++ const u8 raw_key[POLY1305_BLOCK_SIZE]) + { + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + key->key.r[0] = (get_unaligned_le32(&raw_key[0])) & 0x3ffffff; +--- a/lib/crypto/poly1305-donna64.c ++++ b/lib/crypto/poly1305-donna64.c +@@ -12,7 +12,8 @@ + + typedef __uint128_t u128; + +-void poly1305_core_setkey(struct poly1305_core_key *key, const u8 raw_key[16]) ++void poly1305_core_setkey(struct poly1305_core_key *key, ++ const u8 raw_key[POLY1305_BLOCK_SIZE]) + { + u64 t0, t1; + +--- a/lib/crypto/poly1305.c ++++ b/lib/crypto/poly1305.c +@@ -12,7 +12,8 @@ + #include + #include + +-void poly1305_init_generic(struct poly1305_desc_ctx *desc, const u8 *key) ++void poly1305_init_generic(struct poly1305_desc_ctx *desc, ++ const u8 key[POLY1305_KEY_SIZE]) + { + poly1305_core_setkey(&desc->core_r, key); + desc->s[0] = get_unaligned_le32(key + 16); diff --git a/ipq806x/backport-5.4/080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch b/ipq806x/backport-5.4/080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch new file mode 100644 index 0000000..3e7d1a8 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0127-wireguard-selftests-remove-old-conntrack-kconfig-val.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:30 +0200 +Subject: [PATCH] wireguard: selftests: remove old conntrack kconfig value + +commit acf2492b51c9a3c4dfb947f4d3477a86d315150f upstream. + +On recent kernels, this config symbol is no longer used. + +Reported-by: Rui Salvaterra +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/qemu/kernel.config | 1 - + 1 file changed, 1 deletion(-) + +--- a/tools/testing/selftests/wireguard/qemu/kernel.config ++++ b/tools/testing/selftests/wireguard/qemu/kernel.config +@@ -19,7 +19,6 @@ CONFIG_NETFILTER_XTABLES=y + CONFIG_NETFILTER_XT_NAT=y + CONFIG_NETFILTER_XT_MATCH_LENGTH=y + CONFIG_NETFILTER_XT_MARK=y +-CONFIG_NF_CONNTRACK_IPV4=y + CONFIG_NF_NAT_IPV4=y + CONFIG_IP_NF_IPTABLES=y + CONFIG_IP_NF_FILTER=y diff --git a/ipq806x/backport-5.4/080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch b/ipq806x/backport-5.4/080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch new file mode 100644 index 0000000..22d0f3e --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0128-wireguard-selftests-make-sure-rp_filter-is-disabled-.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:31 +0200 +Subject: [PATCH] wireguard: selftests: make sure rp_filter is disabled on + vethc + +commit f8873d11d4121aad35024f9379e431e0c83abead upstream. + +Some distros may enable strict rp_filter by default, which will prevent +vethc from receiving the packets with an unrouteable reverse path address. + +Reported-by: Hangbin Liu +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + tools/testing/selftests/wireguard/netns.sh | 1 + + 1 file changed, 1 insertion(+) + +--- a/tools/testing/selftests/wireguard/netns.sh ++++ b/tools/testing/selftests/wireguard/netns.sh +@@ -363,6 +363,7 @@ ip1 -6 rule add table main suppress_pref + ip1 -4 route add default dev wg0 table 51820 + ip1 -4 rule add not fwmark 51820 table 51820 + ip1 -4 rule add table main suppress_prefixlength 0 ++n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/vethc/rp_filter' + # Flood the pings instead of sending just one, to trigger routing table reference counting bugs. + n1 ping -W 1 -c 100 -f 192.168.99.7 + n1 ping -W 1 -c 100 -f abab::1111 diff --git a/ipq806x/backport-5.4/080-wireguard-0129-wireguard-do-not-use-O3.patch b/ipq806x/backport-5.4/080-wireguard-0129-wireguard-do-not-use-O3.patch new file mode 100644 index 0000000..a7890a7 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0129-wireguard-do-not-use-O3.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:32 +0200 +Subject: [PATCH] wireguard: do not use -O3 + +commit cc5060ca0285efe2728bced399a1955a7ce808b2 upstream. + +Apparently, various versions of gcc have O3-related miscompiles. Looking +at the difference between -O2 and -O3 for gcc 11 doesn't indicate +miscompiles, but the difference also doesn't seem so significant for +performance that it's worth risking. + +Link: https://lore.kernel.org/lkml/CAHk-=wjuoGyxDhAF8SsrTkN0-YfCx7E6jUN3ikC_tn2AKWTTsA@mail.gmail.com/ +Link: https://lore.kernel.org/lkml/CAHmME9otB5Wwxp7H8bR_i2uH2esEMvoBMC8uEXBMH9p0q1s6Bw@mail.gmail.com/ +Reported-by: Linus Torvalds +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/Makefile | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/net/wireguard/Makefile ++++ b/drivers/net/wireguard/Makefile +@@ -1,5 +1,4 @@ +-ccflags-y := -O3 +-ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt' ++ccflags-y := -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt' + ccflags-$(CONFIG_WIREGUARD_DEBUG) += -DDEBUG + wireguard-y := main.o + wireguard-y += noise.o diff --git a/ipq806x/backport-5.4/080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch b/ipq806x/backport-5.4/080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch new file mode 100644 index 0000000..309fe36 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0130-wireguard-use-synchronize_net-rather-than-synchroniz.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:33 +0200 +Subject: [PATCH] wireguard: use synchronize_net rather than synchronize_rcu + +commit 24b70eeeb4f46c09487f8155239ebfb1f875774a upstream. + +Many of the synchronization points are sometimes called under the rtnl +lock, which means we should use synchronize_net rather than +synchronize_rcu. Under the hood, this expands to using the expedited +flavor of function in the event that rtnl is held, in order to not stall +other concurrent changes. + +This fixes some very, very long delays when removing multiple peers at +once, which would cause some operations to take several minutes. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/peer.c | 6 +++--- + drivers/net/wireguard/socket.c | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireguard/peer.c ++++ b/drivers/net/wireguard/peer.c +@@ -88,7 +88,7 @@ static void peer_make_dead(struct wg_pee + /* Mark as dead, so that we don't allow jumping contexts after. */ + WRITE_ONCE(peer->is_dead, true); + +- /* The caller must now synchronize_rcu() for this to take effect. */ ++ /* The caller must now synchronize_net() for this to take effect. */ + } + + static void peer_remove_after_dead(struct wg_peer *peer) +@@ -160,7 +160,7 @@ void wg_peer_remove(struct wg_peer *peer + lockdep_assert_held(&peer->device->device_update_lock); + + peer_make_dead(peer); +- synchronize_rcu(); ++ synchronize_net(); + peer_remove_after_dead(peer); + } + +@@ -178,7 +178,7 @@ void wg_peer_remove_all(struct wg_device + peer_make_dead(peer); + list_add_tail(&peer->peer_list, &dead_peers); + } +- synchronize_rcu(); ++ synchronize_net(); + list_for_each_entry_safe(peer, temp, &dead_peers, peer_list) + peer_remove_after_dead(peer); + } +--- a/drivers/net/wireguard/socket.c ++++ b/drivers/net/wireguard/socket.c +@@ -430,7 +430,7 @@ void wg_socket_reinit(struct wg_device * + if (new4) + wg->incoming_port = ntohs(inet_sk(new4)->inet_sport); + mutex_unlock(&wg->socket_update_lock); +- synchronize_rcu(); ++ synchronize_net(); + sock_free(old4); + sock_free(old6); + } diff --git a/ipq806x/backport-5.4/080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch b/ipq806x/backport-5.4/080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch new file mode 100644 index 0000000..32ae327 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0131-wireguard-peer-allocate-in-kmem_cache.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:34 +0200 +Subject: [PATCH] wireguard: peer: allocate in kmem_cache + +commit a4e9f8e3287c9eb6bf70df982870980dd3341863 upstream. + +With deployments having upwards of 600k peers now, this somewhat heavy +structure could benefit from more fine-grained allocations. +Specifically, instead of using a 2048-byte slab for a 1544-byte object, +we can now use 1544-byte objects directly, thus saving almost 25% +per-peer, or with 600k peers, that's a savings of 303 MiB. This also +makes wireguard's memory usage more transparent in tools like slabtop +and /proc/slabinfo. + +Fixes: 8b5553ace83c ("wireguard: queueing: get rid of per-peer ring buffers") +Suggested-by: Arnd Bergmann +Suggested-by: Matthew Wilcox +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/main.c | 7 +++++++ + drivers/net/wireguard/peer.c | 21 +++++++++++++++++---- + drivers/net/wireguard/peer.h | 3 +++ + 3 files changed, 27 insertions(+), 4 deletions(-) + +--- a/drivers/net/wireguard/main.c ++++ b/drivers/net/wireguard/main.c +@@ -28,6 +28,10 @@ static int __init mod_init(void) + #endif + wg_noise_init(); + ++ ret = wg_peer_init(); ++ if (ret < 0) ++ goto err_peer; ++ + ret = wg_device_init(); + if (ret < 0) + goto err_device; +@@ -44,6 +48,8 @@ static int __init mod_init(void) + err_netlink: + wg_device_uninit(); + err_device: ++ wg_peer_uninit(); ++err_peer: + return ret; + } + +@@ -51,6 +57,7 @@ static void __exit mod_exit(void) + { + wg_genetlink_uninit(); + wg_device_uninit(); ++ wg_peer_uninit(); + } + + module_init(mod_init); +--- a/drivers/net/wireguard/peer.c ++++ b/drivers/net/wireguard/peer.c +@@ -15,6 +15,7 @@ + #include + #include + ++static struct kmem_cache *peer_cache; + static atomic64_t peer_counter = ATOMIC64_INIT(0); + + struct wg_peer *wg_peer_create(struct wg_device *wg, +@@ -29,10 +30,10 @@ struct wg_peer *wg_peer_create(struct wg + if (wg->num_peers >= MAX_PEERS_PER_DEVICE) + return ERR_PTR(ret); + +- peer = kzalloc(sizeof(*peer), GFP_KERNEL); ++ peer = kmem_cache_zalloc(peer_cache, GFP_KERNEL); + if (unlikely(!peer)) + return ERR_PTR(ret); +- if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) ++ if (unlikely(dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))) + goto err; + + peer->device = wg; +@@ -64,7 +65,7 @@ struct wg_peer *wg_peer_create(struct wg + return peer; + + err: +- kfree(peer); ++ kmem_cache_free(peer_cache, peer); + return ERR_PTR(ret); + } + +@@ -193,7 +194,8 @@ static void rcu_release(struct rcu_head + /* The final zeroing takes care of clearing any remaining handshake key + * material and other potentially sensitive information. + */ +- kzfree(peer); ++ memzero_explicit(peer, sizeof(*peer)); ++ kmem_cache_free(peer_cache, peer); + } + + static void kref_release(struct kref *refcount) +@@ -225,3 +227,14 @@ void wg_peer_put(struct wg_peer *peer) + return; + kref_put(&peer->refcount, kref_release); + } ++ ++int __init wg_peer_init(void) ++{ ++ peer_cache = KMEM_CACHE(wg_peer, 0); ++ return peer_cache ? 0 : -ENOMEM; ++} ++ ++void wg_peer_uninit(void) ++{ ++ kmem_cache_destroy(peer_cache); ++} +--- a/drivers/net/wireguard/peer.h ++++ b/drivers/net/wireguard/peer.h +@@ -80,4 +80,7 @@ void wg_peer_put(struct wg_peer *peer); + void wg_peer_remove(struct wg_peer *peer); + void wg_peer_remove_all(struct wg_device *wg); + ++int wg_peer_init(void); ++void wg_peer_uninit(void); ++ + #endif /* _WG_PEER_H */ diff --git a/ipq806x/backport-5.4/080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch b/ipq806x/backport-5.4/080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch new file mode 100644 index 0000000..ce4e5dc --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0132-wireguard-allowedips-initialize-list-head-in-selftes.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:35 +0200 +Subject: [PATCH] wireguard: allowedips: initialize list head in selftest + +commit 46cfe8eee285cde465b420637507884551f5d7ca upstream. + +The randomized trie tests weren't initializing the dummy peer list head, +resulting in a NULL pointer dereference when used. Fix this by +initializing it in the randomized trie test, just like we do for the +static unit test. + +While we're at it, all of the other strings like this have the word +"self-test", so add it to the missing place here. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/selftest/allowedips.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireguard/selftest/allowedips.c ++++ b/drivers/net/wireguard/selftest/allowedips.c +@@ -296,6 +296,7 @@ static __init bool randomized_test(void) + goto free; + } + kref_init(&peers[i]->refcount); ++ INIT_LIST_HEAD(&peers[i]->allowedips_list); + } + + mutex_lock(&mutex); +@@ -333,7 +334,7 @@ static __init bool randomized_test(void) + if (wg_allowedips_insert_v4(&t, + (struct in_addr *)mutated, + cidr, peer, &mutex) < 0) { +- pr_err("allowedips random malloc: FAIL\n"); ++ pr_err("allowedips random self-test malloc: FAIL\n"); + goto free_locked; + } + if (horrible_allowedips_insert_v4(&h, diff --git a/ipq806x/backport-5.4/080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch b/ipq806x/backport-5.4/080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch new file mode 100644 index 0000000..78da24e --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0133-wireguard-allowedips-remove-nodes-in-O-1.patch @@ -0,0 +1,237 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:36 +0200 +Subject: [PATCH] wireguard: allowedips: remove nodes in O(1) + +commit f634f418c227c912e7ea95a3299efdc9b10e4022 upstream. + +Previously, deleting peers would require traversing the entire trie in +order to rebalance nodes and safely free them. This meant that removing +1000 peers from a trie with a half million nodes would take an extremely +long time, during which we're holding the rtnl lock. Large-scale users +were reporting 200ms latencies added to the networking stack as a whole +every time their userspace software would queue up significant removals. +That's a serious situation. + +This commit fixes that by maintaining a double pointer to the parent's +bit pointer for each node, and then using the already existing node list +belonging to each peer to go directly to the node, fix up its pointers, +and free it with RCU. This means removal is O(1) instead of O(n), and we +don't use gobs of stack. + +The removal algorithm has the same downside as the code that it fixes: +it won't collapse needlessly long runs of fillers. We can enhance that +in the future if it ever becomes a problem. This commit documents that +limitation with a TODO comment in code, a small but meaningful +improvement over the prior situation. + +Currently the biggest flaw, which the next commit addresses, is that +because this increases the node size on 64-bit machines from 60 bytes to +68 bytes. 60 rounds up to 64, but 68 rounds up to 128. So we wind up +using twice as much memory per node, because of power-of-two +allocations, which is a big bummer. We'll need to figure something out +there. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/allowedips.c | 132 ++++++++++++----------------- + drivers/net/wireguard/allowedips.h | 9 +- + 2 files changed, 57 insertions(+), 84 deletions(-) + +--- a/drivers/net/wireguard/allowedips.c ++++ b/drivers/net/wireguard/allowedips.c +@@ -66,60 +66,6 @@ static void root_remove_peer_lists(struc + } + } + +-static void walk_remove_by_peer(struct allowedips_node __rcu **top, +- struct wg_peer *peer, struct mutex *lock) +-{ +-#define REF(p) rcu_access_pointer(p) +-#define DEREF(p) rcu_dereference_protected(*(p), lockdep_is_held(lock)) +-#define PUSH(p) ({ \ +- WARN_ON(IS_ENABLED(DEBUG) && len >= 128); \ +- stack[len++] = p; \ +- }) +- +- struct allowedips_node __rcu **stack[128], **nptr; +- struct allowedips_node *node, *prev; +- unsigned int len; +- +- if (unlikely(!peer || !REF(*top))) +- return; +- +- for (prev = NULL, len = 0, PUSH(top); len > 0; prev = node) { +- nptr = stack[len - 1]; +- node = DEREF(nptr); +- if (!node) { +- --len; +- continue; +- } +- if (!prev || REF(prev->bit[0]) == node || +- REF(prev->bit[1]) == node) { +- if (REF(node->bit[0])) +- PUSH(&node->bit[0]); +- else if (REF(node->bit[1])) +- PUSH(&node->bit[1]); +- } else if (REF(node->bit[0]) == prev) { +- if (REF(node->bit[1])) +- PUSH(&node->bit[1]); +- } else { +- if (rcu_dereference_protected(node->peer, +- lockdep_is_held(lock)) == peer) { +- RCU_INIT_POINTER(node->peer, NULL); +- list_del_init(&node->peer_list); +- if (!node->bit[0] || !node->bit[1]) { +- rcu_assign_pointer(*nptr, DEREF( +- &node->bit[!REF(node->bit[0])])); +- kfree_rcu(node, rcu); +- node = DEREF(nptr); +- } +- } +- --len; +- } +- } +- +-#undef REF +-#undef DEREF +-#undef PUSH +-} +- + static unsigned int fls128(u64 a, u64 b) + { + return a ? fls64(a) + 64U : fls64(b); +@@ -224,6 +170,7 @@ static int add(struct allowedips_node __ + RCU_INIT_POINTER(node->peer, peer); + list_add_tail(&node->peer_list, &peer->allowedips_list); + copy_and_assign_cidr(node, key, cidr, bits); ++ rcu_assign_pointer(node->parent_bit, trie); + rcu_assign_pointer(*trie, node); + return 0; + } +@@ -243,9 +190,9 @@ static int add(struct allowedips_node __ + if (!node) { + down = rcu_dereference_protected(*trie, lockdep_is_held(lock)); + } else { +- down = rcu_dereference_protected(CHOOSE_NODE(node, key), +- lockdep_is_held(lock)); ++ down = rcu_dereference_protected(CHOOSE_NODE(node, key), lockdep_is_held(lock)); + if (!down) { ++ rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, key)); + rcu_assign_pointer(CHOOSE_NODE(node, key), newnode); + return 0; + } +@@ -254,29 +201,37 @@ static int add(struct allowedips_node __ + parent = node; + + if (newnode->cidr == cidr) { ++ rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(newnode, down->bits)); + rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down); +- if (!parent) ++ if (!parent) { ++ rcu_assign_pointer(newnode->parent_bit, trie); + rcu_assign_pointer(*trie, newnode); +- else +- rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), +- newnode); +- } else { +- node = kzalloc(sizeof(*node), GFP_KERNEL); +- if (unlikely(!node)) { +- list_del(&newnode->peer_list); +- kfree(newnode); +- return -ENOMEM; ++ } else { ++ rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(parent, newnode->bits)); ++ rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), newnode); + } +- INIT_LIST_HEAD(&node->peer_list); +- copy_and_assign_cidr(node, newnode->bits, cidr, bits); ++ return 0; ++ } ++ ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (unlikely(!node)) { ++ list_del(&newnode->peer_list); ++ kfree(newnode); ++ return -ENOMEM; ++ } ++ INIT_LIST_HEAD(&node->peer_list); ++ copy_and_assign_cidr(node, newnode->bits, cidr, bits); + +- rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down); +- rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode); +- if (!parent) +- rcu_assign_pointer(*trie, node); +- else +- rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), +- node); ++ rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(node, down->bits)); ++ rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down); ++ rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, newnode->bits)); ++ rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode); ++ if (!parent) { ++ rcu_assign_pointer(node->parent_bit, trie); ++ rcu_assign_pointer(*trie, node); ++ } else { ++ rcu_assign_pointer(node->parent_bit, &CHOOSE_NODE(parent, node->bits)); ++ rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), node); + } + return 0; + } +@@ -335,9 +290,30 @@ int wg_allowedips_insert_v6(struct allow + void wg_allowedips_remove_by_peer(struct allowedips *table, + struct wg_peer *peer, struct mutex *lock) + { ++ struct allowedips_node *node, *child, *tmp; ++ ++ if (list_empty(&peer->allowedips_list)) ++ return; + ++table->seq; +- walk_remove_by_peer(&table->root4, peer, lock); +- walk_remove_by_peer(&table->root6, peer, lock); ++ list_for_each_entry_safe(node, tmp, &peer->allowedips_list, peer_list) { ++ list_del_init(&node->peer_list); ++ RCU_INIT_POINTER(node->peer, NULL); ++ if (node->bit[0] && node->bit[1]) ++ continue; ++ child = rcu_dereference_protected( ++ node->bit[!rcu_access_pointer(node->bit[0])], ++ lockdep_is_held(lock)); ++ if (child) ++ child->parent_bit = node->parent_bit; ++ *rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child; ++ kfree_rcu(node, rcu); ++ ++ /* TODO: Note that we currently don't walk up and down in order to ++ * free any potential filler nodes. This means that this function ++ * doesn't free up as much as it could, which could be revisited ++ * at some point. ++ */ ++ } + } + + int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr) +--- a/drivers/net/wireguard/allowedips.h ++++ b/drivers/net/wireguard/allowedips.h +@@ -15,14 +15,11 @@ struct wg_peer; + struct allowedips_node { + struct wg_peer __rcu *peer; + struct allowedips_node __rcu *bit[2]; +- /* While it may seem scandalous that we waste space for v4, +- * we're alloc'ing to the nearest power of 2 anyway, so this +- * doesn't actually make a difference. +- */ +- u8 bits[16] __aligned(__alignof(u64)); + u8 cidr, bit_at_a, bit_at_b, bitlen; ++ u8 bits[16] __aligned(__alignof(u64)); + +- /* Keep rarely used list at bottom to be beyond cache line. */ ++ /* Keep rarely used members at bottom to be beyond cache line. */ ++ struct allowedips_node *__rcu *parent_bit; /* XXX: this puts us at 68->128 bytes instead of 60->64 bytes!! */ + union { + struct list_head peer_list; + struct rcu_head rcu; diff --git a/ipq806x/backport-5.4/080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch b/ipq806x/backport-5.4/080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch new file mode 100644 index 0000000..65b31b0 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0134-wireguard-allowedips-allocate-nodes-in-kmem_cache.patch @@ -0,0 +1,173 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:37 +0200 +Subject: [PATCH] wireguard: allowedips: allocate nodes in kmem_cache + +commit dc680de28ca849dfe589dc15ac56d22505f0ef11 upstream. + +The previous commit moved from O(n) to O(1) for removal, but in the +process introduced an additional pointer member to a struct that +increased the size from 60 to 68 bytes, putting nodes in the 128-byte +slab. With deployed systems having as many as 2 million nodes, this +represents a significant doubling in memory usage (128 MiB -> 256 MiB). +Fix this by using our own kmem_cache, that's sized exactly right. This +also makes wireguard's memory usage more transparent in tools like +slabtop and /proc/slabinfo. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Suggested-by: Arnd Bergmann +Suggested-by: Matthew Wilcox +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/allowedips.c | 31 ++++++++++++++++++++++++------ + drivers/net/wireguard/allowedips.h | 5 ++++- + drivers/net/wireguard/main.c | 10 +++++++++- + 3 files changed, 38 insertions(+), 8 deletions(-) + +--- a/drivers/net/wireguard/allowedips.c ++++ b/drivers/net/wireguard/allowedips.c +@@ -6,6 +6,8 @@ + #include "allowedips.h" + #include "peer.h" + ++static struct kmem_cache *node_cache; ++ + static void swap_endian(u8 *dst, const u8 *src, u8 bits) + { + if (bits == 32) { +@@ -40,6 +42,11 @@ static void push_rcu(struct allowedips_n + } + } + ++static void node_free_rcu(struct rcu_head *rcu) ++{ ++ kmem_cache_free(node_cache, container_of(rcu, struct allowedips_node, rcu)); ++} ++ + static void root_free_rcu(struct rcu_head *rcu) + { + struct allowedips_node *node, *stack[128] = { +@@ -49,7 +56,7 @@ static void root_free_rcu(struct rcu_hea + while (len > 0 && (node = stack[--len])) { + push_rcu(stack, node->bit[0], &len); + push_rcu(stack, node->bit[1], &len); +- kfree(node); ++ kmem_cache_free(node_cache, node); + } + } + +@@ -164,7 +171,7 @@ static int add(struct allowedips_node __ + return -EINVAL; + + if (!rcu_access_pointer(*trie)) { +- node = kzalloc(sizeof(*node), GFP_KERNEL); ++ node = kmem_cache_zalloc(node_cache, GFP_KERNEL); + if (unlikely(!node)) + return -ENOMEM; + RCU_INIT_POINTER(node->peer, peer); +@@ -180,7 +187,7 @@ static int add(struct allowedips_node __ + return 0; + } + +- newnode = kzalloc(sizeof(*newnode), GFP_KERNEL); ++ newnode = kmem_cache_zalloc(node_cache, GFP_KERNEL); + if (unlikely(!newnode)) + return -ENOMEM; + RCU_INIT_POINTER(newnode->peer, peer); +@@ -213,10 +220,10 @@ static int add(struct allowedips_node __ + return 0; + } + +- node = kzalloc(sizeof(*node), GFP_KERNEL); ++ node = kmem_cache_zalloc(node_cache, GFP_KERNEL); + if (unlikely(!node)) { + list_del(&newnode->peer_list); +- kfree(newnode); ++ kmem_cache_free(node_cache, newnode); + return -ENOMEM; + } + INIT_LIST_HEAD(&node->peer_list); +@@ -306,7 +313,7 @@ void wg_allowedips_remove_by_peer(struct + if (child) + child->parent_bit = node->parent_bit; + *rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child; +- kfree_rcu(node, rcu); ++ call_rcu(&node->rcu, node_free_rcu); + + /* TODO: Note that we currently don't walk up and down in order to + * free any potential filler nodes. This means that this function +@@ -350,4 +357,16 @@ struct wg_peer *wg_allowedips_lookup_src + return NULL; + } + ++int __init wg_allowedips_slab_init(void) ++{ ++ node_cache = KMEM_CACHE(allowedips_node, 0); ++ return node_cache ? 0 : -ENOMEM; ++} ++ ++void wg_allowedips_slab_uninit(void) ++{ ++ rcu_barrier(); ++ kmem_cache_destroy(node_cache); ++} ++ + #include "selftest/allowedips.c" +--- a/drivers/net/wireguard/allowedips.h ++++ b/drivers/net/wireguard/allowedips.h +@@ -19,7 +19,7 @@ struct allowedips_node { + u8 bits[16] __aligned(__alignof(u64)); + + /* Keep rarely used members at bottom to be beyond cache line. */ +- struct allowedips_node *__rcu *parent_bit; /* XXX: this puts us at 68->128 bytes instead of 60->64 bytes!! */ ++ struct allowedips_node *__rcu *parent_bit; + union { + struct list_head peer_list; + struct rcu_head rcu; +@@ -53,4 +53,7 @@ struct wg_peer *wg_allowedips_lookup_src + bool wg_allowedips_selftest(void); + #endif + ++int wg_allowedips_slab_init(void); ++void wg_allowedips_slab_uninit(void); ++ + #endif /* _WG_ALLOWEDIPS_H */ +--- a/drivers/net/wireguard/main.c ++++ b/drivers/net/wireguard/main.c +@@ -21,10 +21,15 @@ static int __init mod_init(void) + { + int ret; + ++ ret = wg_allowedips_slab_init(); ++ if (ret < 0) ++ goto err_allowedips; ++ + #ifdef DEBUG ++ ret = -ENOTRECOVERABLE; + if (!wg_allowedips_selftest() || !wg_packet_counter_selftest() || + !wg_ratelimiter_selftest()) +- return -ENOTRECOVERABLE; ++ goto err_peer; + #endif + wg_noise_init(); + +@@ -50,6 +55,8 @@ err_netlink: + err_device: + wg_peer_uninit(); + err_peer: ++ wg_allowedips_slab_uninit(); ++err_allowedips: + return ret; + } + +@@ -58,6 +65,7 @@ static void __exit mod_exit(void) + wg_genetlink_uninit(); + wg_device_uninit(); + wg_peer_uninit(); ++ wg_allowedips_slab_uninit(); + } + + module_init(mod_init); diff --git a/ipq806x/backport-5.4/080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch b/ipq806x/backport-5.4/080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch new file mode 100644 index 0000000..c044ad2 --- /dev/null +++ b/ipq806x/backport-5.4/080-wireguard-0135-wireguard-allowedips-free-empty-intermediate-nodes-w.patch @@ -0,0 +1,521 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 4 Jun 2021 17:17:38 +0200 +Subject: [PATCH] wireguard: allowedips: free empty intermediate nodes when + removing single node + +commit bf7b042dc62a31f66d3a41dd4dfc7806f267b307 upstream. + +When removing single nodes, it's possible that that node's parent is an +empty intermediate node, in which case, it too should be removed. +Otherwise the trie fills up and never is fully emptied, leading to +gradual memory leaks over time for tries that are modified often. There +was originally code to do this, but was removed during refactoring in +2016 and never reworked. Now that we have proper parent pointers from +the previous commits, we can implement this properly. + +In order to reduce branching and expensive comparisons, we want to keep +the double pointer for parent assignment (which lets us easily chain up +to the root), but we still need to actually get the parent's base +address. So encode the bit number into the last two bits of the pointer, +and pack and unpack it as needed. This is a little bit clumsy but is the +fastest and less memory wasteful of the compromises. Note that we align +the root struct here to a minimum of 4, because it's embedded into a +larger struct, and we're relying on having the bottom two bits for our +flag, which would only be 16-bit aligned on m68k. + +The existing macro-based helpers were a bit unwieldy for adding the bit +packing to, so this commit replaces them with safer and clearer ordinary +functions. + +We add a test to the randomized/fuzzer part of the selftests, to free +the randomized tries by-peer, refuzz it, and repeat, until it's supposed +to be empty, and then then see if that actually resulted in the whole +thing being emptied. That combined with kmemcheck should hopefully make +sure this commit is doing what it should. Along the way this resulted in +various other cleanups of the tests and fixes for recent graphviz. + +Fixes: e7096c131e51 ("net: WireGuard secure network tunnel") +Cc: stable@vger.kernel.org +Signed-off-by: Jason A. Donenfeld +Signed-off-by: David S. Miller +Signed-off-by: Jason A. Donenfeld +--- + drivers/net/wireguard/allowedips.c | 102 ++++++------ + drivers/net/wireguard/allowedips.h | 4 +- + drivers/net/wireguard/selftest/allowedips.c | 162 ++++++++++---------- + 3 files changed, 137 insertions(+), 131 deletions(-) + +--- a/drivers/net/wireguard/allowedips.c ++++ b/drivers/net/wireguard/allowedips.c +@@ -30,8 +30,11 @@ static void copy_and_assign_cidr(struct + node->bitlen = bits; + memcpy(node->bits, src, bits / 8U); + } +-#define CHOOSE_NODE(parent, key) \ +- parent->bit[(key[parent->bit_at_a] >> parent->bit_at_b) & 1] ++ ++static inline u8 choose(struct allowedips_node *node, const u8 *key) ++{ ++ return (key[node->bit_at_a] >> node->bit_at_b) & 1; ++} + + static void push_rcu(struct allowedips_node **stack, + struct allowedips_node __rcu *p, unsigned int *len) +@@ -112,7 +115,7 @@ static struct allowedips_node *find_node + found = node; + if (node->cidr == bits) + break; +- node = rcu_dereference_bh(CHOOSE_NODE(node, key)); ++ node = rcu_dereference_bh(node->bit[choose(node, key)]); + } + return found; + } +@@ -144,8 +147,7 @@ static bool node_placement(struct allowe + u8 cidr, u8 bits, struct allowedips_node **rnode, + struct mutex *lock) + { +- struct allowedips_node *node = rcu_dereference_protected(trie, +- lockdep_is_held(lock)); ++ struct allowedips_node *node = rcu_dereference_protected(trie, lockdep_is_held(lock)); + struct allowedips_node *parent = NULL; + bool exact = false; + +@@ -155,13 +157,24 @@ static bool node_placement(struct allowe + exact = true; + break; + } +- node = rcu_dereference_protected(CHOOSE_NODE(parent, key), +- lockdep_is_held(lock)); ++ node = rcu_dereference_protected(parent->bit[choose(parent, key)], lockdep_is_held(lock)); + } + *rnode = parent; + return exact; + } + ++static inline void connect_node(struct allowedips_node **parent, u8 bit, struct allowedips_node *node) ++{ ++ node->parent_bit_packed = (unsigned long)parent | bit; ++ rcu_assign_pointer(*parent, node); ++} ++ ++static inline void choose_and_connect_node(struct allowedips_node *parent, struct allowedips_node *node) ++{ ++ u8 bit = choose(parent, node->bits); ++ connect_node(&parent->bit[bit], bit, node); ++} ++ + static int add(struct allowedips_node __rcu **trie, u8 bits, const u8 *key, + u8 cidr, struct wg_peer *peer, struct mutex *lock) + { +@@ -177,8 +190,7 @@ static int add(struct allowedips_node __ + RCU_INIT_POINTER(node->peer, peer); + list_add_tail(&node->peer_list, &peer->allowedips_list); + copy_and_assign_cidr(node, key, cidr, bits); +- rcu_assign_pointer(node->parent_bit, trie); +- rcu_assign_pointer(*trie, node); ++ connect_node(trie, 2, node); + return 0; + } + if (node_placement(*trie, key, cidr, bits, &node, lock)) { +@@ -197,10 +209,10 @@ static int add(struct allowedips_node __ + if (!node) { + down = rcu_dereference_protected(*trie, lockdep_is_held(lock)); + } else { +- down = rcu_dereference_protected(CHOOSE_NODE(node, key), lockdep_is_held(lock)); ++ const u8 bit = choose(node, key); ++ down = rcu_dereference_protected(node->bit[bit], lockdep_is_held(lock)); + if (!down) { +- rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, key)); +- rcu_assign_pointer(CHOOSE_NODE(node, key), newnode); ++ connect_node(&node->bit[bit], bit, newnode); + return 0; + } + } +@@ -208,15 +220,11 @@ static int add(struct allowedips_node __ + parent = node; + + if (newnode->cidr == cidr) { +- rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(newnode, down->bits)); +- rcu_assign_pointer(CHOOSE_NODE(newnode, down->bits), down); +- if (!parent) { +- rcu_assign_pointer(newnode->parent_bit, trie); +- rcu_assign_pointer(*trie, newnode); +- } else { +- rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(parent, newnode->bits)); +- rcu_assign_pointer(CHOOSE_NODE(parent, newnode->bits), newnode); +- } ++ choose_and_connect_node(newnode, down); ++ if (!parent) ++ connect_node(trie, 2, newnode); ++ else ++ choose_and_connect_node(parent, newnode); + return 0; + } + +@@ -229,17 +237,12 @@ static int add(struct allowedips_node __ + INIT_LIST_HEAD(&node->peer_list); + copy_and_assign_cidr(node, newnode->bits, cidr, bits); + +- rcu_assign_pointer(down->parent_bit, &CHOOSE_NODE(node, down->bits)); +- rcu_assign_pointer(CHOOSE_NODE(node, down->bits), down); +- rcu_assign_pointer(newnode->parent_bit, &CHOOSE_NODE(node, newnode->bits)); +- rcu_assign_pointer(CHOOSE_NODE(node, newnode->bits), newnode); +- if (!parent) { +- rcu_assign_pointer(node->parent_bit, trie); +- rcu_assign_pointer(*trie, node); +- } else { +- rcu_assign_pointer(node->parent_bit, &CHOOSE_NODE(parent, node->bits)); +- rcu_assign_pointer(CHOOSE_NODE(parent, node->bits), node); +- } ++ choose_and_connect_node(node, down); ++ choose_and_connect_node(node, newnode); ++ if (!parent) ++ connect_node(trie, 2, node); ++ else ++ choose_and_connect_node(parent, node); + return 0; + } + +@@ -297,7 +300,8 @@ int wg_allowedips_insert_v6(struct allow + void wg_allowedips_remove_by_peer(struct allowedips *table, + struct wg_peer *peer, struct mutex *lock) + { +- struct allowedips_node *node, *child, *tmp; ++ struct allowedips_node *node, *child, **parent_bit, *parent, *tmp; ++ bool free_parent; + + if (list_empty(&peer->allowedips_list)) + return; +@@ -307,19 +311,29 @@ void wg_allowedips_remove_by_peer(struct + RCU_INIT_POINTER(node->peer, NULL); + if (node->bit[0] && node->bit[1]) + continue; +- child = rcu_dereference_protected( +- node->bit[!rcu_access_pointer(node->bit[0])], +- lockdep_is_held(lock)); ++ child = rcu_dereference_protected(node->bit[!rcu_access_pointer(node->bit[0])], ++ lockdep_is_held(lock)); + if (child) +- child->parent_bit = node->parent_bit; +- *rcu_dereference_protected(node->parent_bit, lockdep_is_held(lock)) = child; ++ child->parent_bit_packed = node->parent_bit_packed; ++ parent_bit = (struct allowedips_node **)(node->parent_bit_packed & ~3UL); ++ *parent_bit = child; ++ parent = (void *)parent_bit - ++ offsetof(struct allowedips_node, bit[node->parent_bit_packed & 1]); ++ free_parent = !rcu_access_pointer(node->bit[0]) && ++ !rcu_access_pointer(node->bit[1]) && ++ (node->parent_bit_packed & 3) <= 1 && ++ !rcu_access_pointer(parent->peer); ++ if (free_parent) ++ child = rcu_dereference_protected( ++ parent->bit[!(node->parent_bit_packed & 1)], ++ lockdep_is_held(lock)); + call_rcu(&node->rcu, node_free_rcu); +- +- /* TODO: Note that we currently don't walk up and down in order to +- * free any potential filler nodes. This means that this function +- * doesn't free up as much as it could, which could be revisited +- * at some point. +- */ ++ if (!free_parent) ++ continue; ++ if (child) ++ child->parent_bit_packed = parent->parent_bit_packed; ++ *(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child; ++ call_rcu(&parent->rcu, node_free_rcu); + } + } + +--- a/drivers/net/wireguard/allowedips.h ++++ b/drivers/net/wireguard/allowedips.h +@@ -19,7 +19,7 @@ struct allowedips_node { + u8 bits[16] __aligned(__alignof(u64)); + + /* Keep rarely used members at bottom to be beyond cache line. */ +- struct allowedips_node *__rcu *parent_bit; ++ unsigned long parent_bit_packed; + union { + struct list_head peer_list; + struct rcu_head rcu; +@@ -30,7 +30,7 @@ struct allowedips { + struct allowedips_node __rcu *root4; + struct allowedips_node __rcu *root6; + u64 seq; +-}; ++} __aligned(4); /* We pack the lower 2 bits of &root, but m68k only gives 16-bit alignment. */ + + void wg_allowedips_init(struct allowedips *table); + void wg_allowedips_free(struct allowedips *table, struct mutex *mutex); +--- a/drivers/net/wireguard/selftest/allowedips.c ++++ b/drivers/net/wireguard/selftest/allowedips.c +@@ -19,32 +19,22 @@ + + #include + +-static __init void swap_endian_and_apply_cidr(u8 *dst, const u8 *src, u8 bits, +- u8 cidr) +-{ +- swap_endian(dst, src, bits); +- memset(dst + (cidr + 7) / 8, 0, bits / 8 - (cidr + 7) / 8); +- if (cidr) +- dst[(cidr + 7) / 8 - 1] &= ~0U << ((8 - (cidr % 8)) % 8); +-} +- + static __init void print_node(struct allowedips_node *node, u8 bits) + { + char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n"; +- char *fmt_declaration = KERN_DEBUG +- "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n"; ++ char *fmt_declaration = KERN_DEBUG "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n"; ++ u8 ip1[16], ip2[16], cidr1, cidr2; + char *style = "dotted"; +- u8 ip1[16], ip2[16]; + u32 color = 0; + ++ if (node == NULL) ++ return; + if (bits == 32) { + fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n"; +- fmt_declaration = KERN_DEBUG +- "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n"; ++ fmt_declaration = KERN_DEBUG "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n"; + } else if (bits == 128) { + fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n"; +- fmt_declaration = KERN_DEBUG +- "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n"; ++ fmt_declaration = KERN_DEBUG "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n"; + } + if (node->peer) { + hsiphash_key_t key = { { 0 } }; +@@ -55,24 +45,20 @@ static __init void print_node(struct all + hsiphash_1u32(0xabad1dea, &key) % 200; + style = "bold"; + } +- swap_endian_and_apply_cidr(ip1, node->bits, bits, node->cidr); +- printk(fmt_declaration, ip1, node->cidr, style, color); ++ wg_allowedips_read_node(node, ip1, &cidr1); ++ printk(fmt_declaration, ip1, cidr1, style, color); + if (node->bit[0]) { +- swap_endian_and_apply_cidr(ip2, +- rcu_dereference_raw(node->bit[0])->bits, bits, +- node->cidr); +- printk(fmt_connection, ip1, node->cidr, ip2, +- rcu_dereference_raw(node->bit[0])->cidr); +- print_node(rcu_dereference_raw(node->bit[0]), bits); ++ wg_allowedips_read_node(rcu_dereference_raw(node->bit[0]), ip2, &cidr2); ++ printk(fmt_connection, ip1, cidr1, ip2, cidr2); + } + if (node->bit[1]) { +- swap_endian_and_apply_cidr(ip2, +- rcu_dereference_raw(node->bit[1])->bits, +- bits, node->cidr); +- printk(fmt_connection, ip1, node->cidr, ip2, +- rcu_dereference_raw(node->bit[1])->cidr); +- print_node(rcu_dereference_raw(node->bit[1]), bits); ++ wg_allowedips_read_node(rcu_dereference_raw(node->bit[1]), ip2, &cidr2); ++ printk(fmt_connection, ip1, cidr1, ip2, cidr2); + } ++ if (node->bit[0]) ++ print_node(rcu_dereference_raw(node->bit[0]), bits); ++ if (node->bit[1]) ++ print_node(rcu_dereference_raw(node->bit[1]), bits); + } + + static __init void print_tree(struct allowedips_node __rcu *top, u8 bits) +@@ -121,8 +107,8 @@ static __init inline union nf_inet_addr + { + union nf_inet_addr mask; + +- memset(&mask, 0x00, 128 / 8); +- memset(&mask, 0xff, cidr / 8); ++ memset(&mask, 0, sizeof(mask)); ++ memset(&mask.all, 0xff, cidr / 8); + if (cidr % 32) + mask.all[cidr / 32] = (__force u32)htonl( + (0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL); +@@ -149,42 +135,36 @@ horrible_mask_self(struct horrible_allow + } + + static __init inline bool +-horrible_match_v4(const struct horrible_allowedips_node *node, +- struct in_addr *ip) ++horrible_match_v4(const struct horrible_allowedips_node *node, struct in_addr *ip) + { + return (ip->s_addr & node->mask.ip) == node->ip.ip; + } + + static __init inline bool +-horrible_match_v6(const struct horrible_allowedips_node *node, +- struct in6_addr *ip) ++horrible_match_v6(const struct horrible_allowedips_node *node, struct in6_addr *ip) + { +- return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == +- node->ip.ip6[0] && +- (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == +- node->ip.ip6[1] && +- (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == +- node->ip.ip6[2] && ++ return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == node->ip.ip6[0] && ++ (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == node->ip.ip6[1] && ++ (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == node->ip.ip6[2] && + (ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3]; + } + + static __init void +-horrible_insert_ordered(struct horrible_allowedips *table, +- struct horrible_allowedips_node *node) ++horrible_insert_ordered(struct horrible_allowedips *table, struct horrible_allowedips_node *node) + { + struct horrible_allowedips_node *other = NULL, *where = NULL; + u8 my_cidr = horrible_mask_to_cidr(node->mask); + + hlist_for_each_entry(other, &table->head, table) { +- if (!memcmp(&other->mask, &node->mask, +- sizeof(union nf_inet_addr)) && +- !memcmp(&other->ip, &node->ip, +- sizeof(union nf_inet_addr)) && +- other->ip_version == node->ip_version) { ++ if (other->ip_version == node->ip_version && ++ !memcmp(&other->mask, &node->mask, sizeof(union nf_inet_addr)) && ++ !memcmp(&other->ip, &node->ip, sizeof(union nf_inet_addr))) { + other->value = node->value; + kfree(node); + return; + } ++ } ++ hlist_for_each_entry(other, &table->head, table) { + where = other; + if (horrible_mask_to_cidr(other->mask) <= my_cidr) + break; +@@ -201,8 +181,7 @@ static __init int + horrible_allowedips_insert_v4(struct horrible_allowedips *table, + struct in_addr *ip, u8 cidr, void *value) + { +- struct horrible_allowedips_node *node = kzalloc(sizeof(*node), +- GFP_KERNEL); ++ struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL); + + if (unlikely(!node)) + return -ENOMEM; +@@ -219,8 +198,7 @@ static __init int + horrible_allowedips_insert_v6(struct horrible_allowedips *table, + struct in6_addr *ip, u8 cidr, void *value) + { +- struct horrible_allowedips_node *node = kzalloc(sizeof(*node), +- GFP_KERNEL); ++ struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL); + + if (unlikely(!node)) + return -ENOMEM; +@@ -234,39 +212,43 @@ horrible_allowedips_insert_v6(struct hor + } + + static __init void * +-horrible_allowedips_lookup_v4(struct horrible_allowedips *table, +- struct in_addr *ip) ++horrible_allowedips_lookup_v4(struct horrible_allowedips *table, struct in_addr *ip) + { + struct horrible_allowedips_node *node; +- void *ret = NULL; + + hlist_for_each_entry(node, &table->head, table) { +- if (node->ip_version != 4) +- continue; +- if (horrible_match_v4(node, ip)) { +- ret = node->value; +- break; +- } ++ if (node->ip_version == 4 && horrible_match_v4(node, ip)) ++ return node->value; + } +- return ret; ++ return NULL; + } + + static __init void * +-horrible_allowedips_lookup_v6(struct horrible_allowedips *table, +- struct in6_addr *ip) ++horrible_allowedips_lookup_v6(struct horrible_allowedips *table, struct in6_addr *ip) + { + struct horrible_allowedips_node *node; +- void *ret = NULL; + + hlist_for_each_entry(node, &table->head, table) { +- if (node->ip_version != 6) ++ if (node->ip_version == 6 && horrible_match_v6(node, ip)) ++ return node->value; ++ } ++ return NULL; ++} ++ ++ ++static __init void ++horrible_allowedips_remove_by_value(struct horrible_allowedips *table, void *value) ++{ ++ struct horrible_allowedips_node *node; ++ struct hlist_node *h; ++ ++ hlist_for_each_entry_safe(node, h, &table->head, table) { ++ if (node->value != value) + continue; +- if (horrible_match_v6(node, ip)) { +- ret = node->value; +- break; +- } ++ hlist_del(&node->table); ++ kfree(node); + } +- return ret; ++ + } + + static __init bool randomized_test(void) +@@ -397,23 +379,33 @@ static __init bool randomized_test(void) + print_tree(t.root6, 128); + } + +- for (i = 0; i < NUM_QUERIES; ++i) { +- prandom_bytes(ip, 4); +- if (lookup(t.root4, 32, ip) != +- horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) { +- pr_err("allowedips random self-test: FAIL\n"); +- goto free; ++ for (j = 0;; ++j) { ++ for (i = 0; i < NUM_QUERIES; ++i) { ++ prandom_bytes(ip, 4); ++ if (lookup(t.root4, 32, ip) != horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) { ++ horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip); ++ pr_err("allowedips random v4 self-test: FAIL\n"); ++ goto free; ++ } ++ prandom_bytes(ip, 16); ++ if (lookup(t.root6, 128, ip) != horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) { ++ pr_err("allowedips random v6 self-test: FAIL\n"); ++ goto free; ++ } + } ++ if (j >= NUM_PEERS) ++ break; ++ mutex_lock(&mutex); ++ wg_allowedips_remove_by_peer(&t, peers[j], &mutex); ++ mutex_unlock(&mutex); ++ horrible_allowedips_remove_by_value(&h, peers[j]); + } + +- for (i = 0; i < NUM_QUERIES; ++i) { +- prandom_bytes(ip, 16); +- if (lookup(t.root6, 128, ip) != +- horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) { +- pr_err("allowedips random self-test: FAIL\n"); +- goto free; +- } ++ if (t.root4 || t.root6) { ++ pr_err("allowedips random self-test removal: FAIL\n"); ++ goto free; + } ++ + ret = true; + + free: diff --git a/ipq806x/backport-5.4/300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch b/ipq806x/backport-5.4/300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch new file mode 100644 index 0000000..0bc58e7 --- /dev/null +++ b/ipq806x/backport-5.4/300-MIPS-Exclude-more-dsemul-code-when-CONFIG_MIPS_FP_SU.patch @@ -0,0 +1,134 @@ +From d96c3157f9ca177727fbad960fcf6f52f145f471 Mon Sep 17 00:00:00 2001 +From: Yousong Zhou +Date: Thu, 9 Jan 2020 11:33:19 +0800 +Subject: [PATCH] MIPS: Exclude more dsemul code when CONFIG_MIPS_FP_SUPPORT=n + +This furthers what commit 42b10815d559 ("MIPS: Don't compile math-emu +when CONFIG_MIPS_FP_SUPPORT=n") has done + +Signed-off-by: Yousong Zhou +--- + arch/mips/include/asm/processor.h | 12 ++++++------ + arch/mips/kernel/process.c | 10 ++++++++-- + arch/mips/kernel/vdso.c | 26 +++++++++++++++----------- + 3 files changed, 29 insertions(+), 19 deletions(-) + +--- a/arch/mips/include/asm/processor.h ++++ b/arch/mips/include/asm/processor.h +@@ -253,13 +253,13 @@ struct thread_struct { + #ifdef CONFIG_MIPS_FP_SUPPORT + /* Saved fpu/fpu emulator stuff. */ + struct mips_fpu_struct fpu FPU_ALIGN; +-#endif + /* Assigned branch delay slot 'emulation' frame */ + atomic_t bd_emu_frame; + /* PC of the branch from a branch delay slot 'emulation' */ + unsigned long bd_emu_branch_pc; + /* PC to continue from following a branch delay slot 'emulation' */ + unsigned long bd_emu_cont_pc; ++#endif + #ifdef CONFIG_MIPS_MT_FPAFF + /* Emulated instruction count */ + unsigned long emulated_fp; +@@ -302,7 +302,11 @@ struct thread_struct { + .fpr = {{{0,},},}, \ + .fcr31 = 0, \ + .msacsr = 0, \ +- }, ++ }, \ ++ /* Delay slot emulation */ \ ++ .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE), \ ++ .bd_emu_branch_pc = 0, \ ++ .bd_emu_cont_pc = 0, + #else + # define FPU_INIT + #endif +@@ -334,10 +338,6 @@ struct thread_struct { + * FPU affinity state (null if not FPAFF) \ + */ \ + FPAFF_INIT \ +- /* Delay slot emulation */ \ +- .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE), \ +- .bd_emu_branch_pc = 0, \ +- .bd_emu_cont_pc = 0, \ + /* \ + * Saved DSP stuff \ + */ \ +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -75,7 +75,9 @@ void start_thread(struct pt_regs * regs, + lose_fpu(0); + clear_thread_flag(TIF_MSA_CTX_LIVE); + clear_used_math(); ++#ifdef CONFIG_MIPS_FP_SUPPORT + atomic_set(¤t->thread.bd_emu_frame, BD_EMUFRAME_NONE); ++#endif + init_dsp(); + regs->cp0_epc = pc; + regs->regs[29] = sp; +@@ -176,7 +178,9 @@ int copy_thread_tls(unsigned long clone_ + clear_tsk_thread_flag(p, TIF_FPUBOUND); + #endif /* CONFIG_MIPS_MT_FPAFF */ + ++#ifdef CONFIG_MIPS_FP_SUPPORT + atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE); ++#endif + + if (clone_flags & CLONE_SETTLS) + ti->tp_value = tls; +@@ -650,8 +654,10 @@ unsigned long mips_stack_top(void) + { + unsigned long top = TASK_SIZE & PAGE_MASK; + +- /* One page for branch delay slot "emulation" */ +- top -= PAGE_SIZE; ++ if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) { ++ /* One page for branch delay slot "emulation" */ ++ top -= PAGE_SIZE; ++ } + + /* Space for the VDSO, data page & GIC user page */ + top -= PAGE_ALIGN(current->thread.abi->vdso->size); +--- a/arch/mips/kernel/vdso.c ++++ b/arch/mips/kernel/vdso.c +@@ -71,10 +71,12 @@ subsys_initcall(init_vdso); + + static unsigned long vdso_base(void) + { +- unsigned long base; ++ unsigned long base = STACK_TOP; + +- /* Skip the delay slot emulation page */ +- base = STACK_TOP + PAGE_SIZE; ++ if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) { ++ /* Skip the delay slot emulation page */ ++ base += PAGE_SIZE; ++ } + + if (current->flags & PF_RANDOMIZE) { + base += get_random_int() & (VDSO_RANDOMIZE_SIZE - 1); +@@ -95,14 +97,16 @@ int arch_setup_additional_pages(struct l + if (down_write_killable(&mm->mmap_sem)) + return -EINTR; + +- /* Map delay slot emulation page */ +- base = mmap_region(NULL, STACK_TOP, PAGE_SIZE, +- VM_READ | VM_EXEC | +- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, +- 0, NULL); +- if (IS_ERR_VALUE(base)) { +- ret = base; +- goto out; ++ if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) { ++ /* Map delay slot emulation page */ ++ base = mmap_region(NULL, STACK_TOP, PAGE_SIZE, ++ VM_READ | VM_EXEC | ++ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, ++ 0, NULL); ++ if (IS_ERR_VALUE(base)) { ++ ret = base; ++ goto out; ++ } + } + + /* diff --git a/ipq806x/backport-5.4/310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch b/ipq806x/backport-5.4/310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch new file mode 100644 index 0000000..e02f103 --- /dev/null +++ b/ipq806x/backport-5.4/310-mips-Kconfig-Add-ARCH_HAS_FORTIFY_SOURCE.patch @@ -0,0 +1,32 @@ +From a8d2bb0559b5fefa5173ff4e7496cc6250db2c8a Mon Sep 17 00:00:00 2001 +From: Dmitry Korotin +Date: Thu, 12 Sep 2019 22:53:45 +0000 +Subject: [PATCH] mips: Kconfig: Add ARCH_HAS_FORTIFY_SOURCE + +FORTIFY_SOURCE detects various overflows at compile and run time. +(6974f0c4555e ("include/linux/string.h: +add the option of fortified string.h functions) + +ARCH_HAS_FORTIFY_SOURCE means that the architecture can be built and +run with CONFIG_FORTIFY_SOURCE. + +Since mips can be built and run with that flag, +select ARCH_HAS_FORTIFY_SOURCE as default. + +Signed-off-by: Dmitry Korotin +Signed-off-by: Paul Burton +Cc: linux-mips@vger.kernel.org +--- + arch/mips/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -7,6 +7,7 @@ config MIPS + select ARCH_CLOCKSOURCE_DATA + select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST + select ARCH_HAS_UBSAN_SANITIZE_ALL ++ select ARCH_HAS_FORTIFY_SOURCE + select ARCH_SUPPORTS_UPROBES + select ARCH_USE_BUILTIN_BSWAP + select ARCH_USE_CMPXCHG_LOCKREF if 64BIT diff --git a/ipq806x/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch b/ipq806x/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch new file mode 100644 index 0000000..51eef4b --- /dev/null +++ b/ipq806x/backport-5.4/310-v5.6-mips-vdso-fix-jalr-t9-crash-in-vdso-code.patch @@ -0,0 +1,54 @@ +From d3f703c4359ff06619b2322b91f69710453e6b6d Mon Sep 17 00:00:00 2001 +From: Victor Kamensky +Date: Tue, 11 Feb 2020 11:24:33 -0800 +Subject: [PATCH] mips: vdso: fix 'jalr t9' crash in vdso code + +Observed that when kernel is built with Yocto mips64-poky-linux-gcc, +and mips64-poky-linux-gnun32-gcc toolchain, resulting vdso contains +'jalr t9' instructions in its code and since in vdso case nobody +sets GOT table code crashes when instruction reached. On other hand +observed that when kernel is built mips-poky-linux-gcc toolchain, the +same 'jalr t9' instruction are replaced with PC relative function +calls using 'bal' instructions. + +The difference boils down to -mrelax-pic-calls and -mexplicit-relocs +gcc options that gets different default values depending on gcc +target triplets and corresponding binutils. -mrelax-pic-calls got +enabled by default only in mips-poky-linux-gcc case. MIPS binutils +ld relies on R_MIPS_JALR relocation to convert 'jalr t9' into 'bal' +and such relocation is generated only if -mrelax-pic-calls option +is on. + +Please note 'jalr t9' conversion to 'bal' can happen only to static +functions. These static PIC calls use mips local GOT entries that +are supposed to be filled with start of DSO value by run-time linker +(missing in VDSO case) and they do not have dynamic relocations. +Global mips GOT entries must have dynamic relocations and they should +be prevented by cmd_vdso_check Makefile rule. + +Solution call out -mrelax-pic-calls and -mexplicit-relocs options +explicitly while compiling MIPS vdso code. That would get correct +and consistent between different toolchains behaviour. + +Reported-by: Bruce Ashfield +Signed-off-by: Victor Kamensky +Signed-off-by: Paul Burton +Cc: linux-mips@vger.kernel.org +Cc: Ralf Baechle +Cc: James Hogan +Cc: Vincenzo Frascino +Cc: richard.purdie@linuxfoundation.org +--- + arch/mips/vdso/Makefile | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/mips/vdso/Makefile ++++ b/arch/mips/vdso/Makefile +@@ -26,6 +26,7 @@ ccflags-vdso := \ + cflags-vdso := $(ccflags-vdso) \ + $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ + -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \ ++ -mrelax-pic-calls -mexplicit-relocs \ + -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \ + $(call cc-option, -fno-asynchronous-unwind-tables) \ + $(call cc-option, -fno-stack-protector) diff --git a/ipq806x/backport-5.4/311-MIPS-Fix-exception-handler-memcpy.patch b/ipq806x/backport-5.4/311-MIPS-Fix-exception-handler-memcpy.patch new file mode 100644 index 0000000..5a6725c --- /dev/null +++ b/ipq806x/backport-5.4/311-MIPS-Fix-exception-handler-memcpy.patch @@ -0,0 +1,107 @@ +From e01c91a360793298c9e1656a61faceff01487a43 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Sat, 23 May 2020 23:50:34 +0800 +Subject: [PATCH] MIPS: Fix exception handler memcpy() + +The exception handler subroutines are declared as a single char, but +when copied to the required addresses the copy length is 0x80. + +When range checks are enabled for memcpy() this results in a build +failure, with error messages such as: + +In file included from arch/mips/mti-malta/malta-init.c:15: +In function 'memcpy', + inlined from 'mips_nmi_setup' at arch/mips/mti-malta/malta-init.c:98:2: +include/linux/string.h:376:4: error: call to '__read_overflow2' declared with attribute error: detected read beyond size of object passed as 2nd parameter + 376 | __read_overflow2(); + | ^~~~~~~~~~~~~~~~~~ + +Change the declarations to use type char[]. + +Signed-off-by: Ben Hutchings +Signed-off-by: YunQiang Su +Signed-off-by: Thomas Bogendoerfer +--- + arch/mips/loongson64/common/init.c | 4 ++-- + arch/mips/mti-malta/malta-init.c | 8 ++++---- + arch/mips/pistachio/init.c | 8 ++++---- + 3 files changed, 10 insertions(+), 10 deletions(-) + +--- a/arch/mips/loongson64/common/init.c ++++ b/arch/mips/loongson64/common/init.c +@@ -18,10 +18,10 @@ unsigned long __maybe_unused _loongson_a + static void __init mips_nmi_setup(void) + { + void *base; +- extern char except_vec_nmi; ++ extern char except_vec_nmi[]; + + base = (void *)(CAC_BASE + 0x380); +- memcpy(base, &except_vec_nmi, 0x80); ++ memcpy(base, except_vec_nmi, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); + } + +--- a/arch/mips/mti-malta/malta-init.c ++++ b/arch/mips/mti-malta/malta-init.c +@@ -90,24 +90,24 @@ static void __init console_config(void) + static void __init mips_nmi_setup(void) + { + void *base; +- extern char except_vec_nmi; ++ extern char except_vec_nmi[]; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa80) : + (void *)(CAC_BASE + 0x380); +- memcpy(base, &except_vec_nmi, 0x80); ++ memcpy(base, except_vec_nmi, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); + } + + static void __init mips_ejtag_setup(void) + { + void *base; +- extern char except_vec_ejtag_debug; ++ extern char except_vec_ejtag_debug[]; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa00) : + (void *)(CAC_BASE + 0x300); +- memcpy(base, &except_vec_ejtag_debug, 0x80); ++ memcpy(base, except_vec_ejtag_debug, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); + } + +--- a/arch/mips/pistachio/init.c ++++ b/arch/mips/pistachio/init.c +@@ -83,12 +83,12 @@ phys_addr_t mips_cdmm_phys_base(void) + static void __init mips_nmi_setup(void) + { + void *base; +- extern char except_vec_nmi; ++ extern char except_vec_nmi[]; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa80) : + (void *)(CAC_BASE + 0x380); +- memcpy(base, &except_vec_nmi, 0x80); ++ memcpy(base, except_vec_nmi, 0x80); + flush_icache_range((unsigned long)base, + (unsigned long)base + 0x80); + } +@@ -96,12 +96,12 @@ static void __init mips_nmi_setup(void) + static void __init mips_ejtag_setup(void) + { + void *base; +- extern char except_vec_ejtag_debug; ++ extern char except_vec_ejtag_debug[]; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa00) : + (void *)(CAC_BASE + 0x300); +- memcpy(base, &except_vec_ejtag_debug, 0x80); ++ memcpy(base, except_vec_ejtag_debug, 0x80); + flush_icache_range((unsigned long)base, + (unsigned long)base + 0x80); + } diff --git a/ipq806x/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch b/ipq806x/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch new file mode 100644 index 0000000..501f42d --- /dev/null +++ b/ipq806x/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch @@ -0,0 +1,99 @@ +From: Pablo Neira Ayuso +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 +--- + +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -529,5 +529,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); ++ ++ 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 "); +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -234,47 +234,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); +- +- 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/ipq806x/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch b/ipq806x/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch new file mode 100644 index 0000000..373a156 --- /dev/null +++ b/ipq806x/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch @@ -0,0 +1,114 @@ +From: Felix Fietkau +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 +--- + +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1207,18 +1207,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 long end_time = jiffies + GC_SCAN_MAX_DURATION; +@@ -1250,10 +1238,8 @@ static void gc_worker(struct work_struct + + tmp = nf_ct_tuplehash_to_ctrack(h); + +- 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 +@@ -198,10 +198,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, +@@ -304,6 +323,7 @@ nf_flow_table_iterate(struct nf_flowtabl + rhashtable_walk_start(&hti); + + while ((tuplehash = rhashtable_walk_next(&hti))) { ++ + if (IS_ERR(tuplehash)) { + if (PTR_ERR(tuplehash) != -EAGAIN) { + err = PTR_ERR(tuplehash); +@@ -328,10 +348,17 @@ static void nf_flow_offload_gc_step(stru + { + struct nf_flowtable *flow_table = data; + struct flow_offload_entry *e; ++ bool teardown; + + e = container_of(flow, struct flow_offload_entry, flow); +- if (nf_flow_has_expired(flow) || nf_ct_is_dying(e->ct) || +- (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); + } + diff --git a/ipq806x/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch b/ipq806x/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch new file mode 100644 index 0000000..383641d --- /dev/null +++ b/ipq806x/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +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 +--- + +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -268,6 +268,9 @@ static void flow_offload_del(struct nf_f + else if (flow->flags & FLOW_OFFLOAD_TEARDOWN) + flow_offload_fixup_ct_timeout(e->ct); + ++ if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN)) ++ flow_offload_fixup_ct_state(e->ct); ++ + flow_offload_free(flow); + } + diff --git a/ipq806x/backport-5.4/393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch b/ipq806x/backport-5.4/393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch new file mode 100644 index 0000000..6c9e8ad --- /dev/null +++ b/ipq806x/backport-5.4/393-v5.5-sch_cake-drop-unused-variable-tin_quantum_prio.patch @@ -0,0 +1,158 @@ +From d7e1738f0a0b0573ac93cf570ba3df9dee61b68e Mon Sep 17 00:00:00 2001 +From: Kevin 'ldir' Darbyshire-Bryant +Date: Wed, 18 Dec 2019 14:05:13 +0000 +Subject: [PATCH 2/2] sch_cake: drop unused variable tin_quantum_prio +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Turns out tin_quantum_prio isn't used anymore and is a leftover from a +previous implementation of diffserv tins. Since the variable isn't used +in any calculations it can be eliminated. + +Drop variable and places where it was set. Rename remaining variable +and consolidate naming of intermediate variables that set it. + +Signed-off-by: Kevin Darbyshire-Bryant +Acked-by: Toke Høiland-Jørgensen +Signed-off-by: David S. Miller +--- + net/sched/sch_cake.c | 59 ++++++++++++++------------------------------ + 1 file changed, 18 insertions(+), 41 deletions(-) + +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -173,8 +173,7 @@ struct cake_tin_data { + u64 tin_rate_bps; + u16 tin_rate_shft; + +- u16 tin_quantum_prio; +- u16 tin_quantum_band; ++ u16 tin_quantum; + s32 tin_deficit; + u32 tin_backlog; + u32 tin_dropped; +@@ -1947,7 +1946,7 @@ begin: + while (b->tin_deficit < 0 || + !(b->sparse_flow_count + b->bulk_flow_count)) { + if (b->tin_deficit <= 0) +- b->tin_deficit += b->tin_quantum_band; ++ b->tin_deficit += b->tin_quantum; + if (b->sparse_flow_count + b->bulk_flow_count) + empty = false; + +@@ -2269,8 +2268,7 @@ static int cake_config_besteffort(struct + + cake_set_rate(b, rate, mtu, + us_to_ns(q->target), us_to_ns(q->interval)); +- b->tin_quantum_band = 65535; +- b->tin_quantum_prio = 65535; ++ b->tin_quantum = 65535; + + return 0; + } +@@ -2281,8 +2279,7 @@ static int cake_config_precedence(struct + struct cake_sched_data *q = qdisc_priv(sch); + u32 mtu = psched_mtu(qdisc_dev(sch)); + u64 rate = q->rate_bps; +- u32 quantum1 = 256; +- u32 quantum2 = 256; ++ u32 quantum = 256; + u32 i; + + q->tin_cnt = 8; +@@ -2295,18 +2292,14 @@ static int cake_config_precedence(struct + cake_set_rate(b, rate, mtu, us_to_ns(q->target), + us_to_ns(q->interval)); + +- b->tin_quantum_prio = max_t(u16, 1U, quantum1); +- b->tin_quantum_band = max_t(u16, 1U, quantum2); ++ b->tin_quantum = max_t(u16, 1U, quantum); + + /* calculate next class's parameters */ + rate *= 7; + rate >>= 3; + +- quantum1 *= 3; +- quantum1 >>= 1; +- +- quantum2 *= 7; +- quantum2 >>= 3; ++ quantum *= 7; ++ quantum >>= 3; + } + + return 0; +@@ -2375,8 +2368,7 @@ static int cake_config_diffserv8(struct + struct cake_sched_data *q = qdisc_priv(sch); + u32 mtu = psched_mtu(qdisc_dev(sch)); + u64 rate = q->rate_bps; +- u32 quantum1 = 256; +- u32 quantum2 = 256; ++ u32 quantum = 256; + u32 i; + + q->tin_cnt = 8; +@@ -2392,18 +2384,14 @@ static int cake_config_diffserv8(struct + cake_set_rate(b, rate, mtu, us_to_ns(q->target), + us_to_ns(q->interval)); + +- b->tin_quantum_prio = max_t(u16, 1U, quantum1); +- b->tin_quantum_band = max_t(u16, 1U, quantum2); ++ b->tin_quantum = max_t(u16, 1U, quantum); + + /* calculate next class's parameters */ + rate *= 7; + rate >>= 3; + +- quantum1 *= 3; +- quantum1 >>= 1; +- +- quantum2 *= 7; +- quantum2 >>= 3; ++ quantum *= 7; ++ quantum >>= 3; + } + + return 0; +@@ -2442,17 +2430,11 @@ static int cake_config_diffserv4(struct + cake_set_rate(&q->tins[3], rate >> 2, mtu, + us_to_ns(q->target), us_to_ns(q->interval)); + +- /* priority weights */ +- q->tins[0].tin_quantum_prio = quantum; +- q->tins[1].tin_quantum_prio = quantum >> 4; +- q->tins[2].tin_quantum_prio = quantum << 2; +- q->tins[3].tin_quantum_prio = quantum << 4; +- + /* bandwidth-sharing weights */ +- q->tins[0].tin_quantum_band = quantum; +- q->tins[1].tin_quantum_band = quantum >> 4; +- q->tins[2].tin_quantum_band = quantum >> 1; +- q->tins[3].tin_quantum_band = quantum >> 2; ++ q->tins[0].tin_quantum = quantum; ++ q->tins[1].tin_quantum = quantum >> 4; ++ q->tins[2].tin_quantum = quantum >> 1; ++ q->tins[3].tin_quantum = quantum >> 2; + + return 0; + } +@@ -2483,15 +2465,10 @@ static int cake_config_diffserv3(struct + cake_set_rate(&q->tins[2], rate >> 2, mtu, + us_to_ns(q->target), us_to_ns(q->interval)); + +- /* priority weights */ +- q->tins[0].tin_quantum_prio = quantum; +- q->tins[1].tin_quantum_prio = quantum >> 4; +- q->tins[2].tin_quantum_prio = quantum << 4; +- + /* bandwidth-sharing weights */ +- q->tins[0].tin_quantum_band = quantum; +- q->tins[1].tin_quantum_band = quantum >> 4; +- q->tins[2].tin_quantum_band = quantum >> 2; ++ q->tins[0].tin_quantum = quantum; ++ q->tins[1].tin_quantum = quantum >> 4; ++ q->tins[2].tin_quantum = quantum >> 2; + + return 0; + } diff --git a/ipq806x/backport-5.4/395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch b/ipq806x/backport-5.4/395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch new file mode 100644 index 0000000..a4981ac --- /dev/null +++ b/ipq806x/backport-5.4/395-v5.8-net-sch_cake-Take-advantage-of-skb-hash-where-appropriate.patch @@ -0,0 +1,170 @@ +From b0c19ed6088ab41dd2a727b60594b7297c15d6ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= +Date: Fri, 29 May 2020 14:43:44 +0200 +Subject: [PATCH] sch_cake: Take advantage of skb->hash where appropriate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While the other fq-based qdiscs take advantage of skb->hash and doesn't +recompute it if it is already set, sch_cake does not. + +This was a deliberate choice because sch_cake hashes various parts of the +packet header to support its advanced flow isolation modes. However, +foregoing the use of skb->hash entirely loses a few important benefits: + +- When skb->hash is set by hardware, a few CPU cycles can be saved by not + hashing again in software. + +- Tunnel encapsulations will generally preserve the value of skb->hash from + before the encapsulation, which allows flow-based qdiscs to distinguish + between flows even though the outer packet header no longer has flow + information. + +It turns out that we can preserve these desirable properties in many cases, +while still supporting the advanced flow isolation properties of sch_cake. +This patch does so by reusing the skb->hash value as the flow_hash part of +the hashing procedure in cake_hash() only in the following conditions: + +- If the skb->hash is marked as covering the flow headers (skb->l4_hash is + set) + +AND + +- NAT header rewriting is either disabled, or did not change any values + used for hashing. The latter is important to match local-origin packets + such as those of a tunnel endpoint. + +The immediate motivation for fixing this was the recent patch to WireGuard +to preserve the skb->hash on encapsulation. As such, this is also what I +tested against; with this patch, added latency under load for competing +flows drops from ~8 ms to sub-1ms on an RRUL test over a WireGuard tunnel +going through a virtual link shaped to 1Gbps using sch_cake. This matches +the results we saw with a similar setup using sch_fq_codel when testing the +WireGuard patch. + +Fixes: 046f6fd5daef ("sched: Add Common Applications Kept Enhanced (cake) qdisc") +Signed-off-by: Toke Høiland-Jørgensen +Signed-off-by: David S. Miller +Signed-off-by: Kevin Darbyshire-Bryant +--- + net/sched/sch_cake.c | 65 ++++++++++++++++++++++++++++++++++---------- + 1 file changed, 51 insertions(+), 14 deletions(-) + +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -584,26 +584,48 @@ static bool cobalt_should_drop(struct co + return drop; + } + +-static void cake_update_flowkeys(struct flow_keys *keys, ++static bool cake_update_flowkeys(struct flow_keys *keys, + const struct sk_buff *skb) + { + #if IS_ENABLED(CONFIG_NF_CONNTRACK) + struct nf_conntrack_tuple tuple = {}; +- bool rev = !skb->_nfct; ++ bool rev = !skb->_nfct, upd = false; ++ __be32 ip; + + if (skb_protocol(skb, true) != htons(ETH_P_IP)) +- return; ++ return false; + + if (!nf_ct_get_tuple_skb(&tuple, skb)) +- return; ++ return false; + +- keys->addrs.v4addrs.src = rev ? tuple.dst.u3.ip : tuple.src.u3.ip; +- keys->addrs.v4addrs.dst = rev ? tuple.src.u3.ip : tuple.dst.u3.ip; ++ ip = rev ? tuple.dst.u3.ip : tuple.src.u3.ip; ++ if (ip != keys->addrs.v4addrs.src) { ++ keys->addrs.v4addrs.src = ip; ++ upd = true; ++ } ++ ip = rev ? tuple.src.u3.ip : tuple.dst.u3.ip; ++ if (ip != keys->addrs.v4addrs.dst) { ++ keys->addrs.v4addrs.dst = ip; ++ upd = true; ++ } + + if (keys->ports.ports) { +- keys->ports.src = rev ? tuple.dst.u.all : tuple.src.u.all; +- keys->ports.dst = rev ? tuple.src.u.all : tuple.dst.u.all; ++ __be16 port; ++ ++ port = rev ? tuple.dst.u.all : tuple.src.u.all; ++ if (port != keys->ports.src) { ++ keys->ports.src = port; ++ upd = true; ++ } ++ port = rev ? tuple.src.u.all : tuple.dst.u.all; ++ if (port != keys->ports.dst) { ++ port = keys->ports.dst; ++ upd = true; ++ } + } ++ return upd; ++#else ++ return false; + #endif + } + +@@ -624,23 +646,36 @@ static bool cake_ddst(int flow_mode) + static u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb, + int flow_mode, u16 flow_override, u16 host_override) + { ++ bool hash_flows = (!flow_override && !!(flow_mode & CAKE_FLOW_FLOWS)); ++ bool hash_hosts = (!host_override && !!(flow_mode & CAKE_FLOW_HOSTS)); ++ bool nat_enabled = !!(flow_mode & CAKE_FLOW_NAT_FLAG); + u32 flow_hash = 0, srchost_hash = 0, dsthost_hash = 0; + u16 reduced_hash, srchost_idx, dsthost_idx; + struct flow_keys keys, host_keys; ++ bool use_skbhash = skb->l4_hash; + + if (unlikely(flow_mode == CAKE_FLOW_NONE)) + return 0; + +- /* If both overrides are set we can skip packet dissection entirely */ +- if ((flow_override || !(flow_mode & CAKE_FLOW_FLOWS)) && +- (host_override || !(flow_mode & CAKE_FLOW_HOSTS))) ++ /* If both overrides are set, or we can use the SKB hash and nat mode is ++ * disabled, we can skip packet dissection entirely. If nat mode is ++ * enabled there's another check below after doing the conntrack lookup. ++ */ ++ if ((!hash_flows || (use_skbhash && !nat_enabled)) && !hash_hosts) + goto skip_hash; + + skb_flow_dissect_flow_keys(skb, &keys, + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); + +- if (flow_mode & CAKE_FLOW_NAT_FLAG) +- cake_update_flowkeys(&keys, skb); ++ /* Don't use the SKB hash if we change the lookup keys from conntrack */ ++ if (nat_enabled && cake_update_flowkeys(&keys, skb)) ++ use_skbhash = false; ++ ++ /* If we can still use the SKB hash and don't need the host hash, we can ++ * skip the rest of the hashing procedure ++ */ ++ if (use_skbhash && !hash_hosts) ++ goto skip_hash; + + /* flow_hash_from_keys() sorts the addresses by value, so we have + * to preserve their order in a separate data structure to treat +@@ -679,12 +714,14 @@ static u32 cake_hash(struct cake_tin_dat + /* This *must* be after the above switch, since as a + * side-effect it sorts the src and dst addresses. + */ +- if (flow_mode & CAKE_FLOW_FLOWS) ++ if (hash_flows && !use_skbhash) + flow_hash = flow_hash_from_keys(&keys); + + skip_hash: + if (flow_override) + flow_hash = flow_override - 1; ++ else if (use_skbhash) ++ flow_hash = skb->hash; + if (host_override) { + dsthost_hash = host_override - 1; + srchost_hash = host_override - 1; diff --git a/ipq806x/backport-5.4/399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch b/ipq806x/backport-5.4/399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch new file mode 100644 index 0000000..e171b4c --- /dev/null +++ b/ipq806x/backport-5.4/399-5.9-sch_cake-add-RFC-8622-LE-PHB-support-to-CAKE-diffser.patch @@ -0,0 +1,57 @@ +From b8392808eb3fc28e523e28cb258c81ca246deb9b Mon Sep 17 00:00:00 2001 +From: Kevin Darbyshire-Bryant +Date: Thu, 25 Jun 2020 22:18:00 +0200 +Subject: [PATCH] sch_cake: add RFC 8622 LE PHB support to CAKE diffserv + handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Change tin mapping on diffserv3, 4 & 8 for LE PHB support, in essence +making LE a member of the Bulk tin. + +Bulk has the least priority and minimum of 1/16th total bandwidth in the +face of higher priority traffic. + +NB: Diffserv 3 & 4 swap tin 0 & 1 priorities from the default order as +found in diffserv8, in case anyone is wondering why it looks a bit odd. + +Signed-off-by: Kevin Darbyshire-Bryant +[ reword commit message slightly ] +Signed-off-by: Toke Høiland-Jørgensen +Signed-off-by: David S. Miller +--- + net/sched/sch_cake.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/net/sched/sch_cake.c ++++ b/net/sched/sch_cake.c +@@ -312,8 +312,8 @@ static const u8 precedence[] = { + }; + + static const u8 diffserv8[] = { +- 2, 5, 1, 2, 4, 2, 2, 2, +- 0, 2, 1, 2, 1, 2, 1, 2, ++ 2, 0, 1, 2, 4, 2, 2, 2, ++ 1, 2, 1, 2, 1, 2, 1, 2, + 5, 2, 4, 2, 4, 2, 4, 2, + 3, 2, 3, 2, 3, 2, 3, 2, + 6, 2, 3, 2, 3, 2, 3, 2, +@@ -323,7 +323,7 @@ static const u8 diffserv8[] = { + }; + + static const u8 diffserv4[] = { +- 0, 2, 0, 0, 2, 0, 0, 0, ++ 0, 1, 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 2, 0, 2, 0, 2, 0, + 2, 0, 2, 0, 2, 0, 2, 0, +@@ -334,7 +334,7 @@ static const u8 diffserv4[] = { + }; + + static const u8 diffserv3[] = { +- 0, 0, 0, 0, 2, 0, 0, 0, ++ 0, 1, 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/ipq806x/backport-5.4/400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch b/ipq806x/backport-5.4/400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch new file mode 100644 index 0000000..7926843 --- /dev/null +++ b/ipq806x/backport-5.4/400-v5.8-dt-bindings-mtd-partition-Document-the-slc-mode-prop.patch @@ -0,0 +1,28 @@ +From 422928a040fe17d17ded69c57903c7908423c7ef Mon Sep 17 00:00:00 2001 +From: Boris Brezillon +Date: Sun, 3 May 2020 17:53:38 +0200 +Subject: [PATCH] dt-bindings: mtd: partition: Document the slc-mode property + +Add a boolean property to force a specific partition attached to an MLC +NAND to be accessed in an emulated SLC mode this making this partition +immune to paired-pages corruptions. + +Signed-off-by: Boris Brezillon +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20200503155341.16712-6-miquel.raynal@bootlin.com +--- + Documentation/devicetree/bindings/mtd/partition.txt | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/Documentation/devicetree/bindings/mtd/partition.txt ++++ b/Documentation/devicetree/bindings/mtd/partition.txt +@@ -61,6 +61,9 @@ Optional properties: + clobbered. + - lock : Do not unlock the partition at initialization time (not supported on + all devices) ++- slc-mode: This parameter, if present, allows one to emulate SLC mode on a ++ partition attached to an MLC NAND thus making this partition immune to ++ paired-pages corruptions + + Examples: + diff --git a/ipq806x/backport-5.4/401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch b/ipq806x/backport-5.4/401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch new file mode 100644 index 0000000..8aded43 --- /dev/null +++ b/ipq806x/backport-5.4/401-v5.11-dt-bindings-mtd-convert-fixed-partitions-to-the-json.patch @@ -0,0 +1,324 @@ +From 04e9ab75267489224364fa510a88ada83e11c325 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 10 Dec 2020 18:23:52 +0100 +Subject: [PATCH] dt-bindings: mtd: convert "fixed-partitions" to the + json-schema +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This standardizes its documentation, allows validating with Makefile +checks and helps writing DTS files. + +Noticeable changes: +1. Dropped "Partitions can be represented by sub-nodes of a flash + device." as we also support subpartitions (don't have to be part of + flash device node) +2. Dropped "to Linux" as bindings are meant to be os agnostic. + +Signed-off-by: Rafał Miłecki +Link: https://lore.kernel.org/r/20201210172352.31632-1-zajec5@gmail.com +Signed-off-by: Rob Herring +--- + .../devicetree/bindings/mtd/partition.txt | 131 +-------------- + .../mtd/partitions/fixed-partitions.yaml | 152 ++++++++++++++++++ + 2 files changed, 154 insertions(+), 129 deletions(-) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml + +--- a/Documentation/devicetree/bindings/mtd/partition.txt ++++ b/Documentation/devicetree/bindings/mtd/partition.txt +@@ -24,137 +24,10 @@ another partitioning method. + Available bindings are listed in the "partitions" subdirectory. + + +-Fixed Partitions +-================ +- +-Partitions can be represented by sub-nodes of a flash device. This can be used +-on platforms which have strong conventions about which portions of a flash are +-used for what purposes, but which don't use an on-flash partition table such +-as RedBoot. +- +-The partition table should be a subnode of the flash node and should be named +-'partitions'. This node should have the following property: +-- compatible : (required) must be "fixed-partitions" +-Partitions are then defined in subnodes of the partitions node. ++Deprecated: partitions defined in flash node ++============================================ + + For backwards compatibility partitions as direct subnodes of the flash device are + supported. This use is discouraged. + NOTE: also for backwards compatibility, direct subnodes that have a compatible + string are not considered partitions, as they may be used for other bindings. +- +-#address-cells & #size-cells must both be present in the partitions subnode of the +-flash device. There are two valid values for both: +-<1>: for partitions that require a single 32-bit cell to represent their +- size/address (aka the value is below 4 GiB) +-<2>: for partitions that require two 32-bit cells to represent their +- size/address (aka the value is 4 GiB or greater). +- +-Required properties: +-- reg : The partition's offset and size within the flash +- +-Optional properties: +-- label : The label / name for this partition. If omitted, the label is taken +- from the node name (excluding the unit address). +-- read-only : This parameter, if present, is a hint to Linux that this +- partition should only be mounted read-only. This is usually used for flash +- partitions containing early-boot firmware images or data which should not be +- clobbered. +-- lock : Do not unlock the partition at initialization time (not supported on +- all devices) +-- slc-mode: This parameter, if present, allows one to emulate SLC mode on a +- partition attached to an MLC NAND thus making this partition immune to +- paired-pages corruptions +- +-Examples: +- +- +-flash@0 { +- partitions { +- compatible = "fixed-partitions"; +- #address-cells = <1>; +- #size-cells = <1>; +- +- partition@0 { +- label = "u-boot"; +- reg = <0x0000000 0x100000>; +- read-only; +- }; +- +- uimage@100000 { +- reg = <0x0100000 0x200000>; +- }; +- }; +-}; +- +-flash@1 { +- partitions { +- compatible = "fixed-partitions"; +- #address-cells = <1>; +- #size-cells = <2>; +- +- /* a 4 GiB partition */ +- partition@0 { +- label = "filesystem"; +- reg = <0x00000000 0x1 0x00000000>; +- }; +- }; +-}; +- +-flash@2 { +- partitions { +- compatible = "fixed-partitions"; +- #address-cells = <2>; +- #size-cells = <2>; +- +- /* an 8 GiB partition */ +- partition@0 { +- label = "filesystem #1"; +- reg = <0x0 0x00000000 0x2 0x00000000>; +- }; +- +- /* a 4 GiB partition */ +- partition@200000000 { +- label = "filesystem #2"; +- reg = <0x2 0x00000000 0x1 0x00000000>; +- }; +- }; +-}; +- +-flash@3 { +- partitions { +- compatible = "fixed-partitions"; +- #address-cells = <1>; +- #size-cells = <1>; +- +- partition@0 { +- label = "bootloader"; +- reg = <0x000000 0x100000>; +- read-only; +- }; +- +- firmware@100000 { +- label = "firmware"; +- reg = <0x100000 0xe00000>; +- compatible = "brcm,trx"; +- }; +- +- calibration@f00000 { +- label = "calibration"; +- reg = <0xf00000 0x100000>; +- compatible = "fixed-partitions"; +- ranges = <0 0xf00000 0x100000>; +- #address-cells = <1>; +- #size-cells = <1>; +- +- partition@0 { +- label = "wifi0"; +- reg = <0x000000 0x080000>; +- }; +- +- partition@80000 { +- label = "wifi1"; +- reg = <0x080000 0x080000>; +- }; +- }; +- }; +-}; +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml +@@ -0,0 +1,152 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/fixed-partitions.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Fixed partitions ++ ++description: | ++ This binding can be used on platforms which have strong conventions about ++ which portions of a flash are used for what purposes, but which don't use an ++ on-flash partition table such as RedBoot. ++ ++ The partition table should be a node named "partitions". Partitions are then ++ defined as subnodes. ++ ++maintainers: ++ - Rafał Miłecki ++ ++properties: ++ compatible: ++ const: fixed-partitions ++ ++ "#address-cells": true ++ ++ "#size-cells": true ++ ++patternProperties: ++ "@[0-9a-f]+$": ++ description: node describing a single flash partition ++ type: object ++ ++ properties: ++ reg: ++ description: partition's offset and size within the flash ++ maxItems: 1 ++ ++ label: ++ description: The label / name for this partition. If omitted, the label ++ is taken from the node name (excluding the unit address). ++ ++ read-only: ++ description: This parameter, if present, is a hint that this partition ++ should only be mounted read-only. This is usually used for flash ++ partitions containing early-boot firmware images or data which should ++ not be clobbered. ++ type: boolean ++ ++ lock: ++ description: Do not unlock the partition at initialization time (not ++ supported on all devices) ++ type: boolean ++ ++ slc-mode: ++ description: This parameter, if present, allows one to emulate SLC mode ++ on a partition attached to an MLC NAND thus making this partition ++ immune to paired-pages corruptions ++ type: boolean ++ ++ required: ++ - reg ++ ++required: ++ - "#address-cells" ++ - "#size-cells" ++ ++additionalProperties: true ++ ++examples: ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "u-boot"; ++ reg = <0x0000000 0x100000>; ++ read-only; ++ }; ++ ++ uimage@100000 { ++ reg = <0x0100000 0x200000>; ++ }; ++ }; ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <2>; ++ ++ /* a 4 GiB partition */ ++ partition@0 { ++ label = "filesystem"; ++ reg = <0x00000000 0x1 0x00000000>; ++ }; ++ }; ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ /* an 8 GiB partition */ ++ partition@0 { ++ label = "filesystem #1"; ++ reg = <0x0 0x00000000 0x2 0x00000000>; ++ }; ++ ++ /* a 4 GiB partition */ ++ partition@200000000 { ++ label = "filesystem #2"; ++ reg = <0x2 0x00000000 0x1 0x00000000>; ++ }; ++ }; ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bootloader"; ++ reg = <0x000000 0x100000>; ++ read-only; ++ }; ++ ++ firmware@100000 { ++ compatible = "brcm,trx"; ++ label = "firmware"; ++ reg = <0x100000 0xe00000>; ++ }; ++ ++ calibration@f00000 { ++ compatible = "fixed-partitions"; ++ label = "calibration"; ++ reg = <0xf00000 0x100000>; ++ ranges = <0 0xf00000 0x100000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "wifi0"; ++ reg = <0x000000 0x080000>; ++ }; ++ ++ partition@80000 { ++ label = "wifi1"; ++ reg = <0x080000 0x080000>; ++ }; ++ }; ++ }; diff --git a/ipq806x/backport-5.4/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch b/ipq806x/backport-5.4/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch new file mode 100644 index 0000000..f3b1179 --- /dev/null +++ b/ipq806x/backport-5.4/402-v5.12-0001-dt-bindings-mtd-move-partition-binding-to-its-own-fi.patch @@ -0,0 +1,115 @@ +From 6418522022c706fd867b00b2571edba48b8fa8c7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 11 Feb 2021 23:04:25 +0100 +Subject: [PATCH] dt-bindings: mtd: move partition binding to its own file +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Single partition binding is quite common and may be: +1. Used by multiple parsers +2. Extended for more specific cases + +Move it to separated file to avoid code duplication. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Rob Herring +Signed-off-by: Richard Weinberger +--- + .../mtd/partitions/fixed-partitions.yaml | 33 +------------ + .../bindings/mtd/partitions/partition.yaml | 47 +++++++++++++++++++ + 2 files changed, 48 insertions(+), 32 deletions(-) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/partition.yaml + +--- a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml ++++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml +@@ -27,38 +27,7 @@ properties: + + patternProperties: + "@[0-9a-f]+$": +- description: node describing a single flash partition +- type: object +- +- properties: +- reg: +- description: partition's offset and size within the flash +- maxItems: 1 +- +- label: +- description: The label / name for this partition. If omitted, the label +- is taken from the node name (excluding the unit address). +- +- read-only: +- description: This parameter, if present, is a hint that this partition +- should only be mounted read-only. This is usually used for flash +- partitions containing early-boot firmware images or data which should +- not be clobbered. +- type: boolean +- +- lock: +- description: Do not unlock the partition at initialization time (not +- supported on all devices) +- type: boolean +- +- slc-mode: +- description: This parameter, if present, allows one to emulate SLC mode +- on a partition attached to an MLC NAND thus making this partition +- immune to paired-pages corruptions +- type: boolean +- +- required: +- - reg ++ $ref: "partition.yaml#" + + required: + - "#address-cells" +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/partition.yaml +@@ -0,0 +1,47 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/partition.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Partition ++ ++description: | ++ This binding describes a single flash partition. Each partition must have its ++ relative offset and size specified. Depending on partition function extra ++ properties can be used. ++ ++maintainers: ++ - Rafał Miłecki ++ ++properties: ++ reg: ++ description: partition's offset and size within the flash ++ maxItems: 1 ++ ++ label: ++ description: The label / name for this partition. If omitted, the label ++ is taken from the node name (excluding the unit address). ++ ++ read-only: ++ description: This parameter, if present, is a hint that this partition ++ should only be mounted read-only. This is usually used for flash ++ partitions containing early-boot firmware images or data which should ++ not be clobbered. ++ type: boolean ++ ++ lock: ++ description: Do not unlock the partition at initialization time (not ++ supported on all devices) ++ type: boolean ++ ++ slc-mode: ++ description: This parameter, if present, allows one to emulate SLC mode ++ on a partition attached to an MLC NAND thus making this partition ++ immune to paired-pages corruptions ++ type: boolean ++ ++required: ++ - reg ++ ++additionalProperties: true diff --git a/ipq806x/backport-5.4/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch b/ipq806x/backport-5.4/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch new file mode 100644 index 0000000..8576c7d --- /dev/null +++ b/ipq806x/backport-5.4/402-v5.12-0002-dt-bindings-mtd-add-binding-for-BCM4908-partitions.patch @@ -0,0 +1,92 @@ +From 6e9dff6fe3fbc452f16566e4a7e293b0decefdba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 11 Feb 2021 23:04:26 +0100 +Subject: [PATCH] dt-bindings: mtd: add binding for BCM4908 partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +BCM4908 uses fixed partitions layout but function of some partitions may +vary. Some devices use multiple firmware partitions and those partitions +should be marked to let system discover their purpose. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Richard Weinberger +--- + .../partitions/brcm,bcm4908-partitions.yaml | 70 +++++++++++++++++++ + 1 file changed, 70 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/brcm,bcm4908-partitions.yaml +@@ -0,0 +1,70 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/brcm,bcm4908-partitions.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom BCM4908 partitioning ++ ++description: | ++ Broadcom BCM4908 CFE bootloader supports two firmware partitions. One is used ++ for regular booting, the other is treated as fallback. ++ ++ This binding allows defining all fixed partitions and marking those containing ++ firmware. System can use that information e.g. for booting or flashing ++ purposes. ++ ++maintainers: ++ - Rafał Miłecki ++ ++properties: ++ compatible: ++ const: brcm,bcm4908-partitions ++ ++ "#address-cells": ++ enum: [ 1, 2 ] ++ ++ "#size-cells": ++ enum: [ 1, 2 ] ++ ++patternProperties: ++ "^partition@[0-9a-f]+$": ++ $ref: "partition.yaml#" ++ properties: ++ compatible: ++ const: brcm,bcm4908-firmware ++ unevaluatedProperties: false ++ ++required: ++ - "#address-cells" ++ - "#size-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ partitions { ++ compatible = "brcm,bcm4908-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "cferom"; ++ reg = <0x0 0x100000>; ++ }; ++ ++ partition@100000 { ++ compatible = "brcm,bcm4908-firmware"; ++ reg = <0x100000 0xf00000>; ++ }; ++ ++ partition@1000000 { ++ compatible = "brcm,bcm4908-firmware"; ++ reg = <0x1000000 0xf00000>; ++ }; ++ ++ partition@1f00000 { ++ label = "calibration"; ++ reg = <0x1f00000 0x100000>; ++ }; ++ }; diff --git a/ipq806x/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch b/ipq806x/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch new file mode 100644 index 0000000..8f292bd --- /dev/null +++ b/ipq806x/backport-5.4/403-v5.13-mtd-parsers-ofpart-support-BCM4908-fixed-partitions.patch @@ -0,0 +1,648 @@ +From afbef8efb591792579c633a7c545f914c6165f82 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 11 Feb 2021 23:04:27 +0100 +Subject: [PATCH] mtd: parsers: ofpart: support BCM4908 fixed partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some devices use fixed partitioning with some partitions requiring some +extra logic. E.g. BCM4908 may have multiple firmware partitions but +detecting currently used one requires checking bootloader parameters. + +To support such cases without duplicating a lot of code (without copying +most of the ofpart.c code) support for post-parsing callback was added. + +BCM4908 support in ofpart can be enabled using config option and results +in compiling & executing a specific callback. It simply reads offset of +currently used firmware partition from the DT. Bootloader specifies it +using the "brcm_blparms" property. + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/parsers/Kconfig | 9 +++ + drivers/mtd/parsers/Makefile | 2 + + drivers/mtd/parsers/ofpart_bcm4908.c | 64 +++++++++++++++++++ + drivers/mtd/parsers/ofpart_bcm4908.h | 15 +++++ + .../mtd/parsers/{ofpart.c => ofpart_core.c} | 28 +++++++- + 5 files changed, 116 insertions(+), 2 deletions(-) + create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.c + create mode 100644 drivers/mtd/parsers/ofpart_bcm4908.h + rename drivers/mtd/parsers/{ofpart.c => ofpart_core.c} (88%) + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -67,6 +67,15 @@ config MTD_OF_PARTS + flash memory node, as described in + Documentation/devicetree/bindings/mtd/partition.txt. + ++config MTD_OF_PARTS_BCM4908 ++ bool "BCM4908 partitioning support" ++ depends on MTD_OF_PARTS && (ARCH_BCM4908 || COMPILE_TEST) ++ default ARCH_BCM4908 ++ help ++ This provides partitions parser for BCM4908 family devices ++ that can have multiple "firmware" partitions. It takes care of ++ finding currently used one and backup ones. ++ + config MTD_PARSER_IMAGETAG + tristate "Parser for BCM963XX Image Tag format partitions" + depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -4,6 +4,8 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm4 + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o ++ofpart-y += ofpart_core.o ++ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o + obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o + obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o +--- /dev/null ++++ b/drivers/mtd/parsers/ofpart_bcm4908.c +@@ -0,0 +1,64 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Rafał Miłecki ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ofpart_bcm4908.h" ++ ++#define BLPARAMS_FW_OFFSET "NAND_RFS_OFS" ++ ++static long long bcm4908_partitions_fw_offset(void) ++{ ++ struct device_node *root; ++ struct property *prop; ++ const char *s; ++ ++ root = of_find_node_by_path("/"); ++ if (!root) ++ return -ENOENT; ++ ++ of_property_for_each_string(root, "brcm_blparms", prop, s) { ++ size_t len = strlen(BLPARAMS_FW_OFFSET); ++ unsigned long offset; ++ int err; ++ ++ if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=') ++ continue; ++ ++ err = kstrtoul(s + len + 1, 0, &offset); ++ if (err) { ++ pr_err("failed to parse %s\n", s + len + 1); ++ return err; ++ } ++ ++ return offset << 10; ++ } ++ ++ return -ENOENT; ++} ++ ++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts) ++{ ++ long long fw_offset; ++ int i; ++ ++ fw_offset = bcm4908_partitions_fw_offset(); ++ ++ for (i = 0; i < nr_parts; i++) { ++ if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) { ++ if (fw_offset < 0 || parts[i].offset == fw_offset) ++ parts[i].name = "firmware"; ++ else ++ parts[i].name = "backup"; ++ } ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/mtd/parsers/ofpart_bcm4908.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __BCM4908_PARTITIONS_H ++#define __BCM4908_PARTITIONS_H ++ ++#ifdef CONFIG_MTD_OF_PARTS_BCM4908 ++int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); ++#else ++static inline int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, ++ int nr_parts) ++{ ++ return -EOPNOTSUPP; ++} ++#endif ++ ++#endif +--- a/drivers/mtd/parsers/ofpart.c ++++ /dev/null +@@ -1,236 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-or-later +-/* +- * Flash partitions described by the OF (or flattened) device tree +- * +- * Copyright © 2006 MontaVista Software Inc. +- * Author: Vitaly Wool +- * +- * Revised to handle newer style flash binding by: +- * Copyright © 2007 David Gibson, IBM Corporation. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-static bool node_has_compatible(struct device_node *pp) +-{ +- return of_get_property(pp, "compatible", NULL); +-} +- +-static int parse_fixed_partitions(struct mtd_info *master, +- const struct mtd_partition **pparts, +- struct mtd_part_parser_data *data) +-{ +- struct mtd_partition *parts; +- struct device_node *mtd_node; +- struct device_node *ofpart_node; +- const char *partname; +- struct device_node *pp; +- int nr_parts, i, ret = 0; +- bool dedicated = true; +- +- +- /* Pull of_node from the master device node */ +- mtd_node = mtd_get_of_node(master); +- if (!mtd_node) +- return 0; +- +- ofpart_node = of_get_child_by_name(mtd_node, "partitions"); +- if (!ofpart_node) { +- /* +- * We might get here even when ofpart isn't used at all (e.g., +- * when using another parser), so don't be louder than +- * KERN_DEBUG +- */ +- pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", +- master->name, mtd_node); +- ofpart_node = mtd_node; +- dedicated = false; +- } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) { +- /* The 'partitions' subnode might be used by another parser */ +- return 0; +- } +- +- /* First count the subnodes */ +- nr_parts = 0; +- for_each_child_of_node(ofpart_node, pp) { +- if (!dedicated && node_has_compatible(pp)) +- continue; +- +- nr_parts++; +- } +- +- if (nr_parts == 0) +- return 0; +- +- parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) +- return -ENOMEM; +- +- i = 0; +- for_each_child_of_node(ofpart_node, pp) { +- const __be32 *reg; +- int len; +- int a_cells, s_cells; +- +- if (!dedicated && node_has_compatible(pp)) +- continue; +- +- reg = of_get_property(pp, "reg", &len); +- if (!reg) { +- if (dedicated) { +- pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", +- master->name, pp, +- mtd_node); +- goto ofpart_fail; +- } else { +- nr_parts--; +- continue; +- } +- } +- +- a_cells = of_n_addr_cells(pp); +- s_cells = of_n_size_cells(pp); +- if (len / 4 != a_cells + s_cells) { +- pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", +- master->name, pp, +- mtd_node); +- goto ofpart_fail; +- } +- +- parts[i].offset = of_read_number(reg, a_cells); +- parts[i].size = of_read_number(reg + a_cells, s_cells); +- parts[i].of_node = pp; +- +- partname = of_get_property(pp, "label", &len); +- if (!partname) +- partname = of_get_property(pp, "name", &len); +- parts[i].name = partname; +- +- if (of_get_property(pp, "read-only", &len)) +- parts[i].mask_flags |= MTD_WRITEABLE; +- +- if (of_get_property(pp, "lock", &len)) +- parts[i].mask_flags |= MTD_POWERUP_LOCK; +- +- i++; +- } +- +- if (!nr_parts) +- goto ofpart_none; +- +- *pparts = parts; +- return nr_parts; +- +-ofpart_fail: +- pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", +- master->name, pp, mtd_node); +- ret = -EINVAL; +-ofpart_none: +- of_node_put(pp); +- kfree(parts); +- return ret; +-} +- +-static const struct of_device_id parse_ofpart_match_table[] = { +- { .compatible = "fixed-partitions" }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); +- +-static struct mtd_part_parser ofpart_parser = { +- .parse_fn = parse_fixed_partitions, +- .name = "fixed-partitions", +- .of_match_table = parse_ofpart_match_table, +-}; +- +-static int parse_ofoldpart_partitions(struct mtd_info *master, +- const struct mtd_partition **pparts, +- struct mtd_part_parser_data *data) +-{ +- struct mtd_partition *parts; +- struct device_node *dp; +- int i, plen, nr_parts; +- const struct { +- __be32 offset, len; +- } *part; +- const char *names; +- +- /* Pull of_node from the master device node */ +- dp = mtd_get_of_node(master); +- if (!dp) +- return 0; +- +- part = of_get_property(dp, "partitions", &plen); +- if (!part) +- return 0; /* No partitions found */ +- +- pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp); +- +- nr_parts = plen / sizeof(part[0]); +- +- parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); +- if (!parts) +- return -ENOMEM; +- +- names = of_get_property(dp, "partition-names", &plen); +- +- for (i = 0; i < nr_parts; i++) { +- parts[i].offset = be32_to_cpu(part->offset); +- parts[i].size = be32_to_cpu(part->len) & ~1; +- /* bit 0 set signifies read only partition */ +- if (be32_to_cpu(part->len) & 1) +- parts[i].mask_flags = MTD_WRITEABLE; +- +- if (names && (plen > 0)) { +- int len = strlen(names) + 1; +- +- parts[i].name = names; +- plen -= len; +- names += len; +- } else { +- parts[i].name = "unnamed"; +- } +- +- part++; +- } +- +- *pparts = parts; +- return nr_parts; +-} +- +-static struct mtd_part_parser ofoldpart_parser = { +- .parse_fn = parse_ofoldpart_partitions, +- .name = "ofoldpart", +-}; +- +-static int __init ofpart_parser_init(void) +-{ +- register_mtd_parser(&ofpart_parser); +- register_mtd_parser(&ofoldpart_parser); +- return 0; +-} +- +-static void __exit ofpart_parser_exit(void) +-{ +- deregister_mtd_parser(&ofpart_parser); +- deregister_mtd_parser(&ofoldpart_parser); +-} +- +-module_init(ofpart_parser_init); +-module_exit(ofpart_parser_exit); +- +-MODULE_LICENSE("GPL"); +-MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); +-MODULE_AUTHOR("Vitaly Wool, David Gibson"); +-/* +- * When MTD core cannot find the requested parser, it tries to load the module +- * with the same name. Since we provide the ofoldpart parser, we should have +- * the corresponding alias. +- */ +-MODULE_ALIAS("fixed-partitions"); +-MODULE_ALIAS("ofoldpart"); +--- /dev/null ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -0,0 +1,260 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Flash partitions described by the OF (or flattened) device tree ++ * ++ * Copyright © 2006 MontaVista Software Inc. ++ * Author: Vitaly Wool ++ * ++ * Revised to handle newer style flash binding by: ++ * Copyright © 2007 David Gibson, IBM Corporation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ofpart_bcm4908.h" ++ ++struct fixed_partitions_quirks { ++ int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); ++}; ++ ++struct fixed_partitions_quirks bcm4908_partitions_quirks = { ++ .post_parse = bcm4908_partitions_post_parse, ++}; ++ ++static const struct of_device_id parse_ofpart_match_table[]; ++ ++static bool node_has_compatible(struct device_node *pp) ++{ ++ return of_get_property(pp, "compatible", NULL); ++} ++ ++static int parse_fixed_partitions(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ const struct fixed_partitions_quirks *quirks; ++ const struct of_device_id *of_id; ++ struct mtd_partition *parts; ++ struct device_node *mtd_node; ++ struct device_node *ofpart_node; ++ const char *partname; ++ struct device_node *pp; ++ int nr_parts, i, ret = 0; ++ bool dedicated = true; ++ ++ /* Pull of_node from the master device node */ ++ mtd_node = mtd_get_of_node(master); ++ if (!mtd_node) ++ return 0; ++ ++ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); ++ if (!ofpart_node) { ++ /* ++ * We might get here even when ofpart isn't used at all (e.g., ++ * when using another parser), so don't be louder than ++ * KERN_DEBUG ++ */ ++ pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", ++ master->name, mtd_node); ++ ofpart_node = mtd_node; ++ dedicated = false; ++ } ++ ++ of_id = of_match_node(parse_ofpart_match_table, ofpart_node); ++ if (dedicated && !of_id) { ++ /* The 'partitions' subnode might be used by another parser */ ++ return 0; ++ } ++ ++ quirks = of_id ? of_id->data : NULL; ++ ++ /* First count the subnodes */ ++ nr_parts = 0; ++ for_each_child_of_node(ofpart_node, pp) { ++ if (!dedicated && node_has_compatible(pp)) ++ continue; ++ ++ nr_parts++; ++ } ++ ++ if (nr_parts == 0) ++ return 0; ++ ++ parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ i = 0; ++ for_each_child_of_node(ofpart_node, pp) { ++ const __be32 *reg; ++ int len; ++ int a_cells, s_cells; ++ ++ if (!dedicated && node_has_compatible(pp)) ++ continue; ++ ++ reg = of_get_property(pp, "reg", &len); ++ if (!reg) { ++ if (dedicated) { ++ pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", ++ master->name, pp, ++ mtd_node); ++ goto ofpart_fail; ++ } else { ++ nr_parts--; ++ continue; ++ } ++ } ++ ++ a_cells = of_n_addr_cells(pp); ++ s_cells = of_n_size_cells(pp); ++ if (len / 4 != a_cells + s_cells) { ++ pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", ++ master->name, pp, ++ mtd_node); ++ goto ofpart_fail; ++ } ++ ++ parts[i].offset = of_read_number(reg, a_cells); ++ parts[i].size = of_read_number(reg + a_cells, s_cells); ++ parts[i].of_node = pp; ++ ++ partname = of_get_property(pp, "label", &len); ++ if (!partname) ++ partname = of_get_property(pp, "name", &len); ++ parts[i].name = partname; ++ ++ if (of_get_property(pp, "read-only", &len)) ++ parts[i].mask_flags |= MTD_WRITEABLE; ++ ++ if (of_get_property(pp, "lock", &len)) ++ parts[i].mask_flags |= MTD_POWERUP_LOCK; ++ ++ i++; ++ } ++ ++ if (!nr_parts) ++ goto ofpart_none; ++ ++ if (quirks && quirks->post_parse) ++ quirks->post_parse(master, parts, nr_parts); ++ ++ *pparts = parts; ++ return nr_parts; ++ ++ofpart_fail: ++ pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", ++ master->name, pp, mtd_node); ++ ret = -EINVAL; ++ofpart_none: ++ of_node_put(pp); ++ kfree(parts); ++ return ret; ++} ++ ++static const struct of_device_id parse_ofpart_match_table[] = { ++ /* Generic */ ++ { .compatible = "fixed-partitions" }, ++ /* Customized */ ++ { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); ++ ++static struct mtd_part_parser ofpart_parser = { ++ .parse_fn = parse_fixed_partitions, ++ .name = "fixed-partitions", ++ .of_match_table = parse_ofpart_match_table, ++}; ++ ++static int parse_ofoldpart_partitions(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ struct device_node *dp; ++ int i, plen, nr_parts; ++ const struct { ++ __be32 offset, len; ++ } *part; ++ const char *names; ++ ++ /* Pull of_node from the master device node */ ++ dp = mtd_get_of_node(master); ++ if (!dp) ++ return 0; ++ ++ part = of_get_property(dp, "partitions", &plen); ++ if (!part) ++ return 0; /* No partitions found */ ++ ++ pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp); ++ ++ nr_parts = plen / sizeof(part[0]); ++ ++ parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ names = of_get_property(dp, "partition-names", &plen); ++ ++ for (i = 0; i < nr_parts; i++) { ++ parts[i].offset = be32_to_cpu(part->offset); ++ parts[i].size = be32_to_cpu(part->len) & ~1; ++ /* bit 0 set signifies read only partition */ ++ if (be32_to_cpu(part->len) & 1) ++ parts[i].mask_flags = MTD_WRITEABLE; ++ ++ if (names && (plen > 0)) { ++ int len = strlen(names) + 1; ++ ++ parts[i].name = names; ++ plen -= len; ++ names += len; ++ } else { ++ parts[i].name = "unnamed"; ++ } ++ ++ part++; ++ } ++ ++ *pparts = parts; ++ return nr_parts; ++} ++ ++static struct mtd_part_parser ofoldpart_parser = { ++ .parse_fn = parse_ofoldpart_partitions, ++ .name = "ofoldpart", ++}; ++ ++static int __init ofpart_parser_init(void) ++{ ++ register_mtd_parser(&ofpart_parser); ++ register_mtd_parser(&ofoldpart_parser); ++ return 0; ++} ++ ++static void __exit ofpart_parser_exit(void) ++{ ++ deregister_mtd_parser(&ofpart_parser); ++ deregister_mtd_parser(&ofoldpart_parser); ++} ++ ++module_init(ofpart_parser_init); ++module_exit(ofpart_parser_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); ++MODULE_AUTHOR("Vitaly Wool, David Gibson"); ++/* ++ * When MTD core cannot find the requested parser, it tries to load the module ++ * with the same name. Since we provide the ofoldpart parser, we should have ++ * the corresponding alias. ++ */ ++MODULE_ALIAS("fixed-partitions"); ++MODULE_ALIAS("ofoldpart"); diff --git a/ipq806x/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch b/ipq806x/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch new file mode 100644 index 0000000..35058ad --- /dev/null +++ b/ipq806x/backport-5.4/404-v5.13-mtd-parsers-ofpart-limit-parsing-of-deprecated-DT-sy.patch @@ -0,0 +1,69 @@ +From 2d751203aacf86a1b301a188d8551c7da91043ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 2 Mar 2021 20:00:12 +0100 +Subject: [PATCH] mtd: parsers: ofpart: limit parsing of deprecated DT syntax +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For backward compatibility ofpart still supports the old syntax like: +spi-flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x100000>; + }; +}; +(without "partitions" subnode). + +There is no reason however to support nested partitions without a clear +"compatible" string like: +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x100000>; + + partition@0 { + label = "config"; + reg = <0x80000 0x80000>; + }; + }; +}; +(we never officially supported or documented that). + +Make sure ofpart doesn't attempt to parse above. + +Cc: Ansuel Smith +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210302190012.1255-1-zajec5@gmail.com +--- + drivers/mtd/parsers/ofpart_core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -53,7 +53,7 @@ static int parse_fixed_partitions(struct + return 0; + + ofpart_node = of_get_child_by_name(mtd_node, "partitions"); +- if (!ofpart_node) { ++ if (!ofpart_node && !mtd_is_partition(master)) { + /* + * We might get here even when ofpart isn't used at all (e.g., + * when using another parser), so don't be louder than +@@ -64,6 +64,8 @@ static int parse_fixed_partitions(struct + ofpart_node = mtd_node; + dedicated = false; + } ++ if (!ofpart_node) ++ return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { diff --git a/ipq806x/backport-5.4/405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch b/ipq806x/backport-5.4/405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch new file mode 100644 index 0000000..f1b778a --- /dev/null +++ b/ipq806x/backport-5.4/405-v5.13-mtd-parsers-ofpart-make-symbol-bcm4908_partitions_qu.patch @@ -0,0 +1,34 @@ +From b87b6d2d6f540e29c3f98e1572d64e560d73d6c1 Mon Sep 17 00:00:00 2001 +From: Wei Yongjun +Date: Thu, 4 Mar 2021 06:46:00 +0000 +Subject: [PATCH] mtd: parsers: ofpart: make symbol 'bcm4908_partitions_quirks' + static + +The sparse tool complains as follows: + +drivers/mtd/parsers/ofpart_core.c:25:32: warning: + symbol 'bcm4908_partitions_quirks' was not declared. Should it be static? + +This symbol is not used outside of ofpart_core.c, so this +commit marks it static. + +Fixes: 457da931b608 ("mtd: parsers: ofpart: support BCM4908 fixed partitions") +Reported-by: Hulk Robot +Signed-off-by: Wei Yongjun +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210304064600.3279138-1-weiyongjun1@huawei.com +--- + drivers/mtd/parsers/ofpart_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -22,7 +22,7 @@ struct fixed_partitions_quirks { + int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); + }; + +-struct fixed_partitions_quirks bcm4908_partitions_quirks = { ++static struct fixed_partitions_quirks bcm4908_partitions_quirks = { + .post_parse = bcm4908_partitions_post_parse, + }; + diff --git a/ipq806x/backport-5.4/406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch b/ipq806x/backport-5.4/406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch new file mode 100644 index 0000000..ecea743 --- /dev/null +++ b/ipq806x/backport-5.4/406-v5.13-0001-mtd-core-add-nvmem-cells-compatible-to-parse-mtd-as-.patch @@ -0,0 +1,40 @@ +From 658c4448bbbf02a143abf1b89d09a3337ebd3ba6 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:19 +0100 +Subject: [PATCH] mtd: core: add nvmem-cells compatible to parse mtd as nvmem + cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Partitions that contains the nvmem-cells compatible will register +their direct subonodes as nvmem cells and the node will be treated as a +nvmem provider. + +Signed-off-by: Ansuel Smith +Tested-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-1-ansuelsmth@gmail.com +--- + drivers/mtd/mtdcore.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -559,6 +559,7 @@ static int mtd_nvmem_reg_read(void *priv + + static int mtd_nvmem_add(struct mtd_info *mtd) + { ++ struct device_node *node = mtd_get_of_node(mtd); + struct nvmem_config config = {}; + + config.id = -1; +@@ -571,7 +572,7 @@ static int mtd_nvmem_add(struct mtd_info + config.stride = 1; + config.read_only = true; + config.root_only = true; +- config.no_of_node = true; ++ config.no_of_node = !of_device_is_compatible(node, "nvmem-cells"); + config.priv = mtd; + + mtd->nvmem = nvmem_register(&config); diff --git a/ipq806x/backport-5.4/406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch b/ipq806x/backport-5.4/406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch new file mode 100644 index 0000000..c0515bd --- /dev/null +++ b/ipq806x/backport-5.4/406-v5.13-0002-dt-bindings-nvmem-drop-nodename-restriction.patch @@ -0,0 +1,28 @@ +From 52981a0fa9f7d68641e0e6bb584054c6d9eb2056 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:20 +0100 +Subject: [PATCH] dt-bindings: nvmem: drop $nodename restriction + +Drop $nodename restriction as now mtd partition can also be used as +nvmem provider. + +Signed-off-by: Ansuel Smith +Reviewed-by: Rob Herring +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-2-ansuelsmth@gmail.com +--- + Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 --- + 1 file changed, 3 deletions(-) + +--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml ++++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml +@@ -20,9 +20,6 @@ description: | + storage device. + + properties: +- $nodename: +- pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$" +- + "#address-cells": + const: 1 + diff --git a/ipq806x/backport-5.4/406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch b/ipq806x/backport-5.4/406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch new file mode 100644 index 0000000..552919f --- /dev/null +++ b/ipq806x/backport-5.4/406-v5.13-0003-dt-bindings-mtd-Document-use-of-nvmem-cells-compatib.patch @@ -0,0 +1,119 @@ +From ac42c46f983e4a9003a7bb91ad44a23ab7b8f534 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 12 Mar 2021 07:28:21 +0100 +Subject: [PATCH] dt-bindings: mtd: Document use of nvmem-cells compatible + +Document nvmem-cells compatible used to treat mtd partitions as a +nvmem provider. + +Signed-off-by: Ansuel Smith +Reviewed-by: Rob Herring +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210312062830.20548-3-ansuelsmth@gmail.com +--- + .../bindings/mtd/partitions/nvmem-cells.yaml | 99 +++++++++++++++++++ + 1 file changed, 99 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml +@@ -0,0 +1,99 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Nvmem cells ++ ++description: | ++ Any partition containing the compatible "nvmem-cells" will register as a ++ nvmem provider. ++ Each direct subnodes represents a nvmem cell following the nvmem binding. ++ Nvmem binding to declare nvmem-cells can be found in: ++ Documentation/devicetree/bindings/nvmem/nvmem.yaml ++ ++maintainers: ++ - Ansuel Smith ++ ++allOf: ++ - $ref: /schemas/nvmem/nvmem.yaml# ++ ++properties: ++ compatible: ++ const: nvmem-cells ++ ++required: ++ - compatible ++ ++additionalProperties: true ++ ++examples: ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ /* ... */ ++ ++ }; ++ art: art@1200000 { ++ compatible = "nvmem-cells"; ++ reg = <0x1200000 0x0140000>; ++ label = "art"; ++ read-only; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ macaddr_gmac1: macaddr_gmac1@0 { ++ reg = <0x0 0x6>; ++ }; ++ ++ macaddr_gmac2: macaddr_gmac2@6 { ++ reg = <0x6 0x6>; ++ }; ++ ++ pre_cal_24g: pre_cal_24g@1000 { ++ reg = <0x1000 0x2f20>; ++ }; ++ ++ pre_cal_5g: pre_cal_5g@5000{ ++ reg = <0x5000 0x2f20>; ++ }; ++ }; ++ - | ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bootloader"; ++ reg = <0x000000 0x100000>; ++ read-only; ++ }; ++ ++ firmware@100000 { ++ compatible = "brcm,trx"; ++ label = "firmware"; ++ reg = <0x100000 0xe00000>; ++ }; ++ ++ calibration@f00000 { ++ compatible = "nvmem-cells"; ++ label = "calibration"; ++ reg = <0xf00000 0x100000>; ++ ranges = <0 0xf00000 0x100000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ wifi0@0 { ++ reg = <0x000000 0x080000>; ++ }; ++ ++ wifi1@80000 { ++ reg = <0x080000 0x080000>; ++ }; ++ }; ++ }; diff --git a/ipq806x/backport-5.4/407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch b/ipq806x/backport-5.4/407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch new file mode 100644 index 0000000..35a4afd --- /dev/null +++ b/ipq806x/backport-5.4/407-v5.13-0001-dt-bindings-mtd-add-binding-for-Linksys-Northstar-pa.patch @@ -0,0 +1,98 @@ +From 2fa7294175c76e1ec568aa75c1891fd908728c8d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 12 Mar 2021 14:49:18 +0100 +Subject: [PATCH] dt-bindings: mtd: add binding for Linksys Northstar + partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Linksys on Broadcom Northstar devices uses fixed flash layout with +multiple firmware partitions. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Rob Herring +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210312134919.7767-1-zajec5@gmail.com +--- + .../mtd/partitions/linksys,ns-partitions.yaml | 74 +++++++++++++++++++ + 1 file changed, 74 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/partitions/linksys,ns-partitions.yaml +@@ -0,0 +1,74 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/partitions/linksys,ns-partitions.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Linksys Northstar partitioning ++ ++description: | ++ Linksys devices based on Broadcom Northstar architecture often use two ++ firmware partitions. One is used for regular booting, the other is treated as ++ fallback. ++ ++ This binding allows defining all fixed partitions and marking those containing ++ firmware. System can use that information e.g. for booting or flashing ++ purposes. ++ ++maintainers: ++ - Rafał Miłecki ++ ++properties: ++ compatible: ++ const: linksys,ns-partitions ++ ++ "#address-cells": ++ enum: [ 1, 2 ] ++ ++ "#size-cells": ++ enum: [ 1, 2 ] ++ ++patternProperties: ++ "^partition@[0-9a-f]+$": ++ $ref: "partition.yaml#" ++ properties: ++ compatible: ++ items: ++ - const: linksys,ns-firmware ++ - const: brcm,trx ++ unevaluatedProperties: false ++ ++required: ++ - "#address-cells" ++ - "#size-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ partitions { ++ compatible = "linksys,ns-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "boot"; ++ reg = <0x0 0x100000>; ++ read-only; ++ }; ++ ++ partition@100000 { ++ label = "nvram"; ++ reg = <0x100000 0x100000>; ++ }; ++ ++ partition@200000 { ++ compatible = "linksys,ns-firmware", "brcm,trx"; ++ reg = <0x200000 0xf00000>; ++ }; ++ ++ partition@1100000 { ++ compatible = "linksys,ns-firmware", "brcm,trx"; ++ reg = <0x1100000 0xf00000>; ++ }; ++ }; diff --git a/ipq806x/backport-5.4/407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch b/ipq806x/backport-5.4/407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch new file mode 100644 index 0000000..75eb939 --- /dev/null +++ b/ipq806x/backport-5.4/407-v5.13-0002-mtd-parsers-ofpart-support-Linksys-Northstar-partiti.patch @@ -0,0 +1,156 @@ +From 7134a2d026d942210b4d26d6059c9d979ca7866e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 12 Mar 2021 14:49:19 +0100 +Subject: [PATCH] mtd: parsers: ofpart: support Linksys Northstar partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows extending ofpart parser with support for Linksys Northstar +devices. That support uses recently added quirks mechanism. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210312134919.7767-2-zajec5@gmail.com +--- + drivers/mtd/parsers/Kconfig | 10 +++++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/ofpart_core.c | 6 +++ + drivers/mtd/parsers/ofpart_linksys_ns.c | 50 +++++++++++++++++++++++++ + drivers/mtd/parsers/ofpart_linksys_ns.h | 18 +++++++++ + 5 files changed, 85 insertions(+) + create mode 100644 drivers/mtd/parsers/ofpart_linksys_ns.c + create mode 100644 drivers/mtd/parsers/ofpart_linksys_ns.h + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -76,6 +76,16 @@ config MTD_OF_PARTS_BCM4908 + that can have multiple "firmware" partitions. It takes care of + finding currently used one and backup ones. + ++config MTD_OF_PARTS_LINKSYS_NS ++ bool "Linksys Northstar partitioning support" ++ depends on MTD_OF_PARTS && (ARCH_BCM_5301X || ARCH_BCM4908 || COMPILE_TEST) ++ default ARCH_BCM_5301X ++ help ++ This provides partitions parser for Linksys devices based on Broadcom ++ Northstar architecture. Linksys commonly uses fixed flash layout with ++ two "firmware" partitions. Currently used firmware has to be detected ++ using CFE environment variable. ++ + config MTD_PARSER_IMAGETAG + tristate "Parser for BCM963XX Image Tag format partitions" + depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -6,6 +6,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdl + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + ofpart-y += ofpart_core.o + ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o ++ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o + obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o + obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -17,6 +17,7 @@ + #include + + #include "ofpart_bcm4908.h" ++#include "ofpart_linksys_ns.h" + + struct fixed_partitions_quirks { + int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts); +@@ -26,6 +27,10 @@ static struct fixed_partitions_quirks bc + .post_parse = bcm4908_partitions_post_parse, + }; + ++static struct fixed_partitions_quirks linksys_ns_partitions_quirks = { ++ .post_parse = linksys_ns_partitions_post_parse, ++}; ++ + static const struct of_device_id parse_ofpart_match_table[]; + + static bool node_has_compatible(struct device_node *pp) +@@ -164,6 +169,7 @@ static const struct of_device_id parse_o + { .compatible = "fixed-partitions" }, + /* Customized */ + { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, }, ++ { .compatible = "linksys,ns-partitions", .data = &linksys_ns_partitions_quirks, }, + {}, + }; + MODULE_DEVICE_TABLE(of, parse_ofpart_match_table); +--- /dev/null ++++ b/drivers/mtd/parsers/ofpart_linksys_ns.c +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2021 Rafał Miłecki ++ */ ++ ++#include ++#include ++#include ++ ++#include "ofpart_linksys_ns.h" ++ ++#define NVRAM_BOOT_PART "bootpartition" ++ ++static int ofpart_linksys_ns_bootpartition(void) ++{ ++ char buf[4]; ++ int bootpartition; ++ ++ /* Check CFE environment variable */ ++ if (bcm47xx_nvram_getenv(NVRAM_BOOT_PART, buf, sizeof(buf)) > 0) { ++ if (!kstrtoint(buf, 0, &bootpartition)) ++ return bootpartition; ++ pr_warn("Failed to parse %s value \"%s\"\n", NVRAM_BOOT_PART, ++ buf); ++ } else { ++ pr_warn("Failed to get NVRAM \"%s\"\n", NVRAM_BOOT_PART); ++ } ++ ++ return 0; ++} ++ ++int linksys_ns_partitions_post_parse(struct mtd_info *mtd, ++ struct mtd_partition *parts, ++ int nr_parts) ++{ ++ int bootpartition = ofpart_linksys_ns_bootpartition(); ++ int trx_idx = 0; ++ int i; ++ ++ for (i = 0; i < nr_parts; i++) { ++ if (of_device_is_compatible(parts[i].of_node, "linksys,ns-firmware")) { ++ if (trx_idx++ == bootpartition) ++ parts[i].name = "firmware"; ++ else ++ parts[i].name = "backup"; ++ } ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/mtd/parsers/ofpart_linksys_ns.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __OFPART_LINKSYS_NS_H ++#define __OFPART_LINKSYS_NS_H ++ ++#ifdef CONFIG_MTD_OF_PARTS_LINKSYS_NS ++int linksys_ns_partitions_post_parse(struct mtd_info *mtd, ++ struct mtd_partition *parts, ++ int nr_parts); ++#else ++static inline int linksys_ns_partitions_post_parse(struct mtd_info *mtd, ++ struct mtd_partition *parts, ++ int nr_parts) ++{ ++ return -EOPNOTSUPP; ++} ++#endif ++ ++#endif diff --git a/ipq806x/backport-5.4/410-mtd-fix-calculating-partition-end-address.patch b/ipq806x/backport-5.4/410-mtd-fix-calculating-partition-end-address.patch new file mode 100644 index 0000000..1eae015 --- /dev/null +++ b/ipq806x/backport-5.4/410-mtd-fix-calculating-partition-end-address.patch @@ -0,0 +1,28 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 9 Mar 2020 08:30:19 +0100 +Subject: [PATCH] mtd: fix calculating partition end address +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes check for partitions that don't start at beginning of their +parents. Missing partition's offset in formula could result in forcing +read-only incorrectly. + +Fixes: 6750f61a13a0 ("mtd: improve calculating partition boundaries when checking for alignment") +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/mtdpart.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -524,7 +524,7 @@ static struct mtd_part *allocate_partiti + part->name); + } + +- tmp = part_absolute_offset(parent) + slave->mtd.size; ++ tmp = part_absolute_offset(parent) + slave->offset + slave->mtd.size; + remainder = do_div(tmp, wr_alignment); + if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) { + slave->mtd.flags &= ~MTD_WRITEABLE; diff --git a/ipq806x/backport-5.4/600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch b/ipq806x/backport-5.4/600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch new file mode 100644 index 0000000..961140a --- /dev/null +++ b/ipq806x/backport-5.4/600-v5.12-net-extract-napi-poll-functionality-to-__napi_poll.patch @@ -0,0 +1,88 @@ +From: Felix Fietkau +Date: Mon, 8 Feb 2021 11:34:08 -0800 +Subject: [PATCH] net: extract napi poll functionality to __napi_poll() + +This commit introduces a new function __napi_poll() which does the main +logic of the existing napi_poll() function, and will be called by other +functions in later commits. +This idea and implementation is done by Felix Fietkau and +is proposed as part of the patch to move napi work to work_queue +context. +This commit by itself is a code restructure. + +Signed-off-by: Felix Fietkau +Signed-off-by: Wei Wang +Reviewed-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6322,15 +6322,10 @@ void netif_napi_del(struct napi_struct * + } + EXPORT_SYMBOL(netif_napi_del); + +-static int napi_poll(struct napi_struct *n, struct list_head *repoll) ++static int __napi_poll(struct napi_struct *n, bool *repoll) + { +- void *have; + int work, weight; + +- list_del_init(&n->poll_list); +- +- have = netpoll_poll_lock(n); +- + weight = n->weight; + + /* This NAPI_STATE_SCHED test is for avoiding a race +@@ -6348,7 +6343,7 @@ static int napi_poll(struct napi_struct + WARN_ON_ONCE(work > weight); + + if (likely(work < weight)) +- goto out_unlock; ++ return work; + + /* Drivers must not modify the NAPI state if they + * consume the entire weight. In such cases this code +@@ -6357,7 +6352,7 @@ static int napi_poll(struct napi_struct + */ + if (unlikely(napi_disable_pending(n))) { + napi_complete(n); +- goto out_unlock; ++ return work; + } + + if (n->gro_bitmask) { +@@ -6375,12 +6370,29 @@ static int napi_poll(struct napi_struct + if (unlikely(!list_empty(&n->poll_list))) { + pr_warn_once("%s: Budget exhausted after napi rescheduled\n", + n->dev ? n->dev->name : "backlog"); +- goto out_unlock; ++ return work; + } + +- list_add_tail(&n->poll_list, repoll); ++ *repoll = true; ++ ++ return work; ++} ++ ++static int napi_poll(struct napi_struct *n, struct list_head *repoll) ++{ ++ bool do_repoll = false; ++ void *have; ++ int work; ++ ++ list_del_init(&n->poll_list); ++ ++ have = netpoll_poll_lock(n); ++ ++ work = __napi_poll(n, &do_repoll); ++ ++ if (do_repoll) ++ list_add_tail(&n->poll_list, repoll); + +-out_unlock: + netpoll_poll_unlock(have); + + return work; diff --git a/ipq806x/backport-5.4/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch b/ipq806x/backport-5.4/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch new file mode 100644 index 0000000..c9bd4ab --- /dev/null +++ b/ipq806x/backport-5.4/601-v5.12-net-implement-threaded-able-napi-poll-loop-support.patch @@ -0,0 +1,261 @@ +From: Wei Wang +Date: Mon, 8 Feb 2021 11:34:09 -0800 +Subject: [PATCH] net: implement threaded-able napi poll loop support + +This patch allows running each napi poll loop inside its own +kernel thread. +The kthread is created during netif_napi_add() if dev->threaded +is set. And threaded mode is enabled in napi_enable(). We will +provide a way to set dev->threaded and enable threaded mode +without a device up/down in the following patch. + +Once that threaded mode is enabled and the kthread is +started, napi_schedule() will wake-up such thread instead +of scheduling the softirq. + +The threaded poll loop behaves quite likely the net_rx_action, +but it does not have to manipulate local irqs and uses +an explicit scheduling point based on netdev_budget. + +Co-developed-by: Paolo Abeni +Signed-off-by: Paolo Abeni +Co-developed-by: Hannes Frederic Sowa +Signed-off-by: Hannes Frederic Sowa +Co-developed-by: Jakub Kicinski +Signed-off-by: Jakub Kicinski +Signed-off-by: Wei Wang +Reviewed-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -340,6 +340,7 @@ struct napi_struct { + struct list_head dev_list; + struct hlist_node napi_hash_node; + unsigned int napi_id; ++ struct task_struct *thread; + }; + + enum { +@@ -350,6 +351,7 @@ enum { + NAPI_STATE_HASHED, /* In NAPI hash (busy polling possible) */ + NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */ + NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */ ++ NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/ + }; + + enum { +@@ -360,6 +362,7 @@ enum { + NAPIF_STATE_HASHED = BIT(NAPI_STATE_HASHED), + NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL), + NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL), ++ NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED), + }; + + enum gro_result { +@@ -504,20 +507,7 @@ bool napi_hash_del(struct napi_struct *n + */ + void napi_disable(struct napi_struct *n); + +-/** +- * napi_enable - enable NAPI scheduling +- * @n: NAPI context +- * +- * Resume NAPI from being scheduled on this context. +- * Must be paired with napi_disable. +- */ +-static inline void napi_enable(struct napi_struct *n) +-{ +- BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); +- smp_mb__before_atomic(); +- clear_bit(NAPI_STATE_SCHED, &n->state); +- clear_bit(NAPI_STATE_NPSVC, &n->state); +-} ++void napi_enable(struct napi_struct *n); + + /** + * napi_synchronize - wait until NAPI is not running +@@ -1783,6 +1773,8 @@ enum netdev_ml_priv_type { + * + * @wol_enabled: Wake-on-LAN is enabled + * ++ * @threaded: napi threaded mode is enabled ++ * + * FIXME: cleanup struct net_device such that network protocol info + * moves out. + */ +@@ -2075,6 +2067,7 @@ struct net_device { + struct lock_class_key addr_list_lock_key; + bool proto_down; + unsigned wol_enabled:1; ++ unsigned threaded:1; + }; + #define to_net_dev(d) container_of(d, struct net_device, dev) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -91,6 +91,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1289,6 +1290,27 @@ void netdev_notify_peers(struct net_devi + } + EXPORT_SYMBOL(netdev_notify_peers); + ++static int napi_threaded_poll(void *data); ++ ++static int napi_kthread_create(struct napi_struct *n) ++{ ++ int err = 0; ++ ++ /* Create and wake up the kthread once to put it in ++ * TASK_INTERRUPTIBLE mode to avoid the blocked task ++ * warning and work with loadavg. ++ */ ++ n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d", ++ n->dev->name, n->napi_id); ++ if (IS_ERR(n->thread)) { ++ err = PTR_ERR(n->thread); ++ pr_err("kthread_run failed with err %d\n", err); ++ n->thread = NULL; ++ } ++ ++ return err; ++} ++ + static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack) + { + const struct net_device_ops *ops = dev->netdev_ops; +@@ -3885,6 +3907,21 @@ int gro_normal_batch __read_mostly = 8; + static inline void ____napi_schedule(struct softnet_data *sd, + struct napi_struct *napi) + { ++ struct task_struct *thread; ++ ++ if (test_bit(NAPI_STATE_THREADED, &napi->state)) { ++ /* Paired with smp_mb__before_atomic() in ++ * napi_enable(). Use READ_ONCE() to guarantee ++ * a complete read on napi->thread. Only call ++ * wake_up_process() when it's not NULL. ++ */ ++ thread = READ_ONCE(napi->thread); ++ if (thread) { ++ wake_up_process(thread); ++ return; ++ } ++ } ++ + list_add_tail(&napi->poll_list, &sd->poll_list); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); + } +@@ -6276,6 +6313,12 @@ void netif_napi_add(struct net_device *d + set_bit(NAPI_STATE_NPSVC, &napi->state); + list_add_rcu(&napi->dev_list, &dev->napi_list); + napi_hash_add(napi); ++ /* Create kthread for this napi if dev->threaded is set. ++ * Clear dev->threaded if kthread creation failed so that ++ * threaded mode will not be enabled in napi_enable(). ++ */ ++ if (dev->threaded && napi_kthread_create(napi)) ++ dev->threaded = 0; + } + EXPORT_SYMBOL(netif_napi_add); + +@@ -6292,9 +6335,28 @@ void napi_disable(struct napi_struct *n) + hrtimer_cancel(&n->timer); + + clear_bit(NAPI_STATE_DISABLE, &n->state); ++ clear_bit(NAPI_STATE_THREADED, &n->state); + } + EXPORT_SYMBOL(napi_disable); + ++/** ++ * napi_enable - enable NAPI scheduling ++ * @n: NAPI context ++ * ++ * Resume NAPI from being scheduled on this context. ++ * Must be paired with napi_disable. ++ */ ++void napi_enable(struct napi_struct *n) ++{ ++ BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); ++ smp_mb__before_atomic(); ++ clear_bit(NAPI_STATE_SCHED, &n->state); ++ clear_bit(NAPI_STATE_NPSVC, &n->state); ++ if (n->dev->threaded && n->thread) ++ set_bit(NAPI_STATE_THREADED, &n->state); ++} ++EXPORT_SYMBOL(napi_enable); ++ + static void flush_gro_hash(struct napi_struct *napi) + { + int i; +@@ -6319,6 +6381,11 @@ void netif_napi_del(struct napi_struct * + + flush_gro_hash(napi); + napi->gro_bitmask = 0; ++ ++ if (napi->thread) { ++ kthread_stop(napi->thread); ++ napi->thread = NULL; ++ } + } + EXPORT_SYMBOL(netif_napi_del); + +@@ -6398,6 +6465,51 @@ static int napi_poll(struct napi_struct + return work; + } + ++static int napi_thread_wait(struct napi_struct *napi) ++{ ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ while (!kthread_should_stop() && !napi_disable_pending(napi)) { ++ if (test_bit(NAPI_STATE_SCHED, &napi->state)) { ++ WARN_ON(!list_empty(&napi->poll_list)); ++ __set_current_state(TASK_RUNNING); ++ return 0; ++ } ++ ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++ __set_current_state(TASK_RUNNING); ++ return -1; ++} ++ ++static int napi_threaded_poll(void *data) ++{ ++ struct napi_struct *napi = data; ++ void *have; ++ ++ while (!napi_thread_wait(napi)) { ++ for (;;) { ++ bool repoll = false; ++ ++ local_bh_disable(); ++ ++ have = netpoll_poll_lock(napi); ++ __napi_poll(napi, &repoll); ++ netpoll_poll_unlock(have); ++ ++ __kfree_skb_flush(); ++ local_bh_enable(); ++ ++ if (!repoll) ++ break; ++ ++ cond_resched(); ++ } ++ } ++ return 0; ++} ++ + static __latent_entropy void net_rx_action(struct softirq_action *h) + { + struct softnet_data *sd = this_cpu_ptr(&softnet_data); diff --git a/ipq806x/backport-5.4/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch b/ipq806x/backport-5.4/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch new file mode 100644 index 0000000..d8b9329 --- /dev/null +++ b/ipq806x/backport-5.4/602-v5.12-net-add-sysfs-attribute-to-control-napi-threaded-mod.patch @@ -0,0 +1,177 @@ +From: Wei Wang +Date: Mon, 8 Feb 2021 11:34:10 -0800 +Subject: [PATCH] net: add sysfs attribute to control napi threaded mode + +This patch adds a new sysfs attribute to the network device class. +Said attribute provides a per-device control to enable/disable the +threaded mode for all the napi instances of the given network device, +without the need for a device up/down. +User sets it to 1 or 0 to enable or disable threaded mode. +Note: when switching between threaded and the current softirq based mode +for a napi instance, it will not immediately take effect if the napi is +currently being polled. The mode switch will happen for the next time +napi_schedule() is called. + +Co-developed-by: Paolo Abeni +Signed-off-by: Paolo Abeni +Co-developed-by: Hannes Frederic Sowa +Signed-off-by: Hannes Frederic Sowa +Co-developed-by: Felix Fietkau +Signed-off-by: Felix Fietkau +Signed-off-by: Wei Wang +Reviewed-by: Alexander Duyck +Signed-off-by: David S. Miller +--- + +--- a/Documentation/ABI/testing/sysfs-class-net ++++ b/Documentation/ABI/testing/sysfs-class-net +@@ -301,3 +301,18 @@ Contact: netdev@vger.kernel.org + Description: + 32-bit unsigned integer counting the number of times the link has + been down ++ ++What: /sys/class/net//threaded ++Date: Jan 2021 ++KernelVersion: 5.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Boolean value to control the threaded mode per device. User could ++ set this value to enable/disable threaded mode for all napi ++ belonging to this device, without the need to do device up/down. ++ ++ Possible values: ++ == ================================== ++ 0 threaded mode disabled for this dev ++ 1 threaded mode enabled for this dev ++ == ================================== +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -498,6 +498,8 @@ static inline bool napi_complete(struct + */ + bool napi_hash_del(struct napi_struct *napi); + ++int dev_set_threaded(struct net_device *dev, bool threaded); ++ + /** + * napi_disable - prevent NAPI from scheduling + * @n: NAPI context +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3911,8 +3911,9 @@ static inline void ____napi_schedule(str + + if (test_bit(NAPI_STATE_THREADED, &napi->state)) { + /* Paired with smp_mb__before_atomic() in +- * napi_enable(). Use READ_ONCE() to guarantee +- * a complete read on napi->thread. Only call ++ * napi_enable()/dev_set_threaded(). ++ * Use READ_ONCE() to guarantee a complete ++ * read on napi->thread. Only call + * wake_up_process() when it's not NULL. + */ + thread = READ_ONCE(napi->thread); +@@ -6290,6 +6291,49 @@ static void init_gro_hash(struct napi_st + napi->gro_bitmask = 0; + } + ++int dev_set_threaded(struct net_device *dev, bool threaded) ++{ ++ struct napi_struct *napi; ++ int err = 0; ++ ++ if (dev->threaded == threaded) ++ return 0; ++ ++ if (threaded) { ++ list_for_each_entry(napi, &dev->napi_list, dev_list) { ++ if (!napi->thread) { ++ err = napi_kthread_create(napi); ++ if (err) { ++ threaded = false; ++ break; ++ } ++ } ++ } ++ } ++ ++ dev->threaded = threaded; ++ ++ /* Make sure kthread is created before THREADED bit ++ * is set. ++ */ ++ smp_mb__before_atomic(); ++ ++ /* Setting/unsetting threaded mode on a napi might not immediately ++ * take effect, if the current napi instance is actively being ++ * polled. In this case, the switch between threaded mode and ++ * softirq mode will happen in the next round of napi_schedule(). ++ * This should not cause hiccups/stalls to the live traffic. ++ */ ++ list_for_each_entry(napi, &dev->napi_list, dev_list) { ++ if (threaded) ++ set_bit(NAPI_STATE_THREADED, &napi->state); ++ else ++ clear_bit(NAPI_STATE_THREADED, &napi->state); ++ } ++ ++ return err; ++} ++ + void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), int weight) + { +--- a/net/core/net-sysfs.c ++++ b/net/core/net-sysfs.c +@@ -557,6 +557,45 @@ static ssize_t phys_switch_id_show(struc + } + static DEVICE_ATTR_RO(phys_switch_id); + ++static ssize_t threaded_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct net_device *netdev = to_net_dev(dev); ++ ssize_t ret = -EINVAL; ++ ++ if (!rtnl_trylock()) ++ return restart_syscall(); ++ ++ if (dev_isalive(netdev)) ++ ret = sprintf(buf, fmt_dec, netdev->threaded); ++ ++ rtnl_unlock(); ++ return ret; ++} ++ ++static int modify_napi_threaded(struct net_device *dev, unsigned long val) ++{ ++ int ret; ++ ++ if (list_empty(&dev->napi_list)) ++ return -EOPNOTSUPP; ++ ++ if (val != 0 && val != 1) ++ return -EOPNOTSUPP; ++ ++ ret = dev_set_threaded(dev, val); ++ ++ return ret; ++} ++ ++static ssize_t threaded_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ return netdev_store(dev, attr, buf, len, modify_napi_threaded); ++} ++static DEVICE_ATTR_RW(threaded); ++ + static struct attribute *net_class_attrs[] __ro_after_init = { + &dev_attr_netdev_group.attr, + &dev_attr_type.attr, +@@ -587,6 +626,7 @@ static struct attribute *net_class_attrs + &dev_attr_proto_down.attr, + &dev_attr_carrier_up_count.attr, + &dev_attr_carrier_down_count.attr, ++ &dev_attr_threaded.attr, + NULL, + }; + ATTRIBUTE_GROUPS(net_class); diff --git a/ipq806x/backport-5.4/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch b/ipq806x/backport-5.4/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch new file mode 100644 index 0000000..19c5a53 --- /dev/null +++ b/ipq806x/backport-5.4/603-v5.12-net-fix-race-between-napi-kthread-mode-and-busy-poll.patch @@ -0,0 +1,93 @@ +From: Wei Wang +Date: Mon, 1 Mar 2021 17:21:13 -0800 +Subject: [PATCH] net: fix race between napi kthread mode and busy poll + +Currently, napi_thread_wait() checks for NAPI_STATE_SCHED bit to +determine if the kthread owns this napi and could call napi->poll() on +it. However, if socket busy poll is enabled, it is possible that the +busy poll thread grabs this SCHED bit (after the previous napi->poll() +invokes napi_complete_done() and clears SCHED bit) and tries to poll +on the same napi. napi_disable() could grab the SCHED bit as well. +This patch tries to fix this race by adding a new bit +NAPI_STATE_SCHED_THREADED in napi->state. This bit gets set in +____napi_schedule() if the threaded mode is enabled, and gets cleared +in napi_complete_done(), and we only poll the napi in kthread if this +bit is set. This helps distinguish the ownership of the napi between +kthread and other scenarios and fixes the race issue. + +Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") +Reported-by: Martin Zaharinov +Suggested-by: Jakub Kicinski +Signed-off-by: Wei Wang +Cc: Alexander Duyck +Cc: Eric Dumazet +Cc: Paolo Abeni +Cc: Hannes Frederic Sowa +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -352,6 +352,7 @@ enum { + NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */ + NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */ + NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/ ++ NAPI_STATE_SCHED_THREADED, /* Napi is currently scheduled in threaded mode */ + }; + + enum { +@@ -363,6 +364,7 @@ enum { + NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL), + NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL), + NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED), ++ NAPIF_STATE_SCHED_THREADED = BIT(NAPI_STATE_SCHED_THREADED), + }; + + enum gro_result { +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3918,6 +3918,8 @@ static inline void ____napi_schedule(str + */ + thread = READ_ONCE(napi->thread); + if (thread) { ++ if (thread->state != TASK_INTERRUPTIBLE) ++ set_bit(NAPI_STATE_SCHED_THREADED, &napi->state); + wake_up_process(thread); + return; + } +@@ -6078,7 +6080,8 @@ bool napi_complete_done(struct napi_stru + + WARN_ON_ONCE(!(val & NAPIF_STATE_SCHED)); + +- new = val & ~(NAPIF_STATE_MISSED | NAPIF_STATE_SCHED); ++ new = val & ~(NAPIF_STATE_MISSED | NAPIF_STATE_SCHED | ++ NAPIF_STATE_SCHED_THREADED); + + /* If STATE_MISSED was set, leave STATE_SCHED set, + * because we will call napi->poll() one more time. +@@ -6511,16 +6514,25 @@ static int napi_poll(struct napi_struct + + static int napi_thread_wait(struct napi_struct *napi) + { ++ bool woken = false; ++ + set_current_state(TASK_INTERRUPTIBLE); + + while (!kthread_should_stop() && !napi_disable_pending(napi)) { +- if (test_bit(NAPI_STATE_SCHED, &napi->state)) { ++ /* Testing SCHED_THREADED bit here to make sure the current ++ * kthread owns this napi and could poll on this napi. ++ * Testing SCHED bit is not enough because SCHED bit might be ++ * set by some other busy poll thread or by napi_disable(). ++ */ ++ if (test_bit(NAPI_STATE_SCHED_THREADED, &napi->state) || woken) { + WARN_ON(!list_empty(&napi->poll_list)); + __set_current_state(TASK_RUNNING); + return 0; + } + + schedule(); ++ /* woken being true indicates this thread owns this napi. */ ++ woken = true; + set_current_state(TASK_INTERRUPTIBLE); + } + __set_current_state(TASK_RUNNING); diff --git a/ipq806x/backport-5.4/604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch b/ipq806x/backport-5.4/604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch new file mode 100644 index 0000000..108cf80 --- /dev/null +++ b/ipq806x/backport-5.4/604-v5.12-net-fix-hangup-on-napi_disable-for-threaded-napi.patch @@ -0,0 +1,53 @@ +From: Paolo Abeni +Date: Fri, 9 Apr 2021 17:24:17 +0200 +Subject: [PATCH] net: fix hangup on napi_disable for threaded napi + +napi_disable() is subject to an hangup, when the threaded +mode is enabled and the napi is under heavy traffic. + +If the relevant napi has been scheduled and the napi_disable() +kicks in before the next napi_threaded_wait() completes - so +that the latter quits due to the napi_disable_pending() condition, +the existing code leaves the NAPI_STATE_SCHED bit set and the +napi_disable() loop waiting for such bit will hang. + +This patch addresses the issue by dropping the NAPI_STATE_DISABLE +bit test in napi_thread_wait(). The later napi_threaded_poll() +iteration will take care of clearing the NAPI_STATE_SCHED. + +This also addresses a related problem reported by Jakub: +before this patch a napi_disable()/napi_enable() pair killed +the napi thread, effectively disabling the threaded mode. +On the patched kernel napi_disable() simply stops scheduling +the relevant thread. + +v1 -> v2: + - let the main napi_thread_poll() loop clear the SCHED bit + +Reported-by: Jakub Kicinski +Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") +Signed-off-by: Paolo Abeni +Reviewed-by: Eric Dumazet +Link: https://lore.kernel.org/r/883923fa22745a9589e8610962b7dc59df09fb1f.1617981844.git.pabeni@redhat.com +Signed-off-by: Jakub Kicinski +--- + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6518,7 +6518,7 @@ static int napi_thread_wait(struct napi_ + + set_current_state(TASK_INTERRUPTIBLE); + +- while (!kthread_should_stop() && !napi_disable_pending(napi)) { ++ while (!kthread_should_stop()) { + /* Testing SCHED_THREADED bit here to make sure the current + * kthread owns this napi and could poll on this napi. + * Testing SCHED bit is not enough because SCHED bit might be +@@ -6536,6 +6536,7 @@ static int napi_thread_wait(struct napi_ + set_current_state(TASK_INTERRUPTIBLE); + } + __set_current_state(TASK_RUNNING); ++ + return -1; + } + diff --git a/ipq806x/backport-5.4/700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch b/ipq806x/backport-5.4/700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch new file mode 100644 index 0000000..13f0d9d --- /dev/null +++ b/ipq806x/backport-5.4/700-v5.5-net-core-allow-fast-GRO-for-skbs-with-Ethernet-heade.patch @@ -0,0 +1,78 @@ +From: Alexander Lobakin +Date: Fri, 15 Nov 2019 12:11:35 +0300 +Subject: [PATCH] net: core: allow fast GRO for skbs with Ethernet header in + head + +Commit 78d3fd0b7de8 ("gro: Only use skb_gro_header for completely +non-linear packets") back in May'09 (v2.6.31-rc1) has changed the +original condition '!skb_headlen(skb)' to +'skb->mac_header == skb->tail' in gro_reset_offset() saying: "Since +the drivers that need this optimisation all provide completely +non-linear packets" (note that this condition has become the current +'skb_mac_header(skb) == skb_tail_pointer(skb)' later with commmit +ced14f6804a9 ("net: Correct comparisons and calculations using +skb->tail and skb-transport_header") without any functional changes). + +For now, we have the following rough statistics for v5.4-rc7: +1) napi_gro_frags: 14 +2) napi_gro_receive with skb->head containing (most of) payload: 83 +3) napi_gro_receive with skb->head containing all the headers: 20 +4) napi_gro_receive with skb->head containing only Ethernet header: 2 + +With the current condition, fast GRO with the usage of +NAPI_GRO_CB(skb)->frag0 is available only in the [1] case. +Packets pushed by [2] and [3] go through the 'slow' path, but +it's not a problem for them as they already contain all the needed +headers in skb->head, so pskb_may_pull() only moves skb->data. + +The layout of skbs in the fourth [4] case at the moment of +dev_gro_receive() is identical to skbs that have come through [1], +as napi_frags_skb() pulls Ethernet header to skb->head. The only +difference is that the mentioned condition is always false for them, +because skb_put() and friends irreversibly alter the tail pointer. +They also go through the 'slow' path, but now every single +pskb_may_pull() in every single .gro_receive() will call the *really* +slow __pskb_pull_tail() to pull headers to head. This significantly +decreases the overall performance for no visible reasons. + +The only two users of method [4] is: +* drivers/staging/qlge +* drivers/net/wireless/iwlwifi (all three variants: dvm, mvm, mvm-mq) + +Note that in case with wireless drivers we can't use [1] +(napi_gro_frags()) at least for now and mac80211 stack always +performs pushes and pulls anyways, so performance hit is inavoidable. + +At the moment of v2.6.31 the mentioned change was necessary (that's +why I don't add the "Fixes:" tag), but it became obsolete since +skb_gro_mac_header() has gone in commit a50e233c50db ("net-gro: +restore frag0 optimization"), so we can simply revert the condition +in gro_reset_offset() to allow skbs from [4] go through the 'fast' +path just like in case [1]. + +This was tested on a 600 MHz MIPS CPU and a custom driver and this +patch gave boosts up to 40 Mbps to method [4] in both directions +comparing to net-next, which made overall performance relatively +close to [1] (without it, [4] is the slowest). + +v2: +- Add more references and explanations to commit message +- Fix some typos ibid +- No functional changes + +Signed-off-by: Alexander Lobakin +Signed-off-by: David S. Miller +--- + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -5429,8 +5429,7 @@ static inline void skb_gro_reset_offset( + NAPI_GRO_CB(skb)->frag0 = NULL; + NAPI_GRO_CB(skb)->frag0_len = 0; + +- if (skb_mac_header(skb) == skb_tail_pointer(skb) && +- pinfo->nr_frags && ++ if (!skb_headlen(skb) && pinfo->nr_frags && + !PageHighMem(skb_frag_page(frag0)) && + (!NET_IP_ALIGN || !((skb_frag_off(frag0) + nhoff) & 3))) { + NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); diff --git a/ipq806x/backport-5.4/716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch b/ipq806x/backport-5.4/716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch new file mode 100644 index 0000000..92fe224 --- /dev/null +++ b/ipq806x/backport-5.4/716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch @@ -0,0 +1,179 @@ +From 4054955f0da08c81d42220cb445820d474f1ac92 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -565,26 +565,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; +- +- phylink_err(pl, "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); ++ phylink_err(pl, "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 +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -520,45 +521,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/ipq806x/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch b/ipq806x/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch new file mode 100644 index 0000000..9175f25 --- /dev/null +++ b/ipq806x/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch @@ -0,0 +1,254 @@ +From 863b5b6941f9f43b924393b6ba2b36647e7dee42 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -568,7 +568,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); + phylink_err(pl, "unable to attach SFP bus: %d\n", ret); +@@ -577,7 +577,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; + } + + /** +@@ -675,8 +678,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 +@@ -404,10 +404,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) + { +@@ -423,11 +432,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; + } + +@@ -521,13 +530,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, +@@ -537,9 +545,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; +@@ -557,7 +563,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; + +@@ -570,33 +608,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/ipq806x/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch b/ipq806x/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch new file mode 100644 index 0000000..c7bfd8a --- /dev/null +++ b/ipq806x/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch @@ -0,0 +1,27 @@ +From ea7bfd81921827d334c2a23bd11ef0e4e2abafd2 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -406,7 +406,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/ipq806x/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch b/ipq806x/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch new file mode 100644 index 0000000..9528049 --- /dev/null +++ b/ipq806x/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch @@ -0,0 +1,27 @@ +From f76d84cd85f8bd3f083495f7ca723822cba8abc9 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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/ipq806x/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch b/ipq806x/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch new file mode 100644 index 0000000..e4ca85b --- /dev/null +++ b/ipq806x/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch @@ -0,0 +1,124 @@ +From b9d6ed5cdb67533feda7f221eb06f2f9f1ff5047 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1544,19 +1544,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) { +@@ -1596,27 +1611,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 || +@@ -1627,7 +1625,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; + } + +@@ -1682,6 +1679,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/ipq806x/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch b/ipq806x/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch new file mode 100644 index 0000000..71021c8 --- /dev/null +++ b/ipq806x/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch @@ -0,0 +1,41 @@ +From 7e89b737c97a9e7a81dd1584000bc136b92f12fd Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1554,15 +1554,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; + } + } +@@ -1624,6 +1617,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/ipq806x/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch b/ipq806x/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch new file mode 100644 index 0000000..2974586 --- /dev/null +++ b/ipq806x/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch @@ -0,0 +1,71 @@ +From f2a1ccfc4ad4f97c98c3cc18eb32992151ce089a Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1245,7 +1245,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; +@@ -1569,22 +1569,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); + } +@@ -1592,7 +1592,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 */ +@@ -1600,7 +1600,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/ipq806x/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch b/ipq806x/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch new file mode 100644 index 0000000..62cdb8a --- /dev/null +++ b/ipq806x/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch @@ -0,0 +1,53 @@ +From d2591ea5520e2ee8fa557f96bb64c23cafac4b20 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1565,6 +1565,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) { +@@ -1574,9 +1582,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) +@@ -1598,10 +1604,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/ipq806x/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch b/ipq806x/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch new file mode 100644 index 0000000..780e7d7 --- /dev/null +++ b/ipq806x/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch @@ -0,0 +1,51 @@ +From 615090acb3c0b41691f3a03522ea38350387c0e4 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -149,11 +149,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) + +@@ -1560,8 +1559,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) + { +@@ -1577,7 +1576,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/ipq806x/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch b/ipq806x/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch new file mode 100644 index 0000000..df5ef9f --- /dev/null +++ b/ipq806x/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch @@ -0,0 +1,115 @@ +From d4b8746219e8c0361e5ed6e440ab3a8a600d1f76 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -198,6 +198,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; +@@ -1374,17 +1376,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)) != +@@ -1393,23 +1392,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)); +@@ -1429,7 +1438,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: +@@ -1516,6 +1526,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; +@@ -1539,6 +1554,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/ipq806x/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch b/ipq806x/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch new file mode 100644 index 0000000..5237f55 --- /dev/null +++ b/ipq806x/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch @@ -0,0 +1,65 @@ +From dca678b8838945572cf50584cb33a7199c1fd397 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1385,25 +1385,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/ipq806x/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch b/ipq806x/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch new file mode 100644 index 0000000..eebcac6 --- /dev/null +++ b/ipq806x/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch @@ -0,0 +1,52 @@ +From df5c4d93c5a59cba0f7479a4cd4e22b50726ce88 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1557,11 +1557,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; + +@@ -1599,10 +1594,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/ipq806x/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch b/ipq806x/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch new file mode 100644 index 0000000..92df26c --- /dev/null +++ b/ipq806x/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch @@ -0,0 +1,53 @@ +From 5ed0bd49b2d3ac4439c2d7f44e5a82b7cf6f409a Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1353,14 +1353,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. +@@ -1645,8 +1641,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/ipq806x/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch b/ipq806x/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch new file mode 100644 index 0000000..e26a727 --- /dev/null +++ b/ipq806x/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch @@ -0,0 +1,130 @@ +From 0fe72afaa31f98ebd71bd6683fc47021105d0157 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -54,6 +54,7 @@ enum { + SFP_DEV_UP, + + SFP_S_DOWN = 0, ++ SFP_S_WAIT, + SFP_S_INIT, + SFP_S_WAIT_LOS, + SFP_S_LINK_UP, +@@ -110,6 +111,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", +@@ -141,6 +143,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) +@@ -161,9 +164,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); +@@ -1267,8 +1267,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"); +@@ -1623,6 +1621,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 || +@@ -1640,17 +1640,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; + +@@ -1658,7 +1686,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/ipq806x/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch b/ipq806x/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch new file mode 100644 index 0000000..d45b061 --- /dev/null +++ b/ipq806x/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch @@ -0,0 +1,69 @@ +From 2aa424ee7fbe43e2cd24e28c2f6388c4e1796bd2 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -1334,7 +1334,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, +@@ -1344,7 +1344,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); + } + } + +@@ -1684,14 +1684,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; +@@ -1699,7 +1699,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); +@@ -1715,7 +1715,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/ipq806x/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch b/ipq806x/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch new file mode 100644 index 0000000..acca29b --- /dev/null +++ b/ipq806x/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch @@ -0,0 +1,80 @@ +From 38b62a12231be4b86fc5ca5477579d29831c02a5 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -56,6 +56,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, +@@ -113,6 +114,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", +@@ -1660,8 +1662,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 +@@ -1683,10 +1683,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/ipq806x/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch b/ipq806x/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch new file mode 100644 index 0000000..714d783 --- /dev/null +++ b/ipq806x/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch @@ -0,0 +1,153 @@ +From ec6036a58f979c66bbd5cd9d0d1c783a98c2c644 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -36,6 +36,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, +@@ -50,7 +52,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, +@@ -80,6 +83,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", + }; +@@ -94,6 +98,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", +@@ -188,7 +194,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; +@@ -1559,17 +1564,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; + } +@@ -1580,17 +1594,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; + +@@ -1756,8 +1773,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", +@@ -1770,15 +1787,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/ipq806x/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch b/ipq806x/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch new file mode 100644 index 0000000..f645e44 --- /dev/null +++ b/ipq806x/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch @@ -0,0 +1,184 @@ +From fdff863a4ce3677907f64396e34c45025abb6600 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 +@@ -49,6 +49,7 @@ enum { + SFP_MOD_EMPTY = 0, + SFP_MOD_PROBE, + SFP_MOD_HPOWER, ++ SFP_MOD_WAITPWR, + SFP_MOD_PRESENT, + SFP_MOD_ERROR, + +@@ -71,6 +72,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", + }; +@@ -1423,37 +1425,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) +@@ -1549,7 +1548,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) +@@ -1594,13 +1593,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; + } +@@ -1612,26 +1620,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, SFP_MOD_WAITPWR, T_HPOWER_LEVEL); ++ else if (err != -EAGAIN) ++ sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); ++ else ++ sfp_sm_set_timer(sfp, T_PROBE_RETRY); ++ break; ++ ++ case SFP_MOD_WAITPWR: ++ /* Wait for T_HPOWER_LEVEL to time out */ ++ if (event != SFP_E_TIMEOUT) + break; +- } +- /* fallthrough */ ++ ++ insert: ++ sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0); ++ break; ++ + case SFP_MOD_PRESENT: + case SFP_MOD_ERROR: + break; diff --git a/ipq806x/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch b/ipq806x/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch new file mode 100644 index 0000000..e49bde2 --- /dev/null +++ b/ipq806x/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch @@ -0,0 +1,159 @@ +From 57cbf7453551db1df619b79410d79fc418d862d5 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 5 Nov 2019 13:00:45 +0000 +Subject: [PATCH 632/660] net: sfp: move module insert reporting out of probe + +Move the module insertion reporting out of the probe handling, but +after we have detected that the upstream has attached (since that is +whom we are reporting insertion to.) + +Only report module removal if we had previously reported a module +insertion. + +This gives cleaner semantics, and means we can probe the module before +we have an upstream attached. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 58 +++++++++++++++++++++++++++++-------------- + 1 file changed, 40 insertions(+), 18 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -47,11 +47,12 @@ enum { + SFP_E_TIMEOUT, + + SFP_MOD_EMPTY = 0, ++ SFP_MOD_ERROR, + SFP_MOD_PROBE, ++ SFP_MOD_WAITDEV, + SFP_MOD_HPOWER, + SFP_MOD_WAITPWR, + SFP_MOD_PRESENT, +- SFP_MOD_ERROR, + + SFP_DEV_DETACHED = 0, + SFP_DEV_DOWN, +@@ -70,11 +71,12 @@ enum { + + static const char * const mod_state_strings[] = { + [SFP_MOD_EMPTY] = "empty", ++ [SFP_MOD_ERROR] = "error", + [SFP_MOD_PROBE] = "probe", ++ [SFP_MOD_WAITDEV] = "waitdev", + [SFP_MOD_HPOWER] = "hpower", + [SFP_MOD_WAITPWR] = "waitpwr", + [SFP_MOD_PRESENT] = "present", +- [SFP_MOD_ERROR] = "error", + }; + + static const char *mod_state_to_str(unsigned short mod_state) +@@ -1544,16 +1546,13 @@ static int sfp_sm_mod_probe(struct sfp * + if (ret < 0) + return ret; + +- ret = sfp_module_insert(sfp->sfp_bus, &sfp->id); +- if (ret < 0) +- return ret; +- + return 0; + } + + static void sfp_sm_mod_remove(struct sfp *sfp) + { +- sfp_module_remove(sfp->sfp_bus); ++ if (sfp->sm_mod_state > SFP_MOD_WAITDEV) ++ sfp_module_remove(sfp->sfp_bus); + + sfp_hwmon_remove(sfp); + +@@ -1604,12 +1603,12 @@ static void sfp_sm_module(struct sfp *sf + } + + /* Handle device detach globally */ +- if (sfp->sm_dev_state < SFP_DEV_DOWN) { ++ if (sfp->sm_dev_state < SFP_DEV_DOWN && ++ sfp->sm_mod_state > SFP_MOD_WAITDEV) { + 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); ++ sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); + return; + } + +@@ -1620,6 +1619,7 @@ static void sfp_sm_module(struct sfp *sf + break; + + case SFP_MOD_PROBE: ++ /* Wait for T_PROBE_INIT to time out */ + if (event != SFP_E_TIMEOUT) + break; + +@@ -1633,6 +1633,20 @@ static void sfp_sm_module(struct sfp *sf + break; + } + ++ sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); ++ /* fall through */ ++ case SFP_MOD_WAITDEV: ++ /* Ensure that the device is attached before proceeding */ ++ if (sfp->sm_dev_state < SFP_DEV_DOWN) ++ break; ++ ++ /* Report the module insertion to the upstream device */ ++ err = sfp_module_insert(sfp->sfp_bus, &sfp->id); ++ 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; +@@ -1642,12 +1656,17 @@ static void sfp_sm_module(struct sfp *sf + case SFP_MOD_HPOWER: + /* Enable high power mode */ + err = sfp_sm_mod_hpower(sfp, true); +- if (err == 0) +- sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL); +- else if (err != -EAGAIN) +- sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); +- else +- sfp_sm_set_timer(sfp, T_PROBE_RETRY); ++ if (err < 0) { ++ if (err != -EAGAIN) { ++ sfp_module_remove(sfp->sfp_bus); ++ sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); ++ } else { ++ sfp_sm_set_timer(sfp, T_PROBE_RETRY); ++ } ++ break; ++ } ++ ++ sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL); + break; + + case SFP_MOD_WAITPWR: +@@ -1815,8 +1834,6 @@ static void sfp_sm_event(struct sfp *sfp + static void sfp_attach(struct sfp *sfp) + { + 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) +@@ -2084,6 +2101,11 @@ static int sfp_probe(struct platform_dev + sfp->state |= SFP_F_RATE_SELECT; + sfp_set_state(sfp, sfp->state); + sfp_module_tx_disable(sfp); ++ if (sfp->state & SFP_F_PRESENT) { ++ rtnl_lock(); ++ sfp_sm_event(sfp, SFP_E_INSERT); ++ rtnl_unlock(); ++ } + + for (i = 0; i < GPIO_MAX; i++) { + if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i]) diff --git a/ipq806x/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch b/ipq806x/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch new file mode 100644 index 0000000..ab1ae75 --- /dev/null +++ b/ipq806x/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch @@ -0,0 +1,110 @@ +From fb56cd08880aff8fb030e684fa4311bef712a499 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 5 Nov 2019 13:02:30 +0000 +Subject: [PATCH 633/660] net: sfp: allow sfp to probe slow to initialise GPON + modules + +Some GPON modules (e.g. Huawei MA5671A) take a significant amount of +time to start responding on the I2C bus, contary to the SFF +specifications. + +Work around this by implementing a two-level timeout strategy, where +we initially quickly retry for the module, and then use a slower retry +after we exceed a maximum number of quick attempts. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 38 ++++++++++++++++++++++++++++---------- + 1 file changed, 28 insertions(+), 10 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -167,9 +167,12 @@ static const enum gpiod_flags gpio_flags + * 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_SERIAL msecs_to_jiffies(300) +-#define T_HPOWER_LEVEL msecs_to_jiffies(300) +-#define T_PROBE_RETRY msecs_to_jiffies(100) ++#define T_SERIAL msecs_to_jiffies(300) ++#define T_HPOWER_LEVEL msecs_to_jiffies(300) ++#define T_PROBE_RETRY_INIT msecs_to_jiffies(100) ++#define R_PROBE_RETRY_INIT 10 ++#define T_PROBE_RETRY_SLOW msecs_to_jiffies(5000) ++#define R_PROBE_RETRY_SLOW 12 + + /* SFP modules appear to always have their PHY configured for bus address + * 0x56 (which with mdio-i2c, translates to a PHY address of 22). +@@ -204,6 +207,8 @@ struct sfp { + struct delayed_work timeout; + struct mutex sm_mutex; /* Protects state machine */ + unsigned char sm_mod_state; ++ unsigned char sm_mod_tries_init; ++ unsigned char sm_mod_tries; + unsigned char sm_dev_state; + unsigned short sm_state; + unsigned int sm_retries; +@@ -1457,7 +1462,7 @@ static int sfp_sm_mod_hpower(struct sfp + return 0; + } + +-static int sfp_sm_mod_probe(struct sfp *sfp) ++static int sfp_sm_mod_probe(struct sfp *sfp, bool report) + { + /* SFP module inserted - read I2C data */ + struct sfp_eeprom_id id; +@@ -1467,7 +1472,8 @@ static int sfp_sm_mod_probe(struct sfp * + + ret = sfp_read(sfp, false, 0, &id, sizeof(id)); + if (ret < 0) { +- dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); ++ if (report) ++ dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); + return -EAGAIN; + } + +@@ -1614,8 +1620,11 @@ static void sfp_sm_module(struct sfp *sf + + switch (sfp->sm_mod_state) { + default: +- if (event == SFP_E_INSERT) ++ if (event == SFP_E_INSERT) { + sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); ++ sfp->sm_mod_tries_init = R_PROBE_RETRY_INIT; ++ sfp->sm_mod_tries = R_PROBE_RETRY_SLOW; ++ } + break; + + case SFP_MOD_PROBE: +@@ -1623,10 +1632,19 @@ static void sfp_sm_module(struct sfp *sf + if (event != SFP_E_TIMEOUT) + break; + +- err = sfp_sm_mod_probe(sfp); ++ err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1); + if (err == -EAGAIN) { +- sfp_sm_set_timer(sfp, T_PROBE_RETRY); +- break; ++ if (sfp->sm_mod_tries_init && ++ --sfp->sm_mod_tries_init) { ++ sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT); ++ break; ++ } else if (sfp->sm_mod_tries && --sfp->sm_mod_tries) { ++ if (sfp->sm_mod_tries == R_PROBE_RETRY_SLOW - 1) ++ dev_warn(sfp->dev, ++ "please wait, module slow to respond\n"); ++ sfp_sm_set_timer(sfp, T_PROBE_RETRY_SLOW); ++ break; ++ } + } + if (err < 0) { + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); +@@ -1661,7 +1679,7 @@ static void sfp_sm_module(struct sfp *sf + sfp_module_remove(sfp->sfp_bus); + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); + } else { +- sfp_sm_set_timer(sfp, T_PROBE_RETRY); ++ sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT); + } + break; + } diff --git a/ipq806x/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch b/ipq806x/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch new file mode 100644 index 0000000..e6c1fd7 --- /dev/null +++ b/ipq806x/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch @@ -0,0 +1,198 @@ +From 559391fc20fae506adcb311b904cc544c76436c0 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 7 Nov 2019 18:52:07 +0000 +Subject: [PATCH 634/660] net: sfp: allow modules with slow diagnostics to + probe + +When a module is inserted, we attempt to read read the ID from address +0x50. Once we are able to read the ID, we immediately attempt to +initialise the hwmon support by reading from address 0x51. If this +fails, then we fall into error state, and assume that the module is +not usable. + +Modules such as the ALCATELLUCENT 3FE46541AA use a real EEPROM for +I2C address 0x50, which responds immediately. However, address 0x51 +is an emulated, which only becomes available once the on-board firmware +has booted. This prompts us to fall into the error state. + +Since the module may be usable without diagnostics, arrange for the +hwmon probe independent of the rest of the SFP itself, retrying every +5s for up to about 60s for the monitoring to become available, and +print an error message if it doesn't become available. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 96 +++++++++++++++++++++++++++++++++---------- + 1 file changed, 74 insertions(+), 22 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -218,6 +218,8 @@ struct sfp { + + #if IS_ENABLED(CONFIG_HWMON) + struct sfp_diag diag; ++ struct delayed_work hwmon_probe; ++ unsigned int hwmon_tries; + struct device *hwmon_dev; + char *hwmon_name; + #endif +@@ -1159,29 +1161,27 @@ static const struct hwmon_chip_info sfp_ + .info = sfp_hwmon_info, + }; + +-static int sfp_hwmon_insert(struct sfp *sfp) ++static void sfp_hwmon_probe(struct work_struct *work) + { ++ struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work); + int err, i; + +- if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) +- return 0; +- +- if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) +- return 0; +- +- if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) +- /* This driver in general does not support address +- * change. +- */ +- return 0; +- + err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag)); +- if (err < 0) +- return err; ++ if (err < 0) { ++ if (sfp->hwmon_tries--) { ++ mod_delayed_work(system_wq, &sfp->hwmon_probe, ++ T_PROBE_RETRY_SLOW); ++ } else { ++ dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); ++ } ++ return; ++ } + + sfp->hwmon_name = kstrdup(dev_name(sfp->dev), GFP_KERNEL); +- if (!sfp->hwmon_name) +- return -ENODEV; ++ if (!sfp->hwmon_name) { ++ dev_err(sfp->dev, "out of memory for hwmon name\n"); ++ return; ++ } + + for (i = 0; sfp->hwmon_name[i]; i++) + if (hwmon_is_bad_char(sfp->hwmon_name[i])) +@@ -1191,18 +1191,52 @@ static int sfp_hwmon_insert(struct sfp * + sfp->hwmon_name, sfp, + &sfp_hwmon_chip_info, + NULL); ++ if (IS_ERR(sfp->hwmon_dev)) ++ dev_err(sfp->dev, "failed to register hwmon device: %ld\n", ++ PTR_ERR(sfp->hwmon_dev)); ++} ++ ++static int sfp_hwmon_insert(struct sfp *sfp) ++{ ++ if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) ++ return 0; ++ ++ if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) ++ return 0; ++ ++ if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) ++ /* This driver in general does not support address ++ * change. ++ */ ++ return 0; ++ ++ mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); ++ sfp->hwmon_tries = R_PROBE_RETRY_SLOW; + +- return PTR_ERR_OR_ZERO(sfp->hwmon_dev); ++ return 0; + } + + static void sfp_hwmon_remove(struct sfp *sfp) + { ++ cancel_delayed_work_sync(&sfp->hwmon_probe); + if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) { + hwmon_device_unregister(sfp->hwmon_dev); + sfp->hwmon_dev = NULL; + kfree(sfp->hwmon_name); + } + } ++ ++static int sfp_hwmon_init(struct sfp *sfp) ++{ ++ INIT_DELAYED_WORK(&sfp->hwmon_probe, sfp_hwmon_probe); ++ ++ return 0; ++} ++ ++static void sfp_hwmon_exit(struct sfp *sfp) ++{ ++ cancel_delayed_work_sync(&sfp->hwmon_probe); ++} + #else + static int sfp_hwmon_insert(struct sfp *sfp) + { +@@ -1212,6 +1246,15 @@ static int sfp_hwmon_insert(struct sfp * + static void sfp_hwmon_remove(struct sfp *sfp) + { + } ++ ++static int sfp_hwmon_init(struct sfp *sfp) ++{ ++ return 0; ++} ++ ++static void sfp_hwmon_exit(struct sfp *sfp) ++{ ++} + #endif + + /* Helpers */ +@@ -1548,10 +1591,6 @@ static int sfp_sm_mod_probe(struct sfp * + if (ret < 0) + return ret; + +- ret = sfp_hwmon_insert(sfp); +- if (ret < 0) +- return ret; +- + return 0; + } + +@@ -1700,6 +1739,15 @@ static void sfp_sm_module(struct sfp *sf + case SFP_MOD_ERROR: + break; + } ++ ++#if IS_ENABLED(CONFIG_HWMON) ++ if (sfp->sm_mod_state >= SFP_MOD_WAITDEV && ++ IS_ERR_OR_NULL(sfp->hwmon_dev)) { ++ err = sfp_hwmon_insert(sfp); ++ if (err) ++ dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); ++ } ++#endif + } + + static void sfp_sm_main(struct sfp *sfp, unsigned int event) +@@ -2001,6 +2049,8 @@ static struct sfp *sfp_alloc(struct devi + INIT_DELAYED_WORK(&sfp->poll, sfp_poll); + INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout); + ++ sfp_hwmon_init(sfp); ++ + return sfp; + } + +@@ -2008,6 +2058,8 @@ static void sfp_cleanup(void *data) + { + struct sfp *sfp = data; + ++ sfp_hwmon_exit(sfp); ++ + cancel_delayed_work_sync(&sfp->poll); + cancel_delayed_work_sync(&sfp->timeout); + if (sfp->i2c_mii) { diff --git a/ipq806x/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch b/ipq806x/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch new file mode 100644 index 0000000..edfe151 --- /dev/null +++ b/ipq806x/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch @@ -0,0 +1,183 @@ +From eb156db588ac583cdae7b91eaac9c0ad3a358e63 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Sun, 15 Sep 2019 20:05:34 +0100 +Subject: [PATCH 635/660] net: phy: add core phylib sfp support + +Add core phylib help for supporting SFP sockets on PHYs. This provides +a mechanism to inform the SFP layer about PHY up/down events, and also +unregister the SFP bus when the PHY is going away. + +Signed-off-by: Russell King +--- + drivers/net/phy/phy.c | 7 ++++ + drivers/net/phy/phy_device.c | 66 ++++++++++++++++++++++++++++++++++++ + include/linux/phy.h | 11 ++++++ + 3 files changed, 84 insertions(+) + +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -863,6 +864,9 @@ void phy_stop(struct phy_device *phydev) + + mutex_lock(&phydev->lock); + ++ if (phydev->sfp_bus) ++ sfp_upstream_stop(phydev->sfp_bus); ++ + phydev->state = PHY_HALTED; + + mutex_unlock(&phydev->lock); +@@ -925,6 +929,9 @@ void phy_state_machine(struct work_struc + + old_state = phydev->state; + ++ if (phydev->sfp_bus) ++ sfp_upstream_start(phydev->sfp_bus); ++ + switch (phydev->state) { + case PHY_DOWN: + case PHY_READY: +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1185,6 +1186,65 @@ phy_standalone_show(struct device *dev, + static DEVICE_ATTR_RO(phy_standalone); + + /** ++ * phy_sfp_attach - attach the SFP bus to the PHY upstream network device ++ * @upstream: pointer to the phy device ++ * @bus: sfp bus representing cage being attached ++ * ++ * This is used to fill in the sfp_upstream_ops .attach member. ++ */ ++void phy_sfp_attach(void *upstream, struct sfp_bus *bus) ++{ ++ struct phy_device *phydev = upstream; ++ ++ if (phydev->attached_dev) ++ phydev->attached_dev->sfp_bus = bus; ++ phydev->sfp_bus_attached = true; ++} ++EXPORT_SYMBOL(phy_sfp_attach); ++ ++/** ++ * phy_sfp_detach - detach the SFP bus from the PHY upstream network device ++ * @upstream: pointer to the phy device ++ * @bus: sfp bus representing cage being attached ++ * ++ * This is used to fill in the sfp_upstream_ops .detach member. ++ */ ++void phy_sfp_detach(void *upstream, struct sfp_bus *bus) ++{ ++ struct phy_device *phydev = upstream; ++ ++ if (phydev->attached_dev) ++ phydev->attached_dev->sfp_bus = NULL; ++ phydev->sfp_bus_attached = false; ++} ++EXPORT_SYMBOL(phy_sfp_detach); ++ ++/** ++ * phy_sfp_probe - probe for a SFP cage attached to this PHY device ++ * @phydev: Pointer to phy_device ++ * @ops: SFP's upstream operations ++ */ ++int phy_sfp_probe(struct phy_device *phydev, ++ const struct sfp_upstream_ops *ops) ++{ ++ struct sfp_bus *bus; ++ int ret; ++ ++ if (phydev->mdio.dev.fwnode) { ++ bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode); ++ if (IS_ERR(bus)) ++ return PTR_ERR(bus); ++ ++ phydev->sfp_bus = bus; ++ ++ ret = sfp_bus_add_upstream(bus, phydev, ops); ++ sfp_bus_put(bus); ++ } ++ return 0; ++} ++EXPORT_SYMBOL(phy_sfp_probe); ++ ++/** + * phy_attach_direct - attach a network device to a given PHY device pointer + * @dev: network device to attach + * @phydev: Pointer to phy_device to attach +@@ -1261,6 +1321,9 @@ int phy_attach_direct(struct net_device + dev->phydev = phydev; + } + ++ if (phydev->sfp_bus_attached) ++ dev->sfp_bus = phydev->sfp_bus; ++ + /* Some Ethernet drivers try to connect to a PHY device before + * calling register_netdevice() -> netdev_register_kobject() and + * does the dev->dev.kobj initialization. Here we only check for +@@ -2291,6 +2354,9 @@ static int phy_remove(struct device *dev + phydev->state = PHY_DOWN; + mutex_unlock(&phydev->lock); + ++ sfp_bus_del_upstream(phydev->sfp_bus); ++ phydev->sfp_bus = NULL; ++ + if (phydev->drv && phydev->drv->remove) { + phydev->drv->remove(phydev); + +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -203,6 +203,8 @@ static inline const char *phy_modes(phy_ + + struct device; + struct phylink; ++struct sfp_bus; ++struct sfp_upstream_ops; + struct sk_buff; + + /* +@@ -343,6 +345,8 @@ struct phy_c45_device_ids { + * dev_flags: Device-specific flags used by the PHY driver. + * irq: IRQ number of the PHY's interrupt (-1 if none) + * phy_timer: The timer for handling the state machine ++ * sfp_bus_attached: flag indicating whether the SFP bus has been attached ++ * sfp_bus: SFP bus attached to this PHY's fiber port + * attached_dev: The attached enet driver's device instance ptr + * adjust_link: Callback for the enet controller to respond to + * changes in the link state. +@@ -434,6 +438,9 @@ struct phy_device { + + struct mutex lock; + ++ /* This may be modified under the rtnl lock */ ++ bool sfp_bus_attached; ++ struct sfp_bus *sfp_bus; + struct phylink *phylink; + struct net_device *attached_dev; + +@@ -1023,6 +1030,10 @@ int phy_suspend(struct phy_device *phyde + int phy_resume(struct phy_device *phydev); + int __phy_resume(struct phy_device *phydev); + int phy_loopback(struct phy_device *phydev, bool enable); ++void phy_sfp_attach(void *upstream, struct sfp_bus *bus); ++void phy_sfp_detach(void *upstream, struct sfp_bus *bus); ++int phy_sfp_probe(struct phy_device *phydev, ++ const struct sfp_upstream_ops *ops); + struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, + phy_interface_t interface); + struct phy_device *phy_find_first(struct mii_bus *bus); diff --git a/ipq806x/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch b/ipq806x/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch new file mode 100644 index 0000000..40a666a --- /dev/null +++ b/ipq806x/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch @@ -0,0 +1,67 @@ +From 0836d9fb41ed90090ef4af0d7abe784ee7706f80 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Fri, 14 Apr 2017 14:21:25 +0100 +Subject: [PATCH 636/660] net: phy: marvell10g: add SFP+ support + +Add support for SFP+ cages to the Marvell 10G PHY driver. This is +slightly complicated by the way phylib works in that we need to use +a multi-step process to attach the SFP bus, and we also need to track +the phylink state machine to know when the module's transmit disable +signal should change state. + +With appropriate DT changes, this allows the SFP+ canges on the +Macchiatobin platform to be functional. + +Signed-off-by: Russell King +--- + drivers/net/phy/marvell10g.c | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe + #define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa) +@@ -206,6 +207,28 @@ static int mv3310_hwmon_probe(struct phy + } + #endif + ++static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) ++{ ++ struct phy_device *phydev = upstream; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; ++ phy_interface_t iface; ++ ++ sfp_parse_support(phydev->sfp_bus, id, support); ++ iface = sfp_select_interface(phydev->sfp_bus, id, support); ++ ++ if (iface != PHY_INTERFACE_MODE_10GKR) { ++ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static const struct sfp_upstream_ops mv3310_sfp_ops = { ++ .attach = phy_sfp_attach, ++ .detach = phy_sfp_detach, ++ .module_insert = mv3310_sfp_insert, ++}; ++ + static int mv3310_probe(struct phy_device *phydev) + { + struct mv3310_priv *priv; +@@ -236,7 +259,7 @@ static int mv3310_probe(struct phy_devic + if (ret) + return ret; + +- return 0; ++ return phy_sfp_probe(phydev, &mv3310_sfp_ops); + } + + static int mv3310_suspend(struct phy_device *phydev) diff --git a/ipq806x/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch b/ipq806x/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch new file mode 100644 index 0000000..84a8214 --- /dev/null +++ b/ipq806x/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch @@ -0,0 +1,43 @@ +From 09d7d8395ec61fba4392b35baa6f71c4e36489df Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Fri, 8 Nov 2019 15:18:02 +0000 +Subject: [PATCH 637/660] net: phylink: update to use phy_support_asym_pause() + +Use phy_support_asym_pause() rather than open-coding it. + +Signed-off-by: Russell King +--- + drivers/net/phy/phylink.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -718,11 +718,6 @@ static int phylink_bringup_phy(struct ph + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); + int ret; + +- memset(&config, 0, sizeof(config)); +- linkmode_copy(supported, phy->supported); +- linkmode_copy(config.advertising, phy->advertising); +- config.interface = pl->link_config.interface; +- + /* + * This is the new way of dealing with flow control for PHYs, + * as described by Timur Tabi in commit 529ed1275263 ("net: phy: +@@ -730,10 +725,12 @@ static int phylink_bringup_phy(struct ph + * using our validate call to the MAC, we rely upon the MAC + * clearing the bits from both supported and advertising fields. + */ +- if (phylink_test(supported, Pause)) +- phylink_set(config.advertising, Pause); +- if (phylink_test(supported, Asym_Pause)) +- phylink_set(config.advertising, Asym_Pause); ++ phy_support_asym_pause(phy); ++ ++ memset(&config, 0, sizeof(config)); ++ linkmode_copy(supported, phy->supported); ++ linkmode_copy(config.advertising, phy->advertising); ++ config.interface = pl->link_config.interface; + + ret = phylink_validate(pl, supported, &config); + if (ret) diff --git a/ipq806x/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch b/ipq806x/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch new file mode 100644 index 0000000..abc9f65 --- /dev/null +++ b/ipq806x/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch @@ -0,0 +1,225 @@ +From 40e0b3b15f7da92e6b065292b14af7b9bfb1c6e0 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Fri, 13 Sep 2019 23:00:35 +0100 +Subject: [PATCH 642/660] net: sfp: soft status and control support + +Add support for the soft status and control register, which allows +TX_FAULT and RX_LOS to be monitored and TX_DISABLE to be set. We +make use of this when the board does not support GPIOs for these +signals. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 110 ++++++++++++++++++++++++++++++++++-------- + include/linux/sfp.h | 4 ++ + 2 files changed, 94 insertions(+), 20 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -201,7 +201,10 @@ struct sfp { + struct gpio_desc *gpio[GPIO_MAX]; + int gpio_irq[GPIO_MAX]; + ++ bool need_poll; ++ + struct mutex st_mutex; /* Protects state */ ++ unsigned int state_soft_mask; + unsigned int state; + struct delayed_work poll; + struct delayed_work timeout; +@@ -395,24 +398,90 @@ static int sfp_i2c_configure(struct sfp + } + + /* Interface */ +-static unsigned int sfp_get_state(struct sfp *sfp) ++static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) + { +- return sfp->get_state(sfp); ++ return sfp->read(sfp, a2, addr, buf, len); + } + +-static void sfp_set_state(struct sfp *sfp, unsigned int state) ++static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) + { +- sfp->set_state(sfp, state); ++ return sfp->write(sfp, a2, addr, buf, len); + } + +-static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) ++static unsigned int sfp_soft_get_state(struct sfp *sfp) + { +- return sfp->read(sfp, a2, addr, buf, len); ++ unsigned int state = 0; ++ u8 status; ++ ++ if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == ++ sizeof(status)) { ++ if (status & SFP_STATUS_RX_LOS) ++ state |= SFP_F_LOS; ++ if (status & SFP_STATUS_TX_FAULT) ++ state |= SFP_F_TX_FAULT; ++ } ++ ++ return state & sfp->state_soft_mask; + } + +-static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) ++static void sfp_soft_set_state(struct sfp *sfp, unsigned int state) + { +- return sfp->write(sfp, a2, addr, buf, len); ++ u8 status; ++ ++ if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == ++ sizeof(status)) { ++ if (state & SFP_F_TX_DISABLE) ++ status |= SFP_STATUS_TX_DISABLE_FORCE; ++ else ++ status &= ~SFP_STATUS_TX_DISABLE_FORCE; ++ ++ sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status)); ++ } ++} ++ ++static void sfp_soft_start_poll(struct sfp *sfp) ++{ ++ const struct sfp_eeprom_id *id = &sfp->id; ++ ++ sfp->state_soft_mask = 0; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE && ++ !sfp->gpio[GPIO_TX_DISABLE]) ++ sfp->state_soft_mask |= SFP_F_TX_DISABLE; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT && ++ !sfp->gpio[GPIO_TX_FAULT]) ++ sfp->state_soft_mask |= SFP_F_TX_FAULT; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS && ++ !sfp->gpio[GPIO_LOS]) ++ sfp->state_soft_mask |= SFP_F_LOS; ++ ++ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && ++ !sfp->need_poll) ++ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); ++} ++ ++static void sfp_soft_stop_poll(struct sfp *sfp) ++{ ++ sfp->state_soft_mask = 0; ++} ++ ++static unsigned int sfp_get_state(struct sfp *sfp) ++{ ++ unsigned int state = sfp->get_state(sfp); ++ ++ if (state & SFP_F_PRESENT && ++ sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT)) ++ state |= sfp_soft_get_state(sfp); ++ ++ return state; ++} ++ ++static void sfp_set_state(struct sfp *sfp, unsigned int state) ++{ ++ sfp->set_state(sfp, state); ++ ++ if (state & SFP_F_PRESENT && ++ sfp->state_soft_mask & SFP_F_TX_DISABLE) ++ sfp_soft_set_state(sfp, state); + } + + static unsigned int sfp_check(void *buf, size_t len) +@@ -1407,11 +1476,6 @@ static void sfp_sm_fault(struct sfp *sfp + } + } + +-static void sfp_sm_mod_init(struct sfp *sfp) +-{ +- sfp_module_tx_enable(sfp); +-} +- + static void sfp_sm_probe_for_phy(struct sfp *sfp) + { + /* Setting the serdes link mode is guesswork: there's no +@@ -1574,7 +1638,7 @@ static int sfp_sm_mod_probe(struct sfp * + (int)sizeof(id.ext.datecode), id.ext.datecode); + + /* Check whether we support this module */ +- if (!sfp->type->module_supported(&sfp->id)) { ++ if (!sfp->type->module_supported(&id)) { + dev_err(sfp->dev, + "module is not supported - phys id 0x%02x 0x%02x\n", + sfp->id.base.phys_id, sfp->id.base.phys_ext_id); +@@ -1764,6 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp, + if (sfp->mod_phy) + sfp_sm_phy_detach(sfp); + sfp_module_tx_disable(sfp); ++ sfp_soft_stop_poll(sfp); + sfp_sm_next(sfp, SFP_S_DOWN, 0); + return; + } +@@ -1775,7 +1840,10 @@ static void sfp_sm_main(struct sfp *sfp, + sfp->sm_dev_state != SFP_DEV_UP) + break; + +- sfp_sm_mod_init(sfp); ++ if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) ++ sfp_soft_start_poll(sfp); ++ ++ sfp_module_tx_enable(sfp); + + /* Initialise the fault clearance retries */ + sfp->sm_retries = 5; +@@ -2031,7 +2099,10 @@ static void sfp_poll(struct work_struct + struct sfp *sfp = container_of(work, struct sfp, poll.work); + + sfp_check_state(sfp); +- mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); ++ ++ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) || ++ sfp->need_poll) ++ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); + } + + static struct sfp *sfp_alloc(struct device *dev) +@@ -2076,7 +2147,6 @@ static int sfp_probe(struct platform_dev + const struct sff_data *sff; + struct i2c_adapter *i2c; + struct sfp *sfp; +- bool poll = false; + int err, i; + + sfp = sfp_alloc(&pdev->dev); +@@ -2184,7 +2254,7 @@ static int sfp_probe(struct platform_dev + sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]); + if (sfp->gpio_irq[i] < 0) { + sfp->gpio_irq[i] = 0; +- poll = true; ++ sfp->need_poll = true; + continue; + } + +@@ -2196,11 +2266,11 @@ static int sfp_probe(struct platform_dev + dev_name(sfp->dev), sfp); + if (err) { + sfp->gpio_irq[i] = 0; +- poll = true; ++ sfp->need_poll = true; + } + } + +- if (poll) ++ if (sfp->need_poll) + mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); + + /* We could have an issue in cases no Tx disable pin is available or +--- a/include/linux/sfp.h ++++ b/include/linux/sfp.h +@@ -428,6 +428,10 @@ enum { + SFP_TEC_CUR = 0x6c, + + SFP_STATUS = 0x6e, ++ SFP_STATUS_TX_DISABLE = BIT(7), ++ SFP_STATUS_TX_DISABLE_FORCE = BIT(6), ++ SFP_STATUS_TX_FAULT = BIT(2), ++ SFP_STATUS_RX_LOS = BIT(1), + SFP_ALARM0 = 0x70, + SFP_ALARM0_TEMP_HIGH = BIT(7), + SFP_ALARM0_TEMP_LOW = BIT(6), diff --git a/ipq806x/backport-5.4/745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch b/ipq806x/backport-5.4/745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch new file mode 100644 index 0000000..71a0699 --- /dev/null +++ b/ipq806x/backport-5.4/745-v5.7-net-dsa-mt7530-add-support-for-port-mirroring.patch @@ -0,0 +1,123 @@ +From 37feab6076aa816ed72fe836759a485353241916 Mon Sep 17 00:00:00 2001 +From: DENG Qingfang +Date: Fri, 6 Mar 2020 20:35:35 +0800 +Subject: net: dsa: mt7530: add support for port mirroring + +Add support for configuring port mirroring through the cls_matchall +classifier. We do a full ingress and/or egress capture towards a +capture port. +MT7530 supports one monitor port and multiple mirrored ports. + +Signed-off-by: DENG Qingfang +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/mt7530.h | 7 ++++++ + 2 files changed, 67 insertions(+) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1143,6 +1143,64 @@ mt7530_port_vlan_del(struct dsa_switch * + return 0; + } + ++static int mt7530_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 val; ++ ++ /* Check for existent entry */ ++ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) ++ return -EEXIST; ++ ++ val = mt7530_read(priv, MT7530_MFC); ++ ++ /* MT7530 only supports one monitor port */ ++ if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port) ++ return -EEXIST; ++ ++ val |= MIRROR_EN; ++ val &= ~MIRROR_MASK; ++ val |= mirror->to_local_port; ++ mt7530_write(priv, MT7530_MFC, val); ++ ++ val = mt7530_read(priv, MT7530_PCR_P(port)); ++ if (ingress) { ++ val |= PORT_RX_MIR; ++ priv->mirror_rx |= BIT(port); ++ } else { ++ val |= PORT_TX_MIR; ++ priv->mirror_tx |= BIT(port); ++ } ++ mt7530_write(priv, MT7530_PCR_P(port), val); ++ ++ return 0; ++} ++ ++static void mt7530_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 val; ++ ++ val = mt7530_read(priv, MT7530_PCR_P(port)); ++ if (mirror->ingress) { ++ val &= ~PORT_RX_MIR; ++ priv->mirror_rx &= ~BIT(port); ++ } else { ++ val &= ~PORT_TX_MIR; ++ priv->mirror_tx &= ~BIT(port); ++ } ++ mt7530_write(priv, MT7530_PCR_P(port), val); ++ ++ if (!priv->mirror_rx && !priv->mirror_tx) { ++ val = mt7530_read(priv, MT7530_MFC); ++ val &= ~MIRROR_EN; ++ mt7530_write(priv, MT7530_MFC, val); ++ } ++} ++ + static enum dsa_tag_protocol + mtk_get_tag_protocol(struct dsa_switch *ds, int port) + { +@@ -1520,6 +1578,8 @@ static const struct dsa_switch_ops mt753 + .port_vlan_prepare = mt7530_port_vlan_prepare, + .port_vlan_add = mt7530_port_vlan_add, + .port_vlan_del = mt7530_port_vlan_del, ++ .port_mirror_add = mt7530_port_mirror_add, ++ .port_mirror_del = mt7530_port_mirror_del, + .phylink_validate = mt7530_phylink_validate, + .phylink_mac_link_state = mt7530_phylink_mac_link_state, + .phylink_mac_config = mt7530_phylink_mac_config, +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -37,6 +37,9 @@ enum { + #define CPU_EN BIT(7) + #define CPU_PORT(x) ((x) << 4) + #define CPU_MASK (0xf << 4) ++#define MIRROR_EN BIT(3) ++#define MIRROR_PORT(x) ((x) & 0x7) ++#define MIRROR_MASK 0x7 + + /* Registers for address table access */ + #define MT7530_ATA1 0x74 +@@ -142,6 +145,8 @@ enum mt7530_stp_state { + + /* Register for port control */ + #define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100)) ++#define PORT_TX_MIR BIT(9) ++#define PORT_RX_MIR BIT(8) + #define PORT_VLAN(x) ((x) & 0x3) + + enum mt7530_port_mode { +@@ -464,6 +469,8 @@ struct mt7530_priv { + phy_interface_t p6_interface; + phy_interface_t p5_interface; + unsigned int p5_intf_sel; ++ u8 mirror_rx; ++ u8 mirror_tx; + + struct mt7530_port ports[MT7530_NUM_PORTS]; + /* protect among processes for registers access*/ diff --git a/ipq806x/backport-5.4/746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch b/ipq806x/backport-5.4/746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch new file mode 100644 index 0000000..6831787 --- /dev/null +++ b/ipq806x/backport-5.4/746-v5.5-net-dsa-mv88e6xxx-Split-monitor-port-configuration.patch @@ -0,0 +1,149 @@ +From 5c74c54ce6fff719999ff48f128cf4150ee4ff59 Mon Sep 17 00:00:00 2001 +From: Iwan R Timmer +Date: Thu, 7 Nov 2019 22:11:13 +0100 +Subject: [PATCH] net: dsa: mv88e6xxx: Split monitor port configuration + +Separate the configuration of the egress and ingress monitor port. +This allows the port mirror functionality to do ingress and egress +port mirroring to separate ports. + +Signed-off-by: Iwan R Timmer +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mv88e6xxx/chip.c | 9 ++++++- + drivers/net/dsa/mv88e6xxx/chip.h | 9 ++++++- + drivers/net/dsa/mv88e6xxx/global1.c | 42 ++++++++++++++++++++--------- + drivers/net/dsa/mv88e6xxx/global1.h | 8 ++++-- + 4 files changed, 52 insertions(+), 16 deletions(-) + +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -2384,7 +2384,14 @@ static int mv88e6xxx_setup_upstream_port + + if (chip->info->ops->set_egress_port) { + err = chip->info->ops->set_egress_port(chip, +- upstream_port); ++ MV88E6XXX_EGRESS_DIR_INGRESS, ++ upstream_port); ++ if (err) ++ return err; ++ ++ err = chip->info->ops->set_egress_port(chip, ++ MV88E6XXX_EGRESS_DIR_EGRESS, ++ upstream_port); + if (err) + return err; + } +--- a/drivers/net/dsa/mv88e6xxx/chip.h ++++ b/drivers/net/dsa/mv88e6xxx/chip.h +@@ -33,6 +33,11 @@ enum mv88e6xxx_egress_mode { + MV88E6XXX_EGRESS_MODE_ETHERTYPE, + }; + ++enum mv88e6xxx_egress_direction { ++ MV88E6XXX_EGRESS_DIR_INGRESS, ++ MV88E6XXX_EGRESS_DIR_EGRESS, ++}; ++ + enum mv88e6xxx_frame_mode { + MV88E6XXX_FRAME_MODE_NORMAL, + MV88E6XXX_FRAME_MODE_DSA, +@@ -464,7 +469,9 @@ struct mv88e6xxx_ops { + int (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port, + uint64_t *data); + int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port); +- int (*set_egress_port)(struct mv88e6xxx_chip *chip, int port); ++ int (*set_egress_port)(struct mv88e6xxx_chip *chip, ++ enum mv88e6xxx_egress_direction direction, ++ int port); + + #define MV88E6XXX_CASCADE_PORT_NONE 0xe + #define MV88E6XXX_CASCADE_PORT_MULTIPLE 0xf +--- a/drivers/net/dsa/mv88e6xxx/global1.c ++++ b/drivers/net/dsa/mv88e6xxx/global1.c +@@ -294,7 +294,9 @@ int mv88e6250_g1_ieee_pri_map(struct mv8 + /* Offset 0x1a: Monitor Control */ + /* Offset 0x1a: Monitor & MGMT Control on some devices */ + +-int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) ++int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, ++ enum mv88e6xxx_egress_direction direction, ++ int port) + { + u16 reg; + int err; +@@ -303,11 +305,20 @@ int mv88e6095_g1_set_egress_port(struct + if (err) + return err; + +- reg &= ~(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK | +- MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); +- +- reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK) | +- port << __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); ++ switch (direction) { ++ case MV88E6XXX_EGRESS_DIR_INGRESS: ++ reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK; ++ reg |= port << ++ __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK); ++ break; ++ case MV88E6XXX_EGRESS_DIR_EGRESS: ++ reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK; ++ reg |= port << ++ __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); ++ break; ++ default: ++ return -EINVAL; ++ } + + return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); + } +@@ -341,17 +352,24 @@ static int mv88e6390_g1_monitor_write(st + return mv88e6xxx_g1_write(chip, MV88E6390_G1_MONITOR_MGMT_CTL, reg); + } + +-int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) ++int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, ++ enum mv88e6xxx_egress_direction direction, ++ int port) + { + u16 ptr; + int err; + +- ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; +- err = mv88e6390_g1_monitor_write(chip, ptr, port); +- if (err) +- return err; ++ switch (direction) { ++ case MV88E6XXX_EGRESS_DIR_INGRESS: ++ ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; ++ break; ++ case MV88E6XXX_EGRESS_DIR_EGRESS: ++ ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; ++ break; ++ default: ++ return -EINVAL; ++ } + +- ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; + err = mv88e6390_g1_monitor_write(chip, ptr, port); + if (err) + return err; +--- a/drivers/net/dsa/mv88e6xxx/global1.h ++++ b/drivers/net/dsa/mv88e6xxx/global1.h +@@ -289,8 +289,12 @@ int mv88e6095_g1_stats_set_histogram(str + int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip); + void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val); + int mv88e6xxx_g1_stats_clear(struct mv88e6xxx_chip *chip); +-int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port); +-int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port); ++int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, ++ enum mv88e6xxx_egress_direction direction, ++ int port); ++int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, ++ enum mv88e6xxx_egress_direction direction, ++ int port); + int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); + int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); + int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); diff --git a/ipq806x/backport-5.4/747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch b/ipq806x/backport-5.4/747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch new file mode 100644 index 0000000..a23f450 --- /dev/null +++ b/ipq806x/backport-5.4/747-v5.5-net-dsa-mv88e6xxx-Add-support-for-port-mirroring.patch @@ -0,0 +1,266 @@ +From f0942e00a1abb6404ca4302c66497fc623676c11 Mon Sep 17 00:00:00 2001 +From: Iwan R Timmer +Date: Thu, 7 Nov 2019 22:11:14 +0100 +Subject: [PATCH] net: dsa: mv88e6xxx: Add support for port mirroring + +Add support for configuring port mirroring through the cls_matchall +classifier. We do a full ingress and/or egress capture towards a +capture port. It allows setting a different capture port for ingress +and egress traffic. + +It keeps track of the mirrored ports and the destination ports to +prevent changes to the capture port while other ports are being +mirrored. + +Signed-off-by: Iwan R Timmer +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mv88e6xxx/chip.c | 76 +++++++++++++++++++++++++++++ + drivers/net/dsa/mv88e6xxx/chip.h | 6 +++ + drivers/net/dsa/mv88e6xxx/global1.c | 18 +++++-- + drivers/net/dsa/mv88e6xxx/port.c | 37 ++++++++++++++ + drivers/net/dsa/mv88e6xxx/port.h | 3 ++ + 5 files changed, 136 insertions(+), 4 deletions(-) + +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -4926,6 +4926,80 @@ static int mv88e6xxx_port_mdb_del(struct + return err; + } + ++static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress) ++{ ++ enum mv88e6xxx_egress_direction direction = ingress ? ++ MV88E6XXX_EGRESS_DIR_INGRESS : ++ MV88E6XXX_EGRESS_DIR_EGRESS; ++ struct mv88e6xxx_chip *chip = ds->priv; ++ bool other_mirrors = false; ++ int i; ++ int err; ++ ++ if (!chip->info->ops->set_egress_port) ++ return -EOPNOTSUPP; ++ ++ mutex_lock(&chip->reg_lock); ++ if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != ++ mirror->to_local_port) { ++ for (i = 0; i < mv88e6xxx_num_ports(chip); i++) ++ other_mirrors |= ingress ? ++ chip->ports[i].mirror_ingress : ++ chip->ports[i].mirror_egress; ++ ++ /* Can't change egress port when other mirror is active */ ++ if (other_mirrors) { ++ err = -EBUSY; ++ goto out; ++ } ++ ++ err = chip->info->ops->set_egress_port(chip, ++ direction, ++ mirror->to_local_port); ++ if (err) ++ goto out; ++ } ++ ++ err = mv88e6xxx_port_set_mirror(chip, port, direction, true); ++out: ++ mutex_unlock(&chip->reg_lock); ++ ++ return err; ++} ++ ++static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror) ++{ ++ enum mv88e6xxx_egress_direction direction = mirror->ingress ? ++ MV88E6XXX_EGRESS_DIR_INGRESS : ++ MV88E6XXX_EGRESS_DIR_EGRESS; ++ struct mv88e6xxx_chip *chip = ds->priv; ++ bool other_mirrors = false; ++ int i; ++ ++ mutex_lock(&chip->reg_lock); ++ if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) ++ dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); ++ ++ for (i = 0; i < mv88e6xxx_num_ports(chip); i++) ++ other_mirrors |= mirror->ingress ? ++ chip->ports[i].mirror_ingress : ++ chip->ports[i].mirror_egress; ++ ++ /* Reset egress port when no other mirror is active */ ++ if (!other_mirrors) { ++ if (chip->info->ops->set_egress_port(chip, ++ direction, ++ dsa_upstream_port(ds, ++ port))); ++ dev_err(ds->dev, "failed to set egress port\n"); ++ } ++ ++ mutex_unlock(&chip->reg_lock); ++} ++ + static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, + bool unicast, bool multicast) + { +@@ -4980,6 +5054,8 @@ static const struct dsa_switch_ops mv88e + .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, + .port_mdb_add = mv88e6xxx_port_mdb_add, + .port_mdb_del = mv88e6xxx_port_mdb_del, ++ .port_mirror_add = mv88e6xxx_port_mirror_add, ++ .port_mirror_del = mv88e6xxx_port_mirror_del, + .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, + .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, + .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, +--- a/drivers/net/dsa/mv88e6xxx/chip.h ++++ b/drivers/net/dsa/mv88e6xxx/chip.h +@@ -232,6 +232,8 @@ struct mv88e6xxx_port { + u64 vtu_member_violation; + u64 vtu_miss_violation; + u8 cmode; ++ bool mirror_ingress; ++ bool mirror_egress; + unsigned int serdes_irq; + }; + +@@ -315,6 +317,10 @@ struct mv88e6xxx_chip { + u16 evcap_config; + u16 enable_count; + ++ /* Current ingress and egress monitor ports */ ++ int egress_dest_port; ++ int ingress_dest_port; ++ + /* Per-port timestamping resources. */ + struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS]; + +--- a/drivers/net/dsa/mv88e6xxx/global1.c ++++ b/drivers/net/dsa/mv88e6xxx/global1.c +@@ -298,6 +298,7 @@ int mv88e6095_g1_set_egress_port(struct + enum mv88e6xxx_egress_direction direction, + int port) + { ++ int *dest_port_chip; + u16 reg; + int err; + +@@ -307,11 +308,13 @@ int mv88e6095_g1_set_egress_port(struct + + switch (direction) { + case MV88E6XXX_EGRESS_DIR_INGRESS: ++ dest_port_chip = &chip->ingress_dest_port; + reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK; + reg |= port << + __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK); + break; + case MV88E6XXX_EGRESS_DIR_EGRESS: ++ dest_port_chip = &chip->egress_dest_port; + reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK; + reg |= port << + __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); +@@ -320,7 +323,11 @@ int mv88e6095_g1_set_egress_port(struct + return -EINVAL; + } + +- return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); ++ err = mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); ++ if (!err) ++ *dest_port_chip = port; ++ ++ return err; + } + + /* Older generations also call this the ARP destination. It has been +@@ -356,14 +363,17 @@ int mv88e6390_g1_set_egress_port(struct + enum mv88e6xxx_egress_direction direction, + int port) + { ++ int *dest_port_chip; + u16 ptr; + int err; + + switch (direction) { + case MV88E6XXX_EGRESS_DIR_INGRESS: ++ dest_port_chip = &chip->ingress_dest_port; + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; + break; + case MV88E6XXX_EGRESS_DIR_EGRESS: ++ dest_port_chip = &chip->egress_dest_port; + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; + break; + default: +@@ -371,10 +381,10 @@ int mv88e6390_g1_set_egress_port(struct + } + + err = mv88e6390_g1_monitor_write(chip, ptr, port); +- if (err) +- return err; ++ if (!err) ++ *dest_port_chip = port; + +- return 0; ++ return err; + } + + int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) +--- a/drivers/net/dsa/mv88e6xxx/port.c ++++ b/drivers/net/dsa/mv88e6xxx/port.c +@@ -1181,6 +1181,43 @@ int mv88e6095_port_set_upstream_port(str + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); + } + ++int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port, ++ enum mv88e6xxx_egress_direction direction, ++ bool mirror) ++{ ++ bool *mirror_port; ++ u16 reg; ++ u16 bit; ++ int err; ++ ++ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); ++ if (err) ++ return err; ++ ++ switch (direction) { ++ case MV88E6XXX_EGRESS_DIR_INGRESS: ++ bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR; ++ mirror_port = &chip->ports[port].mirror_ingress; ++ break; ++ case MV88E6XXX_EGRESS_DIR_EGRESS: ++ bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR; ++ mirror_port = &chip->ports[port].mirror_egress; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ reg &= ~bit; ++ if (mirror) ++ reg |= bit; ++ ++ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); ++ if (!err) ++ *mirror_port = mirror; ++ ++ return err; ++} ++ + int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, + u16 mode) + { +--- a/drivers/net/dsa/mv88e6xxx/port.h ++++ b/drivers/net/dsa/mv88e6xxx/port.h +@@ -368,6 +368,9 @@ int mv88e6352_port_link_state(struct mv8 + int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port); + int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, + int upstream_port); ++int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port, ++ enum mv88e6xxx_egress_direction direction, ++ bool mirror); + + int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port); + int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port); diff --git a/ipq806x/backport-5.4/748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch b/ipq806x/backport-5.4/748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch new file mode 100644 index 0000000..37e7a7f --- /dev/null +++ b/ipq806x/backport-5.4/748-v5.5-net-dsa-mv88e6xxx-fix-broken-if-statement-because-of.patch @@ -0,0 +1,30 @@ +From 4e4637b10374ede3cd33d7e1b389e6cea6343ea3 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Tue, 12 Nov 2019 13:05:23 +0000 +Subject: [PATCH] net: dsa: mv88e6xxx: fix broken if statement because of a + stray semicolon + +There is a stray semicolon in an if statement that will cause a dev_err +message to be printed unconditionally. Fix this by removing the stray +semicolon. + +Addresses-Coverity: ("Stay semicolon") +Fixes: f0942e00a1ab ("net: dsa: mv88e6xxx: Add support for port mirroring") +Signed-off-by: Colin Ian King +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mv88e6xxx/chip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -4993,7 +4993,7 @@ static void mv88e6xxx_port_mirror_del(st + if (chip->info->ops->set_egress_port(chip, + direction, + dsa_upstream_port(ds, +- port))); ++ port))) + dev_err(ds->dev, "failed to set egress port\n"); + } + diff --git a/ipq806x/backport-5.4/749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch b/ipq806x/backport-5.4/749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch new file mode 100644 index 0000000..497a808 --- /dev/null +++ b/ipq806x/backport-5.4/749-v5.5-net-dsa-mv88e6xxx-Fix-masking-of-egress-port.patch @@ -0,0 +1,34 @@ +From 3ee339eb28959629db33aaa2b8cde4c63c6289eb Mon Sep 17 00:00:00 2001 +From: Andrew Lunn +Date: Thu, 27 Feb 2020 21:20:49 +0100 +Subject: [PATCH] net: dsa: mv88e6xxx: Fix masking of egress port + +Add missing ~ to the usage of the mask. + +Reported-by: Kevin Benson +Reported-by: Chris Healy +Fixes: 5c74c54ce6ff ("net: dsa: mv88e6xxx: Split monitor port configuration") +Signed-off-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mv88e6xxx/global1.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/mv88e6xxx/global1.c ++++ b/drivers/net/dsa/mv88e6xxx/global1.c +@@ -309,13 +309,13 @@ int mv88e6095_g1_set_egress_port(struct + switch (direction) { + case MV88E6XXX_EGRESS_DIR_INGRESS: + dest_port_chip = &chip->ingress_dest_port; +- reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK; ++ reg &= ~MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK; + reg |= port << + __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK); + break; + case MV88E6XXX_EGRESS_DIR_EGRESS: + dest_port_chip = &chip->egress_dest_port; +- reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK; ++ reg &= ~MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK; + reg |= port << + __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); + break; diff --git a/ipq806x/backport-5.4/750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch b/ipq806x/backport-5.4/750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch new file mode 100644 index 0000000..69c56ec --- /dev/null +++ b/ipq806x/backport-5.4/750-v5.5-net-phy-add-support-for-clause-37-auto-negotiation.patch @@ -0,0 +1,195 @@ +From fa6e98cee558622565c97924e922b97340aeabd8 Mon Sep 17 00:00:00 2001 +From: Heiner Kallweit +Date: Tue, 22 Oct 2019 11:31:07 -0700 +Subject: [PATCH] net: phy: add support for clause 37 auto-negotiation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds support for clause 37 1000Base-X auto-negotiation. + +Signed-off-by: Heiner Kallweit +Signed-off-by: Tao Ren +Tested-by: René van Dorst +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/phy_device.c | 139 +++++++++++++++++++++++++++++++++++ + include/linux/phy.h | 4 + + 2 files changed, 143 insertions(+) + +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1682,6 +1682,40 @@ static int genphy_config_advert(struct p + } + + /** ++ * genphy_c37_config_advert - sanitize and advertise auto-negotiation parameters ++ * @phydev: target phy_device struct ++ * ++ * Description: Writes MII_ADVERTISE with the appropriate values, ++ * after sanitizing the values to make sure we only advertise ++ * what is supported. Returns < 0 on error, 0 if the PHY's advertisement ++ * hasn't changed, and > 0 if it has changed. This function is intended ++ * for Clause 37 1000Base-X mode. ++ */ ++static int genphy_c37_config_advert(struct phy_device *phydev) ++{ ++ u16 adv = 0; ++ ++ /* Only allow advertising what this PHY supports */ ++ linkmode_and(phydev->advertising, phydev->advertising, ++ phydev->supported); ++ ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, ++ phydev->advertising)) ++ adv |= ADVERTISE_1000XFULL; ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, ++ phydev->advertising)) ++ adv |= ADVERTISE_1000XPAUSE; ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, ++ phydev->advertising)) ++ adv |= ADVERTISE_1000XPSE_ASYM; ++ ++ return phy_modify_changed(phydev, MII_ADVERTISE, ++ ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | ++ ADVERTISE_1000XHALF | ADVERTISE_1000XPSE_ASYM, ++ adv); ++} ++ ++/** + * genphy_config_eee_advert - disable unwanted eee mode advertisement + * @phydev: target phy_device struct + * +@@ -1790,6 +1824,54 @@ int __genphy_config_aneg(struct phy_devi + EXPORT_SYMBOL(__genphy_config_aneg); + + /** ++ * genphy_c37_config_aneg - restart auto-negotiation or write BMCR ++ * @phydev: target phy_device struct ++ * ++ * Description: If auto-negotiation is enabled, we configure the ++ * advertising, and then restart auto-negotiation. If it is not ++ * enabled, then we write the BMCR. This function is intended ++ * for use with Clause 37 1000Base-X mode. ++ */ ++int genphy_c37_config_aneg(struct phy_device *phydev) ++{ ++ int err, changed; ++ ++ if (phydev->autoneg != AUTONEG_ENABLE) ++ return genphy_setup_forced(phydev); ++ ++ err = phy_modify(phydev, MII_BMCR, BMCR_SPEED1000 | BMCR_SPEED100, ++ BMCR_SPEED1000); ++ if (err) ++ return err; ++ ++ changed = genphy_c37_config_advert(phydev); ++ if (changed < 0) /* error */ ++ return changed; ++ ++ if (!changed) { ++ /* Advertisement hasn't changed, but maybe aneg was never on to ++ * begin with? Or maybe phy was isolated? ++ */ ++ int ctl = phy_read(phydev, MII_BMCR); ++ ++ if (ctl < 0) ++ return ctl; ++ ++ if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) ++ changed = 1; /* do restart aneg */ ++ } ++ ++ /* Only restart aneg if we are advertising something different ++ * than we were before. ++ */ ++ if (changed > 0) ++ return genphy_restart_aneg(phydev); ++ ++ return 0; ++} ++EXPORT_SYMBOL(genphy_c37_config_aneg); ++ ++/** + * genphy_aneg_done - return auto-negotiation status + * @phydev: target phy_device struct + * +@@ -1962,6 +2044,63 @@ int genphy_read_status(struct phy_device + EXPORT_SYMBOL(genphy_read_status); + + /** ++ * genphy_c37_read_status - check the link status and update current link state ++ * @phydev: target phy_device struct ++ * ++ * Description: Check the link, then figure out the current state ++ * by comparing what we advertise with what the link partner ++ * advertises. This function is for Clause 37 1000Base-X mode. ++ */ ++int genphy_c37_read_status(struct phy_device *phydev) ++{ ++ int lpa, err, old_link = phydev->link; ++ ++ /* Update the link, but return if there was an error */ ++ err = genphy_update_link(phydev); ++ if (err) ++ return err; ++ ++ /* why bother the PHY if nothing can have changed */ ++ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) ++ return 0; ++ ++ phydev->duplex = DUPLEX_UNKNOWN; ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { ++ lpa = phy_read(phydev, MII_LPA); ++ if (lpa < 0) ++ return lpa; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, ++ phydev->lp_advertising, lpa & LPA_LPACK); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, ++ phydev->lp_advertising, lpa & LPA_1000XFULL); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, ++ phydev->lp_advertising, lpa & LPA_1000XPAUSE); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, ++ phydev->lp_advertising, ++ lpa & LPA_1000XPAUSE_ASYM); ++ ++ phy_resolve_aneg_linkmode(phydev); ++ } else if (phydev->autoneg == AUTONEG_DISABLE) { ++ int bmcr = phy_read(phydev, MII_BMCR); ++ ++ if (bmcr < 0) ++ return bmcr; ++ ++ if (bmcr & BMCR_FULLDPLX) ++ phydev->duplex = DUPLEX_FULL; ++ else ++ phydev->duplex = DUPLEX_HALF; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(genphy_c37_read_status); ++ ++/** + * genphy_soft_reset - software reset the PHY via BMCR_RESET bit + * @phydev: target phy_device struct + * +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -1120,6 +1120,10 @@ int genphy_read_mmd_unsupported(struct p + int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, + u16 regnum, u16 val); + ++/* Clause 37 */ ++int genphy_c37_config_aneg(struct phy_device *phydev); ++int genphy_c37_read_status(struct phy_device *phydev); ++ + /* 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); diff --git a/ipq806x/backport-5.4/751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch b/ipq806x/backport-5.4/751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch new file mode 100644 index 0000000..6d51de8 --- /dev/null +++ b/ipq806x/backport-5.4/751-v5.6-net-mvmdio-avoid-error-message-for-optional-IRQ.patch @@ -0,0 +1,33 @@ +From fa2632f74e57bbc869c8ad37751a11b6147a3acc Mon Sep 17 00:00:00 2001 +From: Chris Packham +Date: Mon, 16 Mar 2020 20:49:07 +1300 +Subject: [PATCH] net: mvmdio: avoid error message for optional IRQ + +Per the dt-binding the interrupt is optional so use +platform_get_irq_optional() instead of platform_get_irq(). Since +commit 7723f4c5ecdb ("driver core: platform: Add an error message to +platform_get_irq*()") platform_get_irq() produces an error message + + orion-mdio f1072004.mdio: IRQ index 0 not found + +which is perfectly normal if one hasn't specified the optional property +in the device tree. + +Signed-off-by: Chris Packham +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/mvmdio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/marvell/mvmdio.c ++++ b/drivers/net/ethernet/marvell/mvmdio.c +@@ -347,7 +347,7 @@ static int orion_mdio_probe(struct platf + } + + +- dev->err_interrupt = platform_get_irq(pdev, 0); ++ dev->err_interrupt = platform_get_irq_optional(pdev, 0); + if (dev->err_interrupt > 0 && + resource_size(r) < MVMDIO_ERR_INT_MASK + 4) { + dev_err(&pdev->dev, diff --git a/ipq806x/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch b/ipq806x/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch new file mode 100644 index 0000000..52d9351 --- /dev/null +++ b/ipq806x/backport-5.4/752-v5.8-net-dsa-provide-an-option-for-drivers-to-always-rece.patch @@ -0,0 +1,121 @@ +From 54a0ed0df49609f4e3f098f8943e38e389dc2e15 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 12 May 2020 20:20:25 +0300 +Subject: net: dsa: provide an option for drivers to always receive bridge + VLANs + +DSA assumes that a bridge which has vlan filtering disabled is not +vlan aware, and ignores all vlan configuration. However, the kernel +software bridge code allows configuration in this state. + +This causes the kernel's idea of the bridge vlan state and the +hardware state to disagree, so "bridge vlan show" indicates a correct +configuration but the hardware lacks all configuration. Even worse, +enabling vlan filtering on a DSA bridge immediately blocks all traffic +which, given the output of "bridge vlan show", is very confusing. + +Provide an option that drivers can set to indicate they want to receive +vlan configuration even when vlan filtering is disabled. At the very +least, this is safe for Marvell DSA bridges, which do not look up +ingress traffic in the VTU if the port is in 8021Q disabled state. It is +also safe for the Ocelot switch family. Whether this change is suitable +for all DSA bridges is not known. + +Signed-off-by: Russell King +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 7 +++++++ + net/dsa/dsa_priv.h | 1 + + net/dsa/port.c | 14 ++++++++++++++ + net/dsa/slave.c | 8 ++++---- + 4 files changed, 26 insertions(+), 4 deletions(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -270,6 +270,13 @@ struct dsa_switch { + */ + bool vlan_filtering_is_global; + ++ /* Pass .port_vlan_add and .port_vlan_del to drivers even for bridges ++ * that have vlan_filtering=0. All drivers should ideally set this (and ++ * then the option would get removed), but it is unknown whether this ++ * would break things or not. ++ */ ++ bool configure_vlan_while_not_filtering; ++ + /* In case vlan_filtering_is_global is set, the VLAN awareness state + * should be retrieved from here and not from the per-port settings. + */ +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -139,6 +139,7 @@ int dsa_port_bridge_join(struct dsa_port + void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br); + int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, + struct switchdev_trans *trans); ++bool dsa_port_skip_vlan_configuration(struct dsa_port *dp); + int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, + struct switchdev_trans *trans); + int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -238,6 +238,20 @@ int dsa_port_vlan_filtering(struct dsa_p + return 0; + } + ++/* This enforces legacy behavior for switch drivers which assume they can't ++ * receive VLAN configuration when enslaved to a bridge with vlan_filtering=0 ++ */ ++bool dsa_port_skip_vlan_configuration(struct dsa_port *dp) ++{ ++ struct dsa_switch *ds = dp->ds; ++ ++ if (!dp->bridge_dev) ++ return false; ++ ++ return (!ds->configure_vlan_while_not_filtering && ++ !br_vlan_enabled(dp->bridge_dev)); ++} ++ + int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, + struct switchdev_trans *trans) + { +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -319,7 +319,7 @@ static int dsa_slave_vlan_add(struct net + if (obj->orig_dev != dev) + return -EOPNOTSUPP; + +- if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev)) ++ if (dsa_port_skip_vlan_configuration(dp)) + return 0; + + vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj); +@@ -386,7 +386,7 @@ static int dsa_slave_vlan_del(struct net + if (obj->orig_dev != dev) + return -EOPNOTSUPP; + +- if (dp->bridge_dev && !br_vlan_enabled(dp->bridge_dev)) ++ if (dsa_port_skip_vlan_configuration(dp)) + return 0; + + /* Do not deprogram the CPU port as it may be shared with other user +@@ -1120,7 +1120,7 @@ static int dsa_slave_vlan_rx_add_vid(str + * need to emulate the switchdev prepare + commit phase. + */ + if (dp->bridge_dev) { +- if (!br_vlan_enabled(dp->bridge_dev)) ++ if (dsa_port_skip_vlan_configuration(dp)) + return 0; + + /* br_vlan_get_info() returns -EINVAL or -ENOENT if the +@@ -1154,7 +1154,7 @@ static int dsa_slave_vlan_rx_kill_vid(st + * need to emulate the switchdev prepare + commit phase. + */ + if (dp->bridge_dev) { +- if (!br_vlan_enabled(dp->bridge_dev)) ++ if (dsa_port_skip_vlan_configuration(dp)) + return 0; + + /* br_vlan_get_info() returns -EINVAL or -ENOENT if the diff --git a/ipq806x/backport-5.4/753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch b/ipq806x/backport-5.4/753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch new file mode 100644 index 0000000..0804cea --- /dev/null +++ b/ipq806x/backport-5.4/753-v5.8-net-dsa-mt7530-fix-VLAN-setup.patch @@ -0,0 +1,51 @@ +From 0141792f8b7300006b874dda1c35acd0abd90d9d Mon Sep 17 00:00:00 2001 +From: DENG Qingfang +Date: Fri, 15 May 2020 23:25:55 +0800 +Subject: net: dsa: mt7530: fix VLAN setup + +Allow DSA to add VLAN entries even if VLAN filtering is disabled, so +enabling it will not block the traffic of existent ports in the bridge + +Signed-off-by: DENG Qingfang +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1083,12 +1083,6 @@ mt7530_port_vlan_add(struct dsa_switch * + struct mt7530_priv *priv = ds->priv; + u16 vid; + +- /* The port is kept as VLAN-unaware if bridge with vlan_filtering not +- * being set. +- */ +- if (!dsa_port_is_vlan_filtering(&ds->ports[port])) +- return; +- + mutex_lock(&priv->reg_mutex); + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { +@@ -1114,12 +1108,6 @@ mt7530_port_vlan_del(struct dsa_switch * + struct mt7530_priv *priv = ds->priv; + u16 vid, pvid; + +- /* The port is kept as VLAN-unaware if bridge with vlan_filtering not +- * being set. +- */ +- if (!dsa_port_is_vlan_filtering(&ds->ports[port])) +- return 0; +- + mutex_lock(&priv->reg_mutex); + + pvid = priv->ports[port].pvid; +@@ -1232,6 +1220,7 @@ mt7530_setup(struct dsa_switch *ds) + * as two netdev instances. + */ + dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent; ++ ds->configure_vlan_while_not_filtering = true; + + if (priv->id == ID_MT7530) { + regulator_set_voltage(priv->core_pwr, 1000000, 1000000); diff --git a/ipq806x/backport-5.4/756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch b/ipq806x/backport-5.4/756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch new file mode 100644 index 0000000..b0ab598 --- /dev/null +++ b/ipq806x/backport-5.4/756-v5.8-net-dsa-rtl8366-Pass-GENMASK-signed-bits.patch @@ -0,0 +1,27 @@ +From 733993f502f254912b1415e13f73651d9f2e74ef Mon Sep 17 00:00:00 2001 +From: Andrew Lunn +Date: Sun, 5 Jul 2020 22:42:27 +0200 +Subject: [PATCH 1/5] net: dsa: rtl8366: Pass GENMASK() signed bits + +Oddly, GENMASK() requires signed bit numbers, so that it can compare +them for < 0. If passed an unsigned type, we get warnings about the +test never being true. + +Signed-off-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/rtl8366.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/rtl8366.c ++++ b/drivers/net/dsa/rtl8366.c +@@ -311,7 +311,7 @@ int rtl8366_init_vlan(struct realtek_smi + /* For the CPU port, make all ports members of this + * VLAN. + */ +- mask = GENMASK(smi->num_ports - 1, 0); ++ mask = GENMASK((int)smi->num_ports - 1, 0); + else + /* For all other ports, enable itself plus the + * CPU port. diff --git a/ipq806x/backport-5.4/757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch b/ipq806x/backport-5.4/757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch new file mode 100644 index 0000000..70d7000 --- /dev/null +++ b/ipq806x/backport-5.4/757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch @@ -0,0 +1,232 @@ +From 078ced30af696b52a450a016a16eb47499d68117 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 8 Jul 2020 14:25:36 +0200 +Subject: [PATCH 2/5] net: dsa: tag_rtl4_a: Implement Realtek 4 byte A tag + +This implements the known parts of the Realtek 4 byte +tag protocol version 0xA, as found in the RTL8366RB +DSA switch. + +It is designated as protocol version 0xA as a +different Realtek 4 byte tag format with protocol +version 0x9 is known to exist in the Realtek RTL8306 +chips. + +The tag and switch chip lacks public documentation, so +the tag format has been reverse-engineered from +packet dumps. As only ingress traffic has been available +for analysis an egress tag has not been possible to +develop (even using educated guesses about bit fields) +so this is as far as it gets. It is not known if the +switch even supports egress tagging. + +Excessive attempts to figure out the egress tag format +was made. When nothing else worked, I just tried all bit +combinations with 0xannp where a is protocol and p is +port. I looped through all values several times trying +to get a response from ping, without any positive +result. + +Using just these ingress tags however, the switch +functionality is vastly improved and the packets find +their way into the destination port without any +tricky VLAN configuration. On the D-Link DIR-685 the +LAN ports now come up and respond to ping without +any command line configuration so this is a real +improvement for users. + +Egress packets need to be restricted to the proper +target ports using VLAN, which the RTL8366RB DSA +switch driver already sets up. + +Cc: DENG Qingfang +Cc: Mauri Sandberg +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 2 + + net/dsa/Kconfig | 7 +++ + net/dsa/Makefile | 1 + + net/dsa/tag_rtl4_a.c | 130 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 140 insertions(+) + create mode 100644 net/dsa/tag_rtl4_a.c + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -42,6 +42,7 @@ struct phylink_link_state; + #define DSA_TAG_PROTO_8021Q_VALUE 12 + #define DSA_TAG_PROTO_SJA1105_VALUE 13 + #define DSA_TAG_PROTO_KSZ8795_VALUE 14 ++#define DSA_TAG_PROTO_RTL4_A_VALUE 17 + + enum dsa_tag_protocol { + DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE, +@@ -59,6 +60,7 @@ enum dsa_tag_protocol { + DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE, + DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE, + DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE, ++ DSA_TAG_PROTO_RTL4_A = DSA_TAG_PROTO_RTL4_A_VALUE, + }; + + struct packet_type; +--- a/net/dsa/Kconfig ++++ b/net/dsa/Kconfig +@@ -80,6 +80,13 @@ config NET_DSA_TAG_KSZ + Say Y if you want to enable support for tagging frames for the + Microchip 8795/9477/9893 families of switches. + ++config NET_DSA_TAG_RTL4_A ++ tristate "Tag driver for Realtek 4 byte protocol A tags" ++ help ++ Say Y or M if you want to enable support for tagging frames for the ++ Realtek switches with 4 byte protocol A tags, sich as found in ++ the Realtek RTL8366RB. ++ + config NET_DSA_TAG_QCA + tristate "Tag driver for Qualcomm Atheros QCA8K switches" + help +--- a/net/dsa/Makefile ++++ b/net/dsa/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa + obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o + obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o + obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o ++obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o + obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o + obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o + obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o +--- /dev/null ++++ b/net/dsa/tag_rtl4_a.c +@@ -0,0 +1,130 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Handler for Realtek 4 byte DSA switch tags ++ * Currently only supports protocol "A" found in RTL8366RB ++ * Copyright (c) 2020 Linus Walleij ++ * ++ * This "proprietary tag" header looks like so: ++ * ++ * ------------------------------------------------- ++ * | MAC DA | MAC SA | 0x8899 | 2 bytes tag | Type | ++ * ------------------------------------------------- ++ * ++ * The 2 bytes tag form a 16 bit big endian word. The exact ++ * meaning has been guessed from packet dumps from ingress ++ * frames, as no working egress traffic has been available ++ * we do not know the format of the egress tags or if they ++ * are even supported. ++ */ ++ ++#include ++#include ++ ++#include "dsa_priv.h" ++ ++#define RTL4_A_HDR_LEN 4 ++#define RTL4_A_ETHERTYPE 0x8899 ++#define RTL4_A_PROTOCOL_SHIFT 12 ++/* ++ * 0x1 = Realtek Remote Control protocol (RRCP) ++ * 0x2/0x3 seems to be used for loopback testing ++ * 0x9 = RTL8306 DSA protocol ++ * 0xa = RTL8366RB DSA protocol ++ */ ++#define RTL4_A_PROTOCOL_RTL8366RB 0xa ++ ++static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ /* ++ * Just let it pass thru, we don't know if it is possible ++ * to tag a frame with the 0x8899 ethertype and direct it ++ * to a specific port, all attempts at reverse-engineering have ++ * ended up with the frames getting dropped. ++ * ++ * The VLAN set-up needs to restrict the frames to the right port. ++ * ++ * If you have documentation on the tagging format for RTL8366RB ++ * (tag type A) then please contribute. ++ */ ++ return skb; ++} ++ ++static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb, ++ struct net_device *dev, ++ struct packet_type *pt) ++{ ++ u16 protport; ++ __be16 *p; ++ u16 etype; ++ u8 *tag; ++ u8 prot; ++ u8 port; ++ ++ if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN))) ++ return NULL; ++ ++ /* The RTL4 header has its own custom Ethertype 0x8899 and that ++ * starts right at the beginning of the packet, after the src ++ * ethernet addr. Apparantly skb->data always points 2 bytes in, ++ * behind the Ethertype. ++ */ ++ tag = skb->data - 2; ++ p = (__be16 *)tag; ++ etype = ntohs(*p); ++ if (etype != RTL4_A_ETHERTYPE) { ++ /* Not custom, just pass through */ ++ netdev_dbg(dev, "non-realtek ethertype 0x%04x\n", etype); ++ return skb; ++ } ++ p = (__be16 *)(tag + 2); ++ protport = ntohs(*p); ++ /* The 4 upper bits are the protocol */ ++ prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f; ++ if (prot != RTL4_A_PROTOCOL_RTL8366RB) { ++ netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot); ++ return NULL; ++ } ++ port = protport & 0xff; ++ ++ skb->dev = dsa_master_find_slave(dev, 0, port); ++ if (!skb->dev) { ++ netdev_dbg(dev, "could not find slave for port %d\n", port); ++ return NULL; ++ } ++ ++ /* Remove RTL4 tag and recalculate checksum */ ++ skb_pull_rcsum(skb, RTL4_A_HDR_LEN); ++ ++ /* Move ethernet DA and SA in front of the data */ ++ memmove(skb->data - ETH_HLEN, ++ skb->data - ETH_HLEN - RTL4_A_HDR_LEN, ++ 2 * ETH_ALEN); ++ ++ skb->offload_fwd_mark = 1; ++ ++ return skb; ++} ++ ++static int rtl4a_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto, ++ int *offset) ++{ ++ *offset = RTL4_A_HDR_LEN; ++ /* Skip past the tag and fetch the encapsulated Ethertype */ ++ *proto = ((__be16 *)skb->data)[1]; ++ ++ return 0; ++} ++ ++static const struct dsa_device_ops rtl4a_netdev_ops = { ++ .name = "rtl4a", ++ .proto = DSA_TAG_PROTO_RTL4_A, ++ .xmit = rtl4a_tag_xmit, ++ .rcv = rtl4a_tag_rcv, ++ .flow_dissect = rtl4a_tag_flow_dissect, ++ .overhead = RTL4_A_HDR_LEN, ++}; ++module_dsa_tag_driver(rtl4a_netdev_ops); ++ ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL4_A); diff --git a/ipq806x/backport-5.4/758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch b/ipq806x/backport-5.4/758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch new file mode 100644 index 0000000..b68c033 --- /dev/null +++ b/ipq806x/backport-5.4/758-v5.8-net-dsa-rtl8366rb-Support-the-CPU-DSA-tag.patch @@ -0,0 +1,100 @@ +From c633ba43b7a9c2bfdb992ffd198d4c661520466f Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 8 Jul 2020 14:25:37 +0200 +Subject: [PATCH 3/5] net: dsa: rtl8366rb: Support the CPU DSA tag + +This activates the support to use the CPU tag to properly +direct ingress traffic to the right port. + +Bit 15 in register RTL8368RB_CPU_CTRL_REG can be set to +1 to disable the insertion of the CPU tag which is what +the code currently does. The bit 15 define calls this +setting RTL8368RB_CPU_INSTAG which is confusing since the +inverse meaning is implied: programmers may think that +setting this bit to 1 will *enable* inserting the tag +rather than disabling it, so rename this setting in +bit 15 to RTL8368RB_CPU_NO_TAG which is more to the +point. + +After this e.g. ping works out-of-the-box with the +RTL8366RB. + +Cc: DENG Qingfang +Cc: Mauri Sandberg +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/Kconfig | 1 + + drivers/net/dsa/rtl8366rb.c | 31 ++++++++----------------------- + 2 files changed, 9 insertions(+), 23 deletions(-) + +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -66,6 +66,7 @@ config NET_DSA_QCA8K + config NET_DSA_REALTEK_SMI + tristate "Realtek SMI Ethernet switch family support" + depends on NET_DSA ++ select NET_DSA_TAG_RTL4_A + select FIXED_PHY + select IRQ_DOMAIN + select REALTEK_PHY +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -109,8 +109,8 @@ + /* CPU port control reg */ + #define RTL8368RB_CPU_CTRL_REG 0x0061 + #define RTL8368RB_CPU_PORTS_MSK 0x00FF +-/* Enables inserting custom tag length/type 0x8899 */ +-#define RTL8368RB_CPU_INSTAG BIT(15) ++/* Disables inserting custom tag length/type 0x8899 */ ++#define RTL8368RB_CPU_NO_TAG BIT(15) + + #define RTL8366RB_SMAR0 0x0070 /* bits 0..15 */ + #define RTL8366RB_SMAR1 0x0071 /* bits 16..31 */ +@@ -844,16 +844,14 @@ static int rtl8366rb_setup(struct dsa_sw + if (ret) + return ret; + +- /* Enable CPU port and enable inserting CPU tag ++ /* Enable CPU port with custom DSA tag 8899. + * +- * Disabling RTL8368RB_CPU_INSTAG here will change the behaviour +- * of the switch totally and it will start talking Realtek RRCP +- * internally. It is probably possible to experiment with this, +- * but then the kernel needs to understand and handle RRCP first. ++ * If you set RTL8368RB_CPU_NO_TAG (bit 15) in this registers ++ * the custom tag is turned off. + */ + ret = regmap_update_bits(smi->map, RTL8368RB_CPU_CTRL_REG, + 0xFFFF, +- RTL8368RB_CPU_INSTAG | BIT(smi->cpu_port)); ++ BIT(smi->cpu_port)); + if (ret) + return ret; + +@@ -966,21 +964,8 @@ static int rtl8366rb_setup(struct dsa_sw + static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds, + int port) + { +- /* For now, the RTL switches are handled without any custom tags. +- * +- * It is possible to turn on "custom tags" by removing the +- * RTL8368RB_CPU_INSTAG flag when enabling the port but what it +- * does is unfamiliar to DSA: ethernet frames of type 8899, the Realtek +- * Remote Control Protocol (RRCP) start to appear on the CPU port of +- * the device. So this is not the ordinary few extra bytes in the +- * frame. Instead it appears that the switch starts to talk Realtek +- * RRCP internally which means a pretty complex RRCP implementation +- * decoding and responding the RRCP protocol is needed to exploit this. +- * +- * The OpenRRCP project (dormant since 2009) have reverse-egineered +- * parts of the protocol. +- */ +- return DSA_TAG_PROTO_NONE; ++ /* This switch uses the 4 byte protocol A Realtek DSA tag */ ++ return DSA_TAG_PROTO_RTL4_A; + } + + static void rtl8366rb_adjust_link(struct dsa_switch *ds, int port, diff --git a/ipq806x/backport-5.4/760-net-ethernet-mediatek-Integrate-GDM-PSE-setup-operat.patch b/ipq806x/backport-5.4/760-net-ethernet-mediatek-Integrate-GDM-PSE-setup-operat.patch new file mode 100644 index 0000000..e352b03 --- /dev/null +++ b/ipq806x/backport-5.4/760-net-ethernet-mediatek-Integrate-GDM-PSE-setup-operat.patch @@ -0,0 +1,80 @@ +From: MarkLee +Date: Wed, 13 Nov 2019 10:38:42 +0800 +Subject: [PATCH] net: ethernet: mediatek: Integrate GDM/PSE setup operations + +Integrate GDM/PSE setup operations into single function "mtk_gdm_config" + +Signed-off-by: MarkLee +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2232,6 +2232,28 @@ static int mtk_start_dma(struct mtk_eth + return 0; + } + ++static void mtk_gdm_config(struct mtk_eth *eth, u32 config) ++{ ++ int i; ++ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); ++ ++ /* default setup the forward port to send frame to PDMA */ ++ val &= ~0xffff; ++ ++ /* Enable RX checksum */ ++ val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; ++ ++ val |= config; ++ ++ mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); ++ } ++ /* Reset and enable PSE */ ++ mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); ++ mtk_w32(eth, 0, MTK_RST_GL); ++} ++ + static int mtk_open(struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); +@@ -2427,8 +2449,6 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); + mtk_tx_irq_disable(eth, ~0); + mtk_rx_irq_disable(eth, ~0); +- mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); +- mtk_w32(eth, 0, MTK_RST_GL); + + /* FE int grouping */ + mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); +@@ -2437,18 +2457,7 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + +- for (i = 0; i < MTK_MAC_COUNT; i++) { +- u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); +- +- /* setup the forward port to send frame to PDMA */ +- val &= ~0xffff; +- +- /* Enable RX checksum */ +- val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; +- +- /* setup the mac dma */ +- mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); +- } ++ mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); + + return 0; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -84,6 +84,7 @@ + #define MTK_GDMA_ICS_EN BIT(22) + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) ++#define MTK_GDMA_TO_PDMA 0x0 + + /* Unicast Filter MAC Address Register - Low */ + #define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000)) diff --git a/ipq806x/backport-5.4/761-net-ethernet-mediatek-Refine-the-timing-of-GDM-PSE-s.patch b/ipq806x/backport-5.4/761-net-ethernet-mediatek-Refine-the-timing-of-GDM-PSE-s.patch new file mode 100644 index 0000000..d18d9f9 --- /dev/null +++ b/ipq806x/backport-5.4/761-net-ethernet-mediatek-Refine-the-timing-of-GDM-PSE-s.patch @@ -0,0 +1,45 @@ +From: MarkLee +Date: Wed, 13 Nov 2019 10:38:43 +0800 +Subject: [PATCH] net: ethernet: mediatek: Refine the timing of GDM/PSE setup + +Refine the timing of GDM/PSE setup, move it from mtk_hw_init +to mtk_open. This is recommended by the mt762x HW design to +do GDM/PSE setup only after PDMA has been started. + +We exclude mt7628 in mtk_gdm_config function since it is a old IP +and there is no GDM/PSE block on it. + +Signed-off-by: MarkLee +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2236,6 +2236,9 @@ static void mtk_gdm_config(struct mtk_et + { + int i; + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) ++ return; ++ + for (i = 0; i < MTK_MAC_COUNT; i++) { + u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); + +@@ -2274,6 +2277,8 @@ static int mtk_open(struct net_device *d + if (err) + return err; + ++ mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); ++ + napi_enable(ð->tx_napi); + napi_enable(ð->rx_napi); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); +@@ -2457,8 +2462,6 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + +- mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); +- + return 0; + + err_disable_pm: diff --git a/ipq806x/backport-5.4/762-net-ethernet-mediatek-Enable-GDM-GDMA_DROP_ALL-mode.patch b/ipq806x/backport-5.4/762-net-ethernet-mediatek-Enable-GDM-GDMA_DROP_ALL-mode.patch new file mode 100644 index 0000000..e25f121 --- /dev/null +++ b/ipq806x/backport-5.4/762-net-ethernet-mediatek-Enable-GDM-GDMA_DROP_ALL-mode.patch @@ -0,0 +1,33 @@ +From: MarkLee +Date: Wed, 13 Nov 2019 10:38:44 +0800 +Subject: [PATCH] net: ethernet: mediatek: Enable GDM GDMA_DROP_ALL mode + +Enable GDM GDMA_DROP_ALL mode to drop all packet during the +stop operation. This is recommended by the mt762x HW design +to drop all packet from GMAC before stopping PDMA. + +Signed-off-by: MarkLee +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2331,6 +2331,8 @@ static int mtk_stop(struct net_device *d + if (!refcount_dec_and_test(ð->dma_refcnt)) + return 0; + ++ mtk_gdm_config(eth, MTK_GDMA_DROP_ALL); ++ + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); + mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); + napi_disable(ð->tx_napi); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -85,6 +85,7 @@ + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) + #define MTK_GDMA_TO_PDMA 0x0 ++#define MTK_GDMA_DROP_ALL 0x7777 + + /* Unicast Filter MAC Address Register - Low */ + #define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000)) diff --git a/ipq806x/backport-5.4/765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch b/ipq806x/backport-5.4/765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch new file mode 100644 index 0000000..7ec2689 --- /dev/null +++ b/ipq806x/backport-5.4/765-v5.12-net-dsa-automatically-bring-up-DSA-master-when-openi.patch @@ -0,0 +1,85 @@ +From 9d5ef190e5615a7b63af89f88c4106a5bc127974 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Fri, 5 Feb 2021 15:37:10 +0200 +Subject: [PATCH] net: dsa: automatically bring up DSA master when opening user + port + +DSA wants the master interface to be open before the user port is due to +historical reasons. The promiscuity of interfaces that are down used to +have issues, as referenced Lennert Buytenhek in commit df02c6ff2e39 +("dsa: fix master interface allmulti/promisc handling"). + +The bugfix mentioned there, commit b6c40d68ff64 ("net: only invoke +dev->change_rx_flags when device is UP"), was basically a "don't do +that" approach to working around the promiscuity while down issue. + +Further work done by Vlad Yasevich in commit d2615bf45069 ("net: core: +Always propagate flag changes to interfaces") has resolved the +underlying issue, and it is strictly up to the DSA and 8021q drivers +now, it is no longer mandated by the networking core that the master +interface must be up when changing its promiscuity. + +From DSA's point of view, deciding to error out in dsa_slave_open +because the master isn't up is +(a) a bad user experience and +(b) knocking at an open door. +Even if there still was an issue with promiscuity while down, DSA could +still just open the master and avoid it. + +Doing it this way has the additional benefit that user space can now +remove DSA-specific workarounds, like systemd-networkd with BindCarrier: +https://github.com/systemd/systemd/issues/7478 + +And we can finally remove one of the 2 bullets in the "Common pitfalls +using DSA setups" chapter. + +Tested with two cascaded DSA switches: + +$ ip link set sw0p2 up +fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode +fsl_enetc 0000:00:00.2 eno2: Link is Up - 1Gbps/Full - flow control rx/tx +mscc_felix 0000:00:00.5 swp0: configuring for fixed/sgmii link mode +mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Full - flow control off +8021q: adding VLAN 0 to HW filter on device swp0 +sja1105 spi2.0 sw0p2: configuring for phy/rgmii-id link mode +IPv6: ADDRCONF(NETDEV_CHANGE): eno2: link becomes ready +IPv6: ADDRCONF(NETDEV_CHANGE): swp0: link becomes ready + +Signed-off-by: Vladimir Oltean +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + Documentation/networking/dsa/dsa.rst | 4 ---- + net/dsa/slave.c | 7 +++++-- + 2 files changed, 5 insertions(+), 6 deletions(-) + +--- a/Documentation/networking/dsa/dsa.rst ++++ b/Documentation/networking/dsa/dsa.rst +@@ -273,10 +273,6 @@ will not make us go through the switch t + the Ethernet switch on the other end, expecting a tag will typically drop this + frame. + +-Slave network devices check that the master network device is UP before allowing +-you to administratively bring UP these slave network devices. A common +-configuration mistake is forgetting to bring UP the master network device first. +- + Interactions with other subsystems + ================================== + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -70,8 +70,11 @@ static int dsa_slave_open(struct net_dev + struct dsa_port *dp = dsa_slave_to_port(dev); + int err; + +- if (!(master->flags & IFF_UP)) +- return -ENETDOWN; ++ err = dev_open(master, NULL); ++ if (err < 0) { ++ netdev_err(dev, "failed to open master %s\n", master->name); ++ goto out; ++ } + + if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { + err = dev_uc_add(master, dev->dev_addr); diff --git a/ipq806x/backport-5.4/770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch b/ipq806x/backport-5.4/770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch new file mode 100644 index 0000000..df4e74c --- /dev/null +++ b/ipq806x/backport-5.4/770-v5.12-net-bridge-notify-switchdev-of-disappearance-of-old-.patch @@ -0,0 +1,126 @@ +From 90dc8fd36078a536671adae884d0b929cce6480a Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 6 Jan 2021 11:51:30 +0200 +Subject: [PATCH] net: bridge: notify switchdev of disappearance of old FDB + entry upon migration + +Currently the bridge emits atomic switchdev notifications for +dynamically learnt FDB entries. Monitoring these notifications works +wonders for switchdev drivers that want to keep their hardware FDB in +sync with the bridge's FDB. + +For example station A wants to talk to station B in the diagram below, +and we are concerned with the behavior of the bridge on the DUT device: + + DUT + +-------------------------------------+ + | br0 | + | +------+ +------+ +------+ +------+ | + | | | | | | | | | | + | | swp0 | | swp1 | | swp2 | | eth0 | | + +-------------------------------------+ + | | | + Station A | | + | | + +--+------+--+ +--+------+--+ + | | | | | | | | + | | swp0 | | | | swp0 | | + Another | +------+ | | +------+ | Another + switch | br0 | | br0 | switch + | +------+ | | +------+ | + | | | | | | | | + | | swp1 | | | | swp1 | | + +--+------+--+ +--+------+--+ + | + Station B + +Interfaces swp0, swp1, swp2 are handled by a switchdev driver that has +the following property: frames injected from its control interface bypass +the internal address analyzer logic, and therefore, this hardware does +not learn from the source address of packets transmitted by the network +stack through it. So, since bridging between eth0 (where Station B is +attached) and swp0 (where Station A is attached) is done in software, +the switchdev hardware will never learn the source address of Station B. +So the traffic towards that destination will be treated as unknown, i.e. +flooded. + +This is where the bridge notifications come in handy. When br0 on the +DUT sees frames with Station B's MAC address on eth0, the switchdev +driver gets these notifications and can install a rule to send frames +towards Station B's address that are incoming from swp0, swp1, swp2, +only towards the control interface. This is all switchdev driver private +business, which the notification makes possible. + +All is fine until someone unplugs Station B's cable and moves it to the +other switch: + + DUT + +-------------------------------------+ + | br0 | + | +------+ +------+ +------+ +------+ | + | | | | | | | | | | + | | swp0 | | swp1 | | swp2 | | eth0 | | + +-------------------------------------+ + | | | + Station A | | + | | + +--+------+--+ +--+------+--+ + | | | | | | | | + | | swp0 | | | | swp0 | | + Another | +------+ | | +------+ | Another + switch | br0 | | br0 | switch + | +------+ | | +------+ | + | | | | | | | | + | | swp1 | | | | swp1 | | + +--+------+--+ +--+------+--+ + | + Station B + +Luckily for the use cases we care about, Station B is noisy enough that +the DUT hears it (on swp1 this time). swp1 receives the frames and +delivers them to the bridge, who enters the unlikely path in br_fdb_update +of updating an existing entry. It moves the entry in the software bridge +to swp1 and emits an addition notification towards that. + +As far as the switchdev driver is concerned, all that it needs to ensure +is that traffic between Station A and Station B is not forever broken. +If it does nothing, then the stale rule to send frames for Station B +towards the control interface remains in place. But Station B is no +longer reachable via the control interface, but via a port that can +offload the bridge port learning attribute. It's just that the port is +prevented from learning this address, since the rule overrides FDB +updates. So the rule needs to go. The question is via what mechanism. + +It sure would be possible for this switchdev driver to keep track of all +addresses which are sent to the control interface, and then also listen +for bridge notifier events on its own ports, searching for the ones that +have a MAC address which was previously sent to the control interface. +But this is cumbersome and inefficient. Instead, with one small change, +the bridge could notify of the address deletion from the old port, in a +symmetrical manner with how it did for the insertion. Then the switchdev +driver would not be required to monitor learn/forget events for its own +ports. It could just delete the rule towards the control interface upon +bridge entry migration. This would make hardware address learning be +possible again. Then it would take a few more packets until the hardware +and software FDB would be in sync again. + +Signed-off-by: Vladimir Oltean +Acked-by: Nikolay Aleksandrov +Reviewed-by: Ido Schimmel +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + net/bridge/br_fdb.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -581,6 +581,7 @@ void br_fdb_update(struct net_bridge *br + + /* fastpath: update of existing entry */ + if (unlikely(source != fdb->dst && !fdb->is_sticky)) { ++ br_switchdev_fdb_notify(fdb, RTM_DELNEIGH); + fdb->dst = source; + fdb_modified = true; + /* Take over HW learned entry */ diff --git a/ipq806x/backport-5.4/771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch b/ipq806x/backport-5.4/771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch new file mode 100644 index 0000000..893eb71 --- /dev/null +++ b/ipq806x/backport-5.4/771-v5.12-net-dsa-be-louder-when-a-non-legacy-FDB-operation-fa.patch @@ -0,0 +1,52 @@ +From 2fd186501b1cff155cc4a755c210793cfc0dffb5 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 6 Jan 2021 11:51:31 +0200 +Subject: [PATCH] net: dsa: be louder when a non-legacy FDB operation fails + +The dev_close() call was added in commit c9eb3e0f8701 ("net: dsa: Add +support for learning FDB through notification") "to indicate inconsistent +situation" when we could not delete an FDB entry from the port. + +bridge fdb del d8:58:d7:00:ca:6d dev swp0 self master + +It is a bit drastic and at the same time not helpful if the above fails +to only print with netdev_dbg log level, but on the other hand to bring +the interface down. + +So increase the verbosity of the error message, and drop dev_close(). + +Signed-off-by: Vladimir Oltean +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + net/dsa/slave.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1593,7 +1593,9 @@ static void dsa_slave_switchdev_event_wo + + err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid); + if (err) { +- netdev_dbg(dev, "fdb add failed err=%d\n", err); ++ netdev_err(dev, ++ "failed to add %pM vid %d to fdb: %d\n", ++ fdb_info->addr, fdb_info->vid, err); + break; + } + fdb_info->offloaded = true; +@@ -1608,9 +1610,11 @@ static void dsa_slave_switchdev_event_wo + + err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid); + if (err) { +- netdev_dbg(dev, "fdb del failed err=%d\n", err); +- dev_close(dev); ++ netdev_err(dev, ++ "failed to delete %pM vid %d from fdb: %d\n", ++ fdb_info->addr, fdb_info->vid, err); + } ++ + break; + } + rtnl_unlock(); diff --git a/ipq806x/backport-5.4/772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch b/ipq806x/backport-5.4/772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch new file mode 100644 index 0000000..275870d --- /dev/null +++ b/ipq806x/backport-5.4/772-v5.12-net-dsa-don-t-use-switchdev_notifier_fdb_info-in-dsa.patch @@ -0,0 +1,226 @@ +From c4bb76a9a0ef87c4cc1f636defed5f12deb9f5a7 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 6 Jan 2021 11:51:32 +0200 +Subject: [PATCH] net: dsa: don't use switchdev_notifier_fdb_info in + dsa_switchdev_event_work + +Currently DSA doesn't add FDB entries on the CPU port, because it only +does so through switchdev, which is associated with a net_device, and +there are none of those for the CPU port. + +But actually FDB addresses on the CPU port have some use cases of their +own, if the switchdev operations are initiated from within the DSA +layer. There is just one problem with the existing code: it passes a +structure in dsa_switchdev_event_work which was retrieved directly from +switchdev, so it contains a net_device. We need to generalize the +contents to something that covers the CPU port as well: the "ds, port" +tuple is fine for that. + +Note that the new procedure for notifying the successful FDB offload is +inspired from the rocker model. + +Also, nothing was being done if added_by_user was false. Let's check for +that a lot earlier, and don't actually bother to schedule the worker +for nothing. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + net/dsa/dsa_priv.h | 12 +++++ + net/dsa/slave.c | 106 ++++++++++++++++++++++----------------------- + 2 files changed, 65 insertions(+), 53 deletions(-) + +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -62,6 +62,18 @@ struct dsa_notifier_vlan_info { + int port; + }; + ++struct dsa_switchdev_event_work { ++ struct dsa_switch *ds; ++ int port; ++ struct work_struct work; ++ unsigned long event; ++ /* Specific for SWITCHDEV_FDB_ADD_TO_DEVICE and ++ * SWITCHDEV_FDB_DEL_TO_DEVICE ++ */ ++ unsigned char addr[ETH_ALEN]; ++ u16 vid; ++}; ++ + struct dsa_slave_priv { + /* Copy of CPU port xmit for faster access in slave transmit hot path */ + struct sk_buff * (*xmit)(struct sk_buff *skb, +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1568,76 +1568,66 @@ static int dsa_slave_netdevice_event(str + return NOTIFY_DONE; + } + +-struct dsa_switchdev_event_work { +- struct work_struct work; +- struct switchdev_notifier_fdb_info fdb_info; +- struct net_device *dev; +- unsigned long event; +-}; ++static void ++dsa_fdb_offload_notify(struct dsa_switchdev_event_work *switchdev_work) ++{ ++ struct dsa_switch *ds = switchdev_work->ds; ++ struct switchdev_notifier_fdb_info info; ++ struct dsa_port *dp; ++ ++ if (!dsa_is_user_port(ds, switchdev_work->port)) ++ return; ++ ++ info.addr = switchdev_work->addr; ++ info.vid = switchdev_work->vid; ++ info.offloaded = true; ++ dp = dsa_to_port(ds, switchdev_work->port); ++ call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, ++ dp->slave, &info.info, NULL); ++} + + static void dsa_slave_switchdev_event_work(struct work_struct *work) + { + struct dsa_switchdev_event_work *switchdev_work = + container_of(work, struct dsa_switchdev_event_work, work); +- struct net_device *dev = switchdev_work->dev; +- struct switchdev_notifier_fdb_info *fdb_info; +- struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct dsa_switch *ds = switchdev_work->ds; ++ struct dsa_port *dp; + int err; + ++ dp = dsa_to_port(ds, switchdev_work->port); ++ + rtnl_lock(); + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: +- fdb_info = &switchdev_work->fdb_info; +- if (!fdb_info->added_by_user) +- break; +- +- err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid); ++ err = dsa_port_fdb_add(dp, switchdev_work->addr, ++ switchdev_work->vid); + if (err) { +- netdev_err(dev, +- "failed to add %pM vid %d to fdb: %d\n", +- fdb_info->addr, fdb_info->vid, err); ++ dev_err(ds->dev, ++ "port %d failed to add %pM vid %d to fdb: %d\n", ++ dp->index, switchdev_work->addr, ++ switchdev_work->vid, err); + break; + } +- fdb_info->offloaded = true; +- call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, dev, +- &fdb_info->info, NULL); ++ dsa_fdb_offload_notify(switchdev_work); + break; + + case SWITCHDEV_FDB_DEL_TO_DEVICE: +- fdb_info = &switchdev_work->fdb_info; +- if (!fdb_info->added_by_user) +- break; +- +- err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid); ++ err = dsa_port_fdb_del(dp, switchdev_work->addr, ++ switchdev_work->vid); + if (err) { +- netdev_err(dev, +- "failed to delete %pM vid %d from fdb: %d\n", +- fdb_info->addr, fdb_info->vid, err); ++ dev_err(ds->dev, ++ "port %d failed to delete %pM vid %d from fdb: %d\n", ++ dp->index, switchdev_work->addr, ++ switchdev_work->vid, err); + } + + break; + } + rtnl_unlock(); + +- kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); +- dev_put(dev); +-} +- +-static int +-dsa_slave_switchdev_fdb_work_init(struct dsa_switchdev_event_work * +- switchdev_work, +- const struct switchdev_notifier_fdb_info * +- fdb_info) +-{ +- memcpy(&switchdev_work->fdb_info, fdb_info, +- sizeof(switchdev_work->fdb_info)); +- switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); +- if (!switchdev_work->fdb_info.addr) +- return -ENOMEM; +- ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, +- fdb_info->addr); +- return 0; ++ if (dsa_is_user_port(ds, dp->index)) ++ dev_put(dp->slave); + } + + /* Called under rcu_read_lock() */ +@@ -1645,7 +1635,9 @@ static int dsa_slave_switchdev_event(str + unsigned long event, void *ptr) + { + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); ++ const struct switchdev_notifier_fdb_info *fdb_info; + struct dsa_switchdev_event_work *switchdev_work; ++ struct dsa_port *dp; + int err; + + if (event == SWITCHDEV_PORT_ATTR_SET) { +@@ -1658,20 +1650,32 @@ static int dsa_slave_switchdev_event(str + if (!dsa_slave_dev_check(dev)) + return NOTIFY_DONE; + ++ dp = dsa_slave_to_port(dev); ++ + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, + dsa_slave_switchdev_event_work); +- switchdev_work->dev = dev; ++ switchdev_work->ds = dp->ds; ++ switchdev_work->port = dp->index; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */ + case SWITCHDEV_FDB_DEL_TO_DEVICE: +- if (dsa_slave_switchdev_fdb_work_init(switchdev_work, ptr)) +- goto err_fdb_work_init; ++ fdb_info = ptr; ++ ++ if (!fdb_info->added_by_user) { ++ kfree(switchdev_work); ++ return NOTIFY_OK; ++ } ++ ++ ether_addr_copy(switchdev_work->addr, ++ fdb_info->addr); ++ switchdev_work->vid = fdb_info->vid; ++ + dev_hold(dev); + break; + default: +@@ -1681,10 +1685,6 @@ static int dsa_slave_switchdev_event(str + + dsa_schedule_work(&switchdev_work->work); + return NOTIFY_OK; +- +-err_fdb_work_init: +- kfree(switchdev_work); +- return NOTIFY_BAD; + } + + static int dsa_slave_switchdev_blocking_event(struct notifier_block *unused, diff --git a/ipq806x/backport-5.4/773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch b/ipq806x/backport-5.4/773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch new file mode 100644 index 0000000..b70986f --- /dev/null +++ b/ipq806x/backport-5.4/773-v5.12-net-dsa-move-switchdev-event-implementation-under-th.patch @@ -0,0 +1,85 @@ +From 447d290a58bd335d68f665713842365d3d6447df Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 6 Jan 2021 11:51:33 +0200 +Subject: [PATCH] net: dsa: move switchdev event implementation under the same + switch/case statement + +We'll need to start listening to SWITCHDEV_FDB_{ADD,DEL}_TO_DEVICE +events even for interfaces where dsa_slave_dev_check returns false, so +we need that check inside the switch-case statement for SWITCHDEV_FDB_*. + +This movement also avoids a useless allocation / free of switchdev_work +on the untreated "default event" case. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + net/dsa/slave.c | 35 ++++++++++++++++------------------- + 1 file changed, 16 insertions(+), 19 deletions(-) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1640,31 +1640,29 @@ static int dsa_slave_switchdev_event(str + struct dsa_port *dp; + int err; + +- if (event == SWITCHDEV_PORT_ATTR_SET) { ++ switch (event) { ++ case SWITCHDEV_PORT_ATTR_SET: + err = switchdev_handle_port_attr_set(dev, ptr, + dsa_slave_dev_check, + dsa_slave_port_attr_set); + return notifier_from_errno(err); +- } +- +- if (!dsa_slave_dev_check(dev)) +- return NOTIFY_DONE; ++ case SWITCHDEV_FDB_ADD_TO_DEVICE: ++ case SWITCHDEV_FDB_DEL_TO_DEVICE: ++ if (!dsa_slave_dev_check(dev)) ++ return NOTIFY_DONE; + +- dp = dsa_slave_to_port(dev); ++ dp = dsa_slave_to_port(dev); + +- switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); +- if (!switchdev_work) +- return NOTIFY_BAD; +- +- INIT_WORK(&switchdev_work->work, +- dsa_slave_switchdev_event_work); +- switchdev_work->ds = dp->ds; +- switchdev_work->port = dp->index; +- switchdev_work->event = event; ++ switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); ++ if (!switchdev_work) ++ return NOTIFY_BAD; ++ ++ INIT_WORK(&switchdev_work->work, ++ dsa_slave_switchdev_event_work); ++ switchdev_work->ds = dp->ds; ++ switchdev_work->port = dp->index; ++ switchdev_work->event = event; + +- switch (event) { +- case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */ +- case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb_info = ptr; + + if (!fdb_info->added_by_user) { +@@ -1677,13 +1675,12 @@ static int dsa_slave_switchdev_event(str + switchdev_work->vid = fdb_info->vid; + + dev_hold(dev); ++ dsa_schedule_work(&switchdev_work->work); + break; + default: +- kfree(switchdev_work); + return NOTIFY_DONE; + } + +- dsa_schedule_work(&switchdev_work->work); + return NOTIFY_OK; + } + diff --git a/ipq806x/backport-5.4/774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch b/ipq806x/backport-5.4/774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch new file mode 100644 index 0000000..c7ed406 --- /dev/null +++ b/ipq806x/backport-5.4/774-v5.12-net-dsa-exit-early-in-dsa_slave_switchdev_event-if-w.patch @@ -0,0 +1,42 @@ +From 5fb4a451a87d8ed3363d28b63a3295399373d6c4 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 6 Jan 2021 11:51:34 +0200 +Subject: [PATCH] net: dsa: exit early in dsa_slave_switchdev_event if we can't + program the FDB + +Right now, the following would happen for a switch driver that does not +implement .port_fdb_add or .port_fdb_del. + +dsa_slave_switchdev_event returns NOTIFY_OK and schedules: +-> dsa_slave_switchdev_event_work + -> dsa_port_fdb_add + -> dsa_port_notify(DSA_NOTIFIER_FDB_ADD) + -> dsa_switch_fdb_add + -> if (!ds->ops->port_fdb_add) return -EOPNOTSUPP; + -> an error is printed with dev_dbg, and + dsa_fdb_offload_notify(switchdev_work) is not called. + +We can avoid scheduling the worker for nothing and say NOTIFY_DONE. +Because we don't call dsa_fdb_offload_notify, the static FDB entry will +remain just in the software bridge. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Reviewed-by: Andrew Lunn +Signed-off-by: Jakub Kicinski +--- + net/dsa/slave.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1653,6 +1653,9 @@ static int dsa_slave_switchdev_event(str + + dp = dsa_slave_to_port(dev); + ++ if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) ++ return NOTIFY_DONE; ++ + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return NOTIFY_BAD; diff --git a/ipq806x/backport-5.4/775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch b/ipq806x/backport-5.4/775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch new file mode 100644 index 0000000..e4ed6e8 --- /dev/null +++ b/ipq806x/backport-5.4/775-v5.12-net-dsa-listen-for-SWITCHDEV_-FDB-DEL-_ADD_TO_DEVICE.patch @@ -0,0 +1,263 @@ +From d5f19486cee79d04c054427577ac96ed123706db Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 6 Jan 2021 11:51:35 +0200 +Subject: [PATCH] net: dsa: listen for SWITCHDEV_{FDB,DEL}_ADD_TO_DEVICE on + foreign bridge neighbors + +Some DSA switches (and not only) cannot learn source MAC addresses from +packets injected from the CPU. They only perform hardware address +learning from inbound traffic. + +This can be problematic when we have a bridge spanning some DSA switch +ports and some non-DSA ports (which we'll call "foreign interfaces" from +DSA's perspective). + +There are 2 classes of problems created by the lack of learning on +CPU-injected traffic: +- excessive flooding, due to the fact that DSA treats those addresses as + unknown +- the risk of stale routes, which can lead to temporary packet loss + +To illustrate the second class, consider the following situation, which +is common in production equipment (wireless access points, where there +is a WLAN interface and an Ethernet switch, and these form a single +bridging domain). + + AP 1: + +------------------------------------------------------------------------+ + | br0 | + +------------------------------------------------------------------------+ + +------------+ +------------+ +------------+ +------------+ +------------+ + | swp0 | | swp1 | | swp2 | | swp3 | | wlan0 | + +------------+ +------------+ +------------+ +------------+ +------------+ + | ^ ^ + | | | + | | | + | Client A Client B + | + | + | + +------------+ +------------+ +------------+ +------------+ +------------+ + | swp0 | | swp1 | | swp2 | | swp3 | | wlan0 | + +------------+ +------------+ +------------+ +------------+ +------------+ + +------------------------------------------------------------------------+ + | br0 | + +------------------------------------------------------------------------+ + AP 2 + +- br0 of AP 1 will know that Clients A and B are reachable via wlan0 +- the hardware fdb of a DSA switch driver today is not kept in sync with + the software entries on other bridge ports, so it will not know that + clients A and B are reachable via the CPU port UNLESS the hardware + switch itself performs SA learning from traffic injected from the CPU. + Nonetheless, a substantial number of switches don't. +- the hardware fdb of the DSA switch on AP 2 may autonomously learn that + Client A and B are reachable through swp0. Therefore, the software br0 + of AP 2 also may or may not learn this. In the example we're + illustrating, some Ethernet traffic has been going on, and br0 from AP + 2 has indeed learnt that it can reach Client B through swp0. + +One of the wireless clients, say Client B, disconnects from AP 1 and +roams to AP 2. The topology now looks like this: + + AP 1: + +------------------------------------------------------------------------+ + | br0 | + +------------------------------------------------------------------------+ + +------------+ +------------+ +------------+ +------------+ +------------+ + | swp0 | | swp1 | | swp2 | | swp3 | | wlan0 | + +------------+ +------------+ +------------+ +------------+ +------------+ + | ^ + | | + | Client A + | + | + | Client B + | | + | v + +------------+ +------------+ +------------+ +------------+ +------------+ + | swp0 | | swp1 | | swp2 | | swp3 | | wlan0 | + +------------+ +------------+ +------------+ +------------+ +------------+ + +------------------------------------------------------------------------+ + | br0 | + +------------------------------------------------------------------------+ + AP 2 + +- br0 of AP 1 still knows that Client A is reachable via wlan0 (no change) +- br0 of AP 1 will (possibly) know that Client B has left wlan0. There + are cases where it might never find out though. Either way, DSA today + does not process that notification in any way. +- the hardware FDB of the DSA switch on AP 1 may learn autonomously that + Client B can be reached via swp0, if it receives any packet with + Client 1's source MAC address over Ethernet. +- the hardware FDB of the DSA switch on AP 2 still thinks that Client B + can be reached via swp0. It does not know that it has roamed to wlan0, + because it doesn't perform SA learning from the CPU port. + +Now Client A contacts Client B. +AP 1 routes the packet fine towards swp0 and delivers it on the Ethernet +segment. +AP 2 sees a frame on swp0 and its fdb says that the destination is swp0. +Hairpinning is disabled => drop. + +This problem comes from the fact that these switches have a 'blind spot' +for addresses coming from software bridging. The generic solution is not +to assume that hardware learning can be enabled somehow, but to listen +to more bridge learning events. It turns out that the bridge driver does +learn in software from all inbound frames, in __br_handle_local_finish. +A proper SWITCHDEV_FDB_ADD_TO_DEVICE notification is emitted for the +addresses serviced by the bridge on 'foreign' interfaces. The software +bridge also does the right thing on migration, by notifying that the old +entry is deleted, so that does not need to be special-cased in DSA. When +it is deleted, we just need to delete our static FDB entry towards the +CPU too, and wait. + +The problem is that DSA currently only cares about SWITCHDEV_FDB_ADD_TO_DEVICE +events received on its own interfaces, such as static FDB entries. + +Luckily we can change that, and DSA can listen to all switchdev FDB +add/del events in the system and figure out if those events were emitted +by a bridge that spans at least one of DSA's own ports. In case that is +true, DSA will also offload that address towards its own CPU port, in +the eventuality that there might be bridge clients attached to the DSA +switch who want to talk to the station connected to the foreign +interface. + +In terms of implementation, we need to keep the fdb_info->added_by_user +check for the case where the switchdev event was targeted directly at a +DSA switch port. But we don't need to look at that flag for snooped +events. So the check is currently too late, we need to move it earlier. +This also simplifies the code a bit, since we avoid uselessly allocating +and freeing switchdev_work. + +We could probably do some improvements in the future. For example, +multi-bridge support is rudimentary at the moment. If there are two +bridges spanning a DSA switch's ports, and both of them need to service +the same MAC address, then what will happen is that the migration of one +of those stations will trigger the deletion of the FDB entry from the +CPU port while it is still used by other bridge. That could be improved +with reference counting but is left for another time. + +This behavior needs to be enabled at driver level by setting +ds->assisted_learning_on_cpu_port = true. This is because we don't want +to inflict a potential performance penalty (accesses through +MDIO/I2C/SPI are expensive) to hardware that really doesn't need it +because address learning on the CPU port works there. + +Reported-by: DENG Qingfang +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Reviewed-by: Andrew Lunn +Signed-off-by: Jakub Kicinski +[Backported to linux-5.4.y] +Signed-off-by: DENG Qingfang +--- + include/net/dsa.h | 5 ++++ + net/dsa/slave.c | 63 ++++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 57 insertions(+), 11 deletions(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -279,6 +279,11 @@ struct dsa_switch { + */ + bool configure_vlan_while_not_filtering; + ++ /* Let DSA manage the FDB entries towards the CPU, based on the ++ * software bridge database. ++ */ ++ bool assisted_learning_on_cpu_port; ++ + /* In case vlan_filtering_is_global is set, the VLAN awareness state + * should be retrieved from here and not from the per-port settings. + */ +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1630,6 +1630,25 @@ static void dsa_slave_switchdev_event_wo + dev_put(dp->slave); + } + ++static int dsa_lower_dev_walk(struct net_device *lower_dev, void *data) ++{ ++ if (dsa_slave_dev_check(lower_dev)) { ++ *((void **)data) = (void *)netdev_priv(lower_dev); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static struct dsa_slave_priv *dsa_slave_dev_lower_find(struct net_device *dev) ++{ ++ struct dsa_slave_priv *data = NULL; ++ ++ netdev_walk_all_lower_dev_rcu(dev, dsa_lower_dev_walk, (void **) &data); ++ ++ return data; ++} ++ + /* Called under rcu_read_lock() */ + static int dsa_slave_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +@@ -1648,10 +1667,37 @@ static int dsa_slave_switchdev_event(str + return notifier_from_errno(err); + case SWITCHDEV_FDB_ADD_TO_DEVICE: + case SWITCHDEV_FDB_DEL_TO_DEVICE: +- if (!dsa_slave_dev_check(dev)) +- return NOTIFY_DONE; ++ fdb_info = ptr; ++ ++ if (dsa_slave_dev_check(dev)) { ++ if (!fdb_info->added_by_user) ++ return NOTIFY_OK; ++ ++ dp = dsa_slave_to_port(dev); ++ } else { ++ /* Snoop addresses learnt on foreign interfaces ++ * bridged with us, for switches that don't ++ * automatically learn SA from CPU-injected traffic ++ */ ++ struct net_device *br_dev; ++ struct dsa_slave_priv *p; ++ ++ br_dev = netdev_master_upper_dev_get_rcu(dev); ++ if (!br_dev) ++ return NOTIFY_DONE; ++ ++ if (!netif_is_bridge_master(br_dev)) ++ return NOTIFY_DONE; ++ ++ p = dsa_slave_dev_lower_find(br_dev); ++ if (!p) ++ return NOTIFY_DONE; + +- dp = dsa_slave_to_port(dev); ++ dp = p->dp->cpu_dp; ++ ++ if (!dp->ds->assisted_learning_on_cpu_port) ++ return NOTIFY_DONE; ++ } + + if (!dp->ds->ops->port_fdb_add || !dp->ds->ops->port_fdb_del) + return NOTIFY_DONE; +@@ -1666,18 +1712,13 @@ static int dsa_slave_switchdev_event(str + switchdev_work->port = dp->index; + switchdev_work->event = event; + +- fdb_info = ptr; +- +- if (!fdb_info->added_by_user) { +- kfree(switchdev_work); +- return NOTIFY_OK; +- } +- + ether_addr_copy(switchdev_work->addr, + fdb_info->addr); + switchdev_work->vid = fdb_info->vid; + +- dev_hold(dev); ++ /* Hold a reference on the slave for dsa_fdb_offload_notify */ ++ if (dsa_is_user_port(dp->ds, dp->index)) ++ dev_hold(dev); + dsa_schedule_work(&switchdev_work->work); + break; + default: diff --git a/ipq806x/backport-5.4/780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch b/ipq806x/backport-5.4/780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch new file mode 100644 index 0000000..7ad7cd3 --- /dev/null +++ b/ipq806x/backport-5.4/780-net-dsa-mt7530-setup-core-clock-even-in-TRGMII-mode.patch @@ -0,0 +1,84 @@ +From c3b8e07909dbe67b0d580416c1a5257643a73be7 Mon Sep 17 00:00:00 2001 +From: Ilya Lipnitskiy +Date: Fri, 12 Mar 2021 00:07:03 -0800 +Subject: [PATCH] net: dsa: mt7530: setup core clock even in TRGMII mode + +A recent change to MIPS ralink reset logic made it so mt7530 actually +resets the switch on platforms such as mt7621 (where bit 2 is the reset +line for the switch). That exposed an issue where the switch would not +function properly in TRGMII mode after a reset. + +Reconfigure core clock in TRGMII mode to fix the issue. + +Tested on Ubiquiti ER-X (MT7621) with TRGMII mode enabled. + +Fixes: 3f9ef7785a9c ("MIPS: ralink: manage low reset lines") +Signed-off-by: Ilya Lipnitskiy +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 52 +++++++++++++++++++--------------------- + 1 file changed, 25 insertions(+), 27 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -428,34 +428,32 @@ mt7530_pad_clk_setup(struct dsa_switch * + TD_DM_DRVP(8) | TD_DM_DRVN(8)); + + /* Setup core clock for MT7530 */ +- if (!trgint) { +- /* Disable MT7530 core clock */ +- core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); +- +- /* Disable PLL, since phy_device has not yet been created +- * provided for phy_[read,write]_mmd_indirect is called, we +- * provide our own core_write_mmd_indirect to complete this +- * function. +- */ +- core_write_mmd_indirect(priv, +- CORE_GSWPLL_GRP1, +- MDIO_MMD_VEND2, +- 0); +- +- /* Set core clock into 500Mhz */ +- core_write(priv, CORE_GSWPLL_GRP2, +- RG_GSWPLL_POSDIV_500M(1) | +- RG_GSWPLL_FBKDIV_500M(25)); +- +- /* Enable PLL */ +- core_write(priv, CORE_GSWPLL_GRP1, +- RG_GSWPLL_EN_PRE | +- RG_GSWPLL_POSDIV_200M(2) | +- RG_GSWPLL_FBKDIV_200M(32)); +- +- /* Enable MT7530 core clock */ +- core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); +- } ++ /* Disable MT7530 core clock */ ++ core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ ++ /* Disable PLL, since phy_device has not yet been created ++ * provided for phy_[read,write]_mmd_indirect is called, we ++ * provide our own core_write_mmd_indirect to complete this ++ * function. ++ */ ++ core_write_mmd_indirect(priv, ++ CORE_GSWPLL_GRP1, ++ MDIO_MMD_VEND2, ++ 0); ++ ++ /* Set core clock into 500Mhz */ ++ core_write(priv, CORE_GSWPLL_GRP2, ++ RG_GSWPLL_POSDIV_500M(1) | ++ RG_GSWPLL_FBKDIV_500M(25)); ++ ++ /* Enable PLL */ ++ core_write(priv, CORE_GSWPLL_GRP1, ++ RG_GSWPLL_EN_PRE | ++ RG_GSWPLL_POSDIV_200M(2) | ++ RG_GSWPLL_FBKDIV_200M(32)); ++ ++ /* Enable MT7530 core clock */ ++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); + + /* Setup the MT7530 TRGMII Tx Clock */ + core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); diff --git a/ipq806x/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch b/ipq806x/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch new file mode 100644 index 0000000..b9cd276 --- /dev/null +++ b/ipq806x/backport-5.4/800-v5.5-iio-imu-Add-support-for-the-FXOS8700-IMU.patch @@ -0,0 +1,893 @@ +From 84e5ddd5c46ea3bf0cad670da32028994cad5936 Mon Sep 17 00:00:00 2001 +From: Robert Jones +Date: Mon, 14 Oct 2019 11:49:21 -0700 +Subject: [PATCH] iio: imu: Add support for the FXOS8700 IMU +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +FXOS8700CQ is a small, low-power, 3-axis linear accelerometer and 3-axis +magnetometer combined into a single package. The device features a +selectable I2C or point-to-point SPI serial interface with 14-bit +accelerometer and 16-bit magnetometer ADC resolution along with +smart-embedded functions. + +FXOS8700CQ has dynamically selectable accelerationfull-scale ranges of +±2 g/±4 g/±8 g and a fixed magnetic measurement range of ±1200 μT. +Output data rates (ODR) from 1.563 Hz to 800 Hz are selectable by the user +for each sensor. Interleaved magnetic and acceleration data is available +at ODR rates of up to 400 Hz. FXOS8700CQ is available in a plastic QFN +package and it is guaranteed to operate over the extended temperature +range of –40 °C to +85 °C. + +TODO: Trigger and IRQ configuration support + +Datasheet: + http://cache.freescale.com/files/sensors/doc/data_sheet/FXOS8700CQ.pdf + +Signed-off-by: Robert Jones +Signed-off-by: Jonathan Cameron +--- + drivers/iio/imu/Kconfig | 27 ++ + drivers/iio/imu/Makefile | 5 + + drivers/iio/imu/fxos8700.h | 10 + + drivers/iio/imu/fxos8700_core.c | 649 ++++++++++++++++++++++++++++++++++++++++ + drivers/iio/imu/fxos8700_i2c.c | 71 +++++ + drivers/iio/imu/fxos8700_spi.c | 59 ++++ + 6 files changed, 821 insertions(+) + create mode 100644 drivers/iio/imu/fxos8700.h + create mode 100644 drivers/iio/imu/fxos8700_core.c + create mode 100644 drivers/iio/imu/fxos8700_i2c.c + create mode 100644 drivers/iio/imu/fxos8700_spi.c + +--- a/drivers/iio/imu/Kconfig ++++ b/drivers/iio/imu/Kconfig +@@ -40,6 +40,33 @@ config ADIS16480 + + source "drivers/iio/imu/bmi160/Kconfig" + ++config FXOS8700 ++ tristate ++ ++config FXOS8700_I2C ++ tristate "NXP FXOS8700 I2C driver" ++ depends on I2C ++ select FXOS8700 ++ select REGMAP_I2C ++ help ++ Say yes here to build support for the NXP FXOS8700 m+g combo ++ sensor on I2C. ++ ++ This driver can also be built as a module. If so, the module will be ++ called fxos8700_i2c. ++ ++config FXOS8700_SPI ++ tristate "NXP FXOS8700 SPI driver" ++ depends on SPI ++ select FXOS8700 ++ select REGMAP_SPI ++ help ++ Say yes here to build support for the NXP FXOS8700 m+g combo ++ sensor on SPI. ++ ++ This driver can also be built as a module. If so, the module will be ++ called fxos8700_spi. ++ + config KMX61 + tristate "Kionix KMX61 6-axis accelerometer and magnetometer" + depends on I2C +--- a/drivers/iio/imu/Makefile ++++ b/drivers/iio/imu/Makefile +@@ -14,6 +14,11 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) + + obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o + + obj-y += bmi160/ ++ ++obj-$(CONFIG_FXOS8700) += fxos8700_core.o ++obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o ++obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o ++ + obj-y += inv_mpu6050/ + + obj-$(CONFIG_KMX61) += kmx61.o +--- /dev/null ++++ b/drivers/iio/imu/fxos8700.h +@@ -0,0 +1,10 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef FXOS8700_H_ ++#define FXOS8700_H_ ++ ++extern const struct regmap_config fxos8700_regmap_config; ++ ++int fxos8700_core_probe(struct device *dev, struct regmap *regmap, ++ const char *name, bool use_spi); ++ ++#endif /* FXOS8700_H_ */ +--- /dev/null ++++ b/drivers/iio/imu/fxos8700_core.c +@@ -0,0 +1,649 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * FXOS8700 - NXP IMU (accelerometer plus magnetometer) ++ * ++ * IIO core driver for FXOS8700, with support for I2C/SPI busses ++ * ++ * TODO: Buffer, trigger, and IRQ support ++ */ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "fxos8700.h" ++ ++/* Register Definitions */ ++#define FXOS8700_STATUS 0x00 ++#define FXOS8700_OUT_X_MSB 0x01 ++#define FXOS8700_OUT_X_LSB 0x02 ++#define FXOS8700_OUT_Y_MSB 0x03 ++#define FXOS8700_OUT_Y_LSB 0x04 ++#define FXOS8700_OUT_Z_MSB 0x05 ++#define FXOS8700_OUT_Z_LSB 0x06 ++#define FXOS8700_F_SETUP 0x09 ++#define FXOS8700_TRIG_CFG 0x0a ++#define FXOS8700_SYSMOD 0x0b ++#define FXOS8700_INT_SOURCE 0x0c ++#define FXOS8700_WHO_AM_I 0x0d ++#define FXOS8700_XYZ_DATA_CFG 0x0e ++#define FXOS8700_HP_FILTER_CUTOFF 0x0f ++#define FXOS8700_PL_STATUS 0x10 ++#define FXOS8700_PL_CFG 0x11 ++#define FXOS8700_PL_COUNT 0x12 ++#define FXOS8700_PL_BF_ZCOMP 0x13 ++#define FXOS8700_PL_THS_REG 0x14 ++#define FXOS8700_A_FFMT_CFG 0x15 ++#define FXOS8700_A_FFMT_SRC 0x16 ++#define FXOS8700_A_FFMT_THS 0x17 ++#define FXOS8700_A_FFMT_COUNT 0x18 ++#define FXOS8700_TRANSIENT_CFG 0x1d ++#define FXOS8700_TRANSIENT_SRC 0x1e ++#define FXOS8700_TRANSIENT_THS 0x1f ++#define FXOS8700_TRANSIENT_COUNT 0x20 ++#define FXOS8700_PULSE_CFG 0x21 ++#define FXOS8700_PULSE_SRC 0x22 ++#define FXOS8700_PULSE_THSX 0x23 ++#define FXOS8700_PULSE_THSY 0x24 ++#define FXOS8700_PULSE_THSZ 0x25 ++#define FXOS8700_PULSE_TMLT 0x26 ++#define FXOS8700_PULSE_LTCY 0x27 ++#define FXOS8700_PULSE_WIND 0x28 ++#define FXOS8700_ASLP_COUNT 0x29 ++#define FXOS8700_CTRL_REG1 0x2a ++#define FXOS8700_CTRL_REG2 0x2b ++#define FXOS8700_CTRL_REG3 0x2c ++#define FXOS8700_CTRL_REG4 0x2d ++#define FXOS8700_CTRL_REG5 0x2e ++#define FXOS8700_OFF_X 0x2f ++#define FXOS8700_OFF_Y 0x30 ++#define FXOS8700_OFF_Z 0x31 ++#define FXOS8700_M_DR_STATUS 0x32 ++#define FXOS8700_M_OUT_X_MSB 0x33 ++#define FXOS8700_M_OUT_X_LSB 0x34 ++#define FXOS8700_M_OUT_Y_MSB 0x35 ++#define FXOS8700_M_OUT_Y_LSB 0x36 ++#define FXOS8700_M_OUT_Z_MSB 0x37 ++#define FXOS8700_M_OUT_Z_LSB 0x38 ++#define FXOS8700_CMP_X_MSB 0x39 ++#define FXOS8700_CMP_X_LSB 0x3a ++#define FXOS8700_CMP_Y_MSB 0x3b ++#define FXOS8700_CMP_Y_LSB 0x3c ++#define FXOS8700_CMP_Z_MSB 0x3d ++#define FXOS8700_CMP_Z_LSB 0x3e ++#define FXOS8700_M_OFF_X_MSB 0x3f ++#define FXOS8700_M_OFF_X_LSB 0x40 ++#define FXOS8700_M_OFF_Y_MSB 0x41 ++#define FXOS8700_M_OFF_Y_LSB 0x42 ++#define FXOS8700_M_OFF_Z_MSB 0x43 ++#define FXOS8700_M_OFF_Z_LSB 0x44 ++#define FXOS8700_MAX_X_MSB 0x45 ++#define FXOS8700_MAX_X_LSB 0x46 ++#define FXOS8700_MAX_Y_MSB 0x47 ++#define FXOS8700_MAX_Y_LSB 0x48 ++#define FXOS8700_MAX_Z_MSB 0x49 ++#define FXOS8700_MAX_Z_LSB 0x4a ++#define FXOS8700_MIN_X_MSB 0x4b ++#define FXOS8700_MIN_X_LSB 0x4c ++#define FXOS8700_MIN_Y_MSB 0x4d ++#define FXOS8700_MIN_Y_LSB 0x4e ++#define FXOS8700_MIN_Z_MSB 0x4f ++#define FXOS8700_MIN_Z_LSB 0x50 ++#define FXOS8700_TEMP 0x51 ++#define FXOS8700_M_THS_CFG 0x52 ++#define FXOS8700_M_THS_SRC 0x53 ++#define FXOS8700_M_THS_X_MSB 0x54 ++#define FXOS8700_M_THS_X_LSB 0x55 ++#define FXOS8700_M_THS_Y_MSB 0x56 ++#define FXOS8700_M_THS_Y_LSB 0x57 ++#define FXOS8700_M_THS_Z_MSB 0x58 ++#define FXOS8700_M_THS_Z_LSB 0x59 ++#define FXOS8700_M_THS_COUNT 0x5a ++#define FXOS8700_M_CTRL_REG1 0x5b ++#define FXOS8700_M_CTRL_REG2 0x5c ++#define FXOS8700_M_CTRL_REG3 0x5d ++#define FXOS8700_M_INT_SRC 0x5e ++#define FXOS8700_A_VECM_CFG 0x5f ++#define FXOS8700_A_VECM_THS_MSB 0x60 ++#define FXOS8700_A_VECM_THS_LSB 0x61 ++#define FXOS8700_A_VECM_CNT 0x62 ++#define FXOS8700_A_VECM_INITX_MSB 0x63 ++#define FXOS8700_A_VECM_INITX_LSB 0x64 ++#define FXOS8700_A_VECM_INITY_MSB 0x65 ++#define FXOS8700_A_VECM_INITY_LSB 0x66 ++#define FXOS8700_A_VECM_INITZ_MSB 0x67 ++#define FXOS8700_A_VECM_INITZ_LSB 0x68 ++#define FXOS8700_M_VECM_CFG 0x69 ++#define FXOS8700_M_VECM_THS_MSB 0x6a ++#define FXOS8700_M_VECM_THS_LSB 0x6b ++#define FXOS8700_M_VECM_CNT 0x6c ++#define FXOS8700_M_VECM_INITX_MSB 0x6d ++#define FXOS8700_M_VECM_INITX_LSB 0x6e ++#define FXOS8700_M_VECM_INITY_MSB 0x6f ++#define FXOS8700_M_VECM_INITY_LSB 0x70 ++#define FXOS8700_M_VECM_INITZ_MSB 0x71 ++#define FXOS8700_M_VECM_INITZ_LSB 0x72 ++#define FXOS8700_A_FFMT_THS_X_MSB 0x73 ++#define FXOS8700_A_FFMT_THS_X_LSB 0x74 ++#define FXOS8700_A_FFMT_THS_Y_MSB 0x75 ++#define FXOS8700_A_FFMT_THS_Y_LSB 0x76 ++#define FXOS8700_A_FFMT_THS_Z_MSB 0x77 ++#define FXOS8700_A_FFMT_THS_Z_LSB 0x78 ++#define FXOS8700_A_TRAN_INIT_MSB 0x79 ++#define FXOS8700_A_TRAN_INIT_LSB_X 0x7a ++#define FXOS8700_A_TRAN_INIT_LSB_Y 0x7b ++#define FXOS8700_A_TRAN_INIT_LSB_Z 0x7d ++#define FXOS8700_TM_NVM_LOCK 0x7e ++#define FXOS8700_NVM_DATA0_35 0x80 ++#define FXOS8700_NVM_DATA_BNK3 0xa4 ++#define FXOS8700_NVM_DATA_BNK2 0xa5 ++#define FXOS8700_NVM_DATA_BNK1 0xa6 ++#define FXOS8700_NVM_DATA_BNK0 0xa7 ++ ++/* Bit definitions for FXOS8700_CTRL_REG1 */ ++#define FXOS8700_CTRL_ODR_MSK 0x38 ++#define FXOS8700_CTRL_ODR_MAX 0x00 ++#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3) ++ ++/* Bit definitions for FXOS8700_M_CTRL_REG1 */ ++#define FXOS8700_HMS_MASK GENMASK(1, 0) ++#define FXOS8700_OS_MASK GENMASK(4, 2) ++ ++/* Bit definitions for FXOS8700_M_CTRL_REG2 */ ++#define FXOS8700_MAXMIN_RST BIT(2) ++#define FXOS8700_MAXMIN_DIS_THS BIT(3) ++#define FXOS8700_MAXMIN_DIS BIT(4) ++ ++#define FXOS8700_ACTIVE 0x01 ++#define FXOS8700_ACTIVE_MIN_USLEEP 4000 /* from table 6 in datasheet */ ++ ++#define FXOS8700_DEVICE_ID 0xC7 ++#define FXOS8700_PRE_DEVICE_ID 0xC4 ++#define FXOS8700_DATA_BUF_SIZE 3 ++ ++struct fxos8700_data { ++ struct regmap *regmap; ++ struct iio_trigger *trig; ++ __be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned; ++}; ++ ++/* Regmap info */ ++static const struct regmap_range read_range[] = { ++ { ++ .range_min = FXOS8700_STATUS, ++ .range_max = FXOS8700_A_FFMT_COUNT, ++ }, { ++ .range_min = FXOS8700_TRANSIENT_CFG, ++ .range_max = FXOS8700_A_FFMT_THS_Z_LSB, ++ }, ++}; ++ ++static const struct regmap_range write_range[] = { ++ { ++ .range_min = FXOS8700_F_SETUP, ++ .range_max = FXOS8700_TRIG_CFG, ++ }, { ++ .range_min = FXOS8700_XYZ_DATA_CFG, ++ .range_max = FXOS8700_HP_FILTER_CUTOFF, ++ }, { ++ .range_min = FXOS8700_PL_CFG, ++ .range_max = FXOS8700_A_FFMT_CFG, ++ }, { ++ .range_min = FXOS8700_A_FFMT_THS, ++ .range_max = FXOS8700_TRANSIENT_CFG, ++ }, { ++ .range_min = FXOS8700_TRANSIENT_THS, ++ .range_max = FXOS8700_PULSE_CFG, ++ }, { ++ .range_min = FXOS8700_PULSE_THSX, ++ .range_max = FXOS8700_OFF_Z, ++ }, { ++ .range_min = FXOS8700_M_OFF_X_MSB, ++ .range_max = FXOS8700_M_OFF_Z_LSB, ++ }, { ++ .range_min = FXOS8700_M_THS_CFG, ++ .range_max = FXOS8700_M_THS_CFG, ++ }, { ++ .range_min = FXOS8700_M_THS_X_MSB, ++ .range_max = FXOS8700_M_CTRL_REG3, ++ }, { ++ .range_min = FXOS8700_A_VECM_CFG, ++ .range_max = FXOS8700_A_FFMT_THS_Z_LSB, ++ }, ++}; ++ ++static const struct regmap_access_table driver_read_table = { ++ .yes_ranges = read_range, ++ .n_yes_ranges = ARRAY_SIZE(read_range), ++}; ++ ++static const struct regmap_access_table driver_write_table = { ++ .yes_ranges = write_range, ++ .n_yes_ranges = ARRAY_SIZE(write_range), ++}; ++ ++const struct regmap_config fxos8700_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = FXOS8700_NVM_DATA_BNK0, ++ .rd_table = &driver_read_table, ++ .wr_table = &driver_write_table, ++}; ++EXPORT_SYMBOL(fxos8700_regmap_config); ++ ++#define FXOS8700_CHANNEL(_type, _axis) { \ ++ .type = _type, \ ++ .modified = 1, \ ++ .channel2 = IIO_MOD_##_axis, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ ++} ++ ++enum fxos8700_accel_scale_bits { ++ MODE_2G = 0, ++ MODE_4G, ++ MODE_8G, ++}; ++ ++/* scan indexes follow DATA register order */ ++enum fxos8700_scan_axis { ++ FXOS8700_SCAN_ACCEL_X = 0, ++ FXOS8700_SCAN_ACCEL_Y, ++ FXOS8700_SCAN_ACCEL_Z, ++ FXOS8700_SCAN_MAGN_X, ++ FXOS8700_SCAN_MAGN_Y, ++ FXOS8700_SCAN_MAGN_Z, ++ FXOS8700_SCAN_RHALL, ++ FXOS8700_SCAN_TIMESTAMP, ++}; ++ ++enum fxos8700_sensor { ++ FXOS8700_ACCEL = 0, ++ FXOS8700_MAGN, ++ FXOS8700_NUM_SENSORS /* must be last */ ++}; ++ ++enum fxos8700_int_pin { ++ FXOS8700_PIN_INT1, ++ FXOS8700_PIN_INT2 ++}; ++ ++struct fxos8700_scale { ++ u8 bits; ++ int uscale; ++}; ++ ++struct fxos8700_odr { ++ u8 bits; ++ int odr; ++ int uodr; ++}; ++ ++static const struct fxos8700_scale fxos8700_accel_scale[] = { ++ { MODE_2G, 244}, ++ { MODE_4G, 488}, ++ { MODE_8G, 976}, ++}; ++ ++/* ++ * Accellerometer and magnetometer have the same ODR options, set in the ++ * CTRL_REG1 register. ODR is halved when using both sensors at once in ++ * hybrid mode. ++ */ ++static const struct fxos8700_odr fxos8700_odr[] = { ++ {0x00, 800, 0}, ++ {0x01, 400, 0}, ++ {0x02, 200, 0}, ++ {0x03, 100, 0}, ++ {0x04, 50, 0}, ++ {0x05, 12, 500000}, ++ {0x06, 6, 250000}, ++ {0x07, 1, 562500}, ++}; ++ ++static const struct iio_chan_spec fxos8700_channels[] = { ++ FXOS8700_CHANNEL(IIO_ACCEL, X), ++ FXOS8700_CHANNEL(IIO_ACCEL, Y), ++ FXOS8700_CHANNEL(IIO_ACCEL, Z), ++ FXOS8700_CHANNEL(IIO_MAGN, X), ++ FXOS8700_CHANNEL(IIO_MAGN, Y), ++ FXOS8700_CHANNEL(IIO_MAGN, Z), ++ IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP), ++}; ++ ++static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type) ++{ ++ switch (iio_type) { ++ case IIO_ACCEL: ++ return FXOS8700_ACCEL; ++ case IIO_ANGL_VEL: ++ return FXOS8700_MAGN; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int fxos8700_set_active_mode(struct fxos8700_data *data, ++ enum fxos8700_sensor t, bool mode) ++{ ++ int ret; ++ ++ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode); ++ if (ret) ++ return ret; ++ ++ usleep_range(FXOS8700_ACTIVE_MIN_USLEEP, ++ FXOS8700_ACTIVE_MIN_USLEEP + 1000); ++ ++ return 0; ++} ++ ++static int fxos8700_set_scale(struct fxos8700_data *data, ++ enum fxos8700_sensor t, int uscale) ++{ ++ int i; ++ static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); ++ struct device *dev = regmap_get_device(data->regmap); ++ ++ if (t == FXOS8700_MAGN) { ++ dev_err(dev, "Magnetometer scale is locked at 1200uT\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < scale_num; i++) ++ if (fxos8700_accel_scale[i].uscale == uscale) ++ break; ++ ++ if (i == scale_num) ++ return -EINVAL; ++ ++ return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, ++ fxos8700_accel_scale[i].bits); ++} ++ ++static int fxos8700_get_scale(struct fxos8700_data *data, ++ enum fxos8700_sensor t, int *uscale) ++{ ++ int i, ret, val; ++ static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); ++ ++ if (t == FXOS8700_MAGN) { ++ *uscale = 1200; /* Magnetometer is locked at 1200uT */ ++ return 0; ++ } ++ ++ ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < scale_num; i++) { ++ if (fxos8700_accel_scale[i].bits == (val & 0x3)) { ++ *uscale = fxos8700_accel_scale[i].uscale; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static int fxos8700_get_data(struct fxos8700_data *data, int chan_type, ++ int axis, int *val) ++{ ++ u8 base, reg; ++ int ret; ++ enum fxos8700_sensor type = fxos8700_to_sensor(chan_type); ++ ++ base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB; ++ ++ /* Block read 6 bytes of device output registers to avoid data loss */ ++ ret = regmap_bulk_read(data->regmap, base, data->buf, ++ FXOS8700_DATA_BUF_SIZE); ++ if (ret) ++ return ret; ++ ++ /* Convert axis to buffer index */ ++ reg = axis - IIO_MOD_X; ++ ++ /* Convert to native endianness */ ++ *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15); ++ ++ return 0; ++} ++ ++static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t, ++ int odr, int uodr) ++{ ++ int i, ret, val; ++ bool active_mode; ++ static const int odr_num = ARRAY_SIZE(fxos8700_odr); ++ ++ ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); ++ if (ret) ++ return ret; ++ ++ active_mode = val & FXOS8700_ACTIVE; ++ ++ if (active_mode) { ++ /* ++ * The device must be in standby mode to change any of the ++ * other fields within CTRL_REG1 ++ */ ++ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, ++ val & ~FXOS8700_ACTIVE); ++ if (ret) ++ return ret; ++ } ++ ++ for (i = 0; i < odr_num; i++) ++ if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr) ++ break; ++ ++ if (i >= odr_num) ++ return -EINVAL; ++ ++ return regmap_update_bits(data->regmap, ++ FXOS8700_CTRL_REG1, ++ FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE, ++ fxos8700_odr[i].bits << 3 | active_mode); ++} ++ ++static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t, ++ int *odr, int *uodr) ++{ ++ int i, val, ret; ++ static const int odr_num = ARRAY_SIZE(fxos8700_odr); ++ ++ ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); ++ if (ret) ++ return ret; ++ ++ val &= FXOS8700_CTRL_ODR_MSK; ++ ++ for (i = 0; i < odr_num; i++) ++ if (val == fxos8700_odr[i].bits) ++ break; ++ ++ if (i >= odr_num) ++ return -EINVAL; ++ ++ *odr = fxos8700_odr[i].odr; ++ *uodr = fxos8700_odr[i].uodr; ++ ++ return 0; ++} ++ ++static int fxos8700_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int *val, int *val2, long mask) ++{ ++ int ret; ++ struct fxos8700_data *data = iio_priv(indio_dev); ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_RAW: ++ ret = fxos8700_get_data(data, chan->type, chan->channel2, val); ++ if (ret) ++ return ret; ++ return IIO_VAL_INT; ++ case IIO_CHAN_INFO_SCALE: ++ *val = 0; ++ ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type), ++ val2); ++ return ret ? ret : IIO_VAL_INT_PLUS_MICRO; ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type), ++ val, val2); ++ return ret ? ret : IIO_VAL_INT_PLUS_MICRO; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int fxos8700_write_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int val, int val2, long mask) ++{ ++ struct fxos8700_data *data = iio_priv(indio_dev); ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_SCALE: ++ return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type), ++ val2); ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type), ++ val, val2); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static IIO_CONST_ATTR(in_accel_sampling_frequency_available, ++ "1.5625 6.25 12.5 50 100 200 400 800"); ++static IIO_CONST_ATTR(in_magn_sampling_frequency_available, ++ "1.5625 6.25 12.5 50 100 200 400 800"); ++static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976"); ++static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200"); ++ ++static struct attribute *fxos8700_attrs[] = { ++ &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr, ++ &iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr, ++ &iio_const_attr_in_accel_scale_available.dev_attr.attr, ++ &iio_const_attr_in_magn_scale_available.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group fxos8700_attrs_group = { ++ .attrs = fxos8700_attrs, ++}; ++ ++static const struct iio_info fxos8700_info = { ++ .read_raw = fxos8700_read_raw, ++ .write_raw = fxos8700_write_raw, ++ .attrs = &fxos8700_attrs_group, ++}; ++ ++static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi) ++{ ++ int ret; ++ unsigned int val; ++ struct device *dev = regmap_get_device(data->regmap); ++ ++ ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val); ++ if (ret) { ++ dev_err(dev, "Error reading chip id\n"); ++ return ret; ++ } ++ if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) { ++ dev_err(dev, "Wrong chip id, got %x expected %x or %x\n", ++ val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID); ++ return -ENODEV; ++ } ++ ++ ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true); ++ if (ret) ++ return ret; ++ ++ ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true); ++ if (ret) ++ return ret; ++ ++ /* ++ * The device must be in standby mode to change any of the other fields ++ * within CTRL_REG1 ++ */ ++ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00); ++ if (ret) ++ return ret; ++ ++ /* Set max oversample ratio (OSR) and both devices active */ ++ ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1, ++ FXOS8700_HMS_MASK | FXOS8700_OS_MASK); ++ if (ret) ++ return ret; ++ ++ /* Disable and rst min/max measurements & threshold */ ++ ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2, ++ FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS | ++ FXOS8700_MAXMIN_DIS); ++ if (ret) ++ return ret; ++ ++ /* Max ODR (800Hz individual or 400Hz hybrid), active mode */ ++ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, ++ FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE); ++ if (ret) ++ return ret; ++ ++ /* Set for max full-scale range (+/-8G) */ ++ return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G); ++} ++ ++static void fxos8700_chip_uninit(void *data) ++{ ++ struct fxos8700_data *fxos8700_data = data; ++ ++ fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false); ++ fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false); ++} ++ ++int fxos8700_core_probe(struct device *dev, struct regmap *regmap, ++ const char *name, bool use_spi) ++{ ++ struct iio_dev *indio_dev; ++ struct fxos8700_data *data; ++ int ret; ++ ++ indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); ++ if (!indio_dev) ++ return -ENOMEM; ++ ++ data = iio_priv(indio_dev); ++ dev_set_drvdata(dev, indio_dev); ++ data->regmap = regmap; ++ ++ ret = fxos8700_chip_init(data, use_spi); ++ if (ret) ++ return ret; ++ ++ ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data); ++ if (ret) ++ return ret; ++ ++ indio_dev->dev.parent = dev; ++ indio_dev->channels = fxos8700_channels; ++ indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels); ++ indio_dev->name = name ? name : "fxos8700"; ++ indio_dev->modes = INDIO_DIRECT_MODE; ++ indio_dev->info = &fxos8700_info; ++ ++ return devm_iio_device_register(dev, indio_dev); ++} ++EXPORT_SYMBOL_GPL(fxos8700_core_probe); ++ ++MODULE_AUTHOR("Robert Jones "); ++MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/drivers/iio/imu/fxos8700_i2c.c +@@ -0,0 +1,71 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * FXOS8700 - NXP IMU, I2C bits ++ * ++ * 7-bit I2C slave address determined by SA1 and SA0 logic level ++ * inputs represented in the following table: ++ * SA1 | SA0 | Slave Address ++ * 0 | 0 | 0x1E ++ * 0 | 1 | 0x1D ++ * 1 | 0 | 0x1C ++ * 1 | 1 | 0x1F ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fxos8700.h" ++ ++static int fxos8700_i2c_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct regmap *regmap; ++ const char *name = NULL; ++ ++ regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config); ++ if (IS_ERR(regmap)) { ++ dev_err(&client->dev, "Failed to register i2c regmap %d\n", ++ (int)PTR_ERR(regmap)); ++ return PTR_ERR(regmap); ++ } ++ ++ if (id) ++ name = id->name; ++ ++ return fxos8700_core_probe(&client->dev, regmap, name, false); ++} ++ ++static const struct i2c_device_id fxos8700_i2c_id[] = { ++ {"fxos8700", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id); ++ ++static const struct acpi_device_id fxos8700_acpi_match[] = { ++ {"FXOS8700", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match); ++ ++static const struct of_device_id fxos8700_of_match[] = { ++ { .compatible = "nxp,fxos8700" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, fxos8700_of_match); ++ ++static struct i2c_driver fxos8700_i2c_driver = { ++ .driver = { ++ .name = "fxos8700_i2c", ++ .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), ++ .of_match_table = fxos8700_of_match, ++ }, ++ .probe = fxos8700_i2c_probe, ++ .id_table = fxos8700_i2c_id, ++}; ++module_i2c_driver(fxos8700_i2c_driver); ++ ++MODULE_AUTHOR("Robert Jones "); ++MODULE_DESCRIPTION("FXOS8700 I2C driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/drivers/iio/imu/fxos8700_spi.c +@@ -0,0 +1,59 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * FXOS8700 - NXP IMU, SPI bits ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "fxos8700.h" ++ ++static int fxos8700_spi_probe(struct spi_device *spi) ++{ ++ struct regmap *regmap; ++ const struct spi_device_id *id = spi_get_device_id(spi); ++ ++ regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config); ++ if (IS_ERR(regmap)) { ++ dev_err(&spi->dev, "Failed to register spi regmap %d\n", ++ (int)PTR_ERR(regmap)); ++ return PTR_ERR(regmap); ++ } ++ ++ return fxos8700_core_probe(&spi->dev, regmap, id->name, true); ++} ++ ++static const struct spi_device_id fxos8700_spi_id[] = { ++ {"fxos8700", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(spi, fxos8700_spi_id); ++ ++static const struct acpi_device_id fxos8700_acpi_match[] = { ++ {"FXOS8700", 0}, ++ { } ++}; ++MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match); ++ ++static const struct of_device_id fxos8700_of_match[] = { ++ { .compatible = "nxp,fxos8700" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, fxos8700_of_match); ++ ++static struct spi_driver fxos8700_spi_driver = { ++ .probe = fxos8700_spi_probe, ++ .id_table = fxos8700_spi_id, ++ .driver = { ++ .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), ++ .of_match_table = fxos8700_of_match, ++ .name = "fxos8700_spi", ++ }, ++}; ++module_spi_driver(fxos8700_spi_driver); ++ ++MODULE_AUTHOR("Robert Jones "); ++MODULE_DESCRIPTION("FXOS8700 SPI driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/ipq806x/backport-5.4/800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch b/ipq806x/backport-5.4/800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch new file mode 100644 index 0000000..8c18d5d --- /dev/null +++ b/ipq806x/backport-5.4/800-v5.5-scsi-core-Add-sysfs-attributes-for-VPD-pages-0h-and-.patch @@ -0,0 +1,122 @@ +From d188b0675b21d5a6ca27b3e741381813983f4719 Mon Sep 17 00:00:00 2001 +From: Ryan Attard +Date: Thu, 26 Sep 2019 11:22:17 -0500 +Subject: [PATCH] scsi: core: Add sysfs attributes for VPD pages 0h and 89h + +Add sysfs attributes for the ATA information page and Supported VPD Pages +page. + +Link: https://lore.kernel.org/r/20190926162216.56591-1-ryanattard@ryanattard.info +Signed-off-by: Ryan Attard +Reviewed-by: Bart Van Assche +Signed-off-by: Martin K. Petersen +--- + drivers/scsi/scsi.c | 4 ++++ + drivers/scsi/scsi_sysfs.c | 19 +++++++++++++++++++ + include/scsi/scsi_device.h | 2 ++ + 3 files changed, 25 insertions(+) + +--- a/drivers/scsi/scsi.c ++++ b/drivers/scsi/scsi.c +@@ -465,10 +465,14 @@ void scsi_attach_vpd(struct scsi_device + return; + + for (i = 4; i < vpd_buf->len; i++) { ++ if (vpd_buf->data[i] == 0x0) ++ scsi_update_vpd_page(sdev, 0x0, &sdev->vpd_pg0); + if (vpd_buf->data[i] == 0x80) + scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80); + if (vpd_buf->data[i] == 0x83) + scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83); ++ if (vpd_buf->data[i] == 0x89) ++ scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89); + } + kfree(vpd_buf); + } +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -437,6 +437,7 @@ static void scsi_device_dev_release_user + struct device *parent; + struct list_head *this, *tmp; + struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; ++ struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL; + unsigned long flags; + struct module *mod; + +@@ -469,16 +470,24 @@ static void scsi_device_dev_release_user + sdev->request_queue = NULL; + + mutex_lock(&sdev->inquiry_mutex); ++ rcu_swap_protected(sdev->vpd_pg0, vpd_pg0, ++ lockdep_is_held(&sdev->inquiry_mutex)); + rcu_swap_protected(sdev->vpd_pg80, vpd_pg80, + lockdep_is_held(&sdev->inquiry_mutex)); + rcu_swap_protected(sdev->vpd_pg83, vpd_pg83, + lockdep_is_held(&sdev->inquiry_mutex)); ++ rcu_swap_protected(sdev->vpd_pg89, vpd_pg89, ++ lockdep_is_held(&sdev->inquiry_mutex)); + mutex_unlock(&sdev->inquiry_mutex); + ++ if (vpd_pg0) ++ kfree_rcu(vpd_pg0, rcu); + if (vpd_pg83) + kfree_rcu(vpd_pg83, rcu); + if (vpd_pg80) + kfree_rcu(vpd_pg80, rcu); ++ if (vpd_pg89) ++ kfree_rcu(vpd_pg89, rcu); + kfree(sdev->inquiry); + kfree(sdev); + +@@ -883,6 +892,8 @@ static struct bin_attribute dev_attr_vpd + + sdev_vpd_pg_attr(pg83); + sdev_vpd_pg_attr(pg80); ++sdev_vpd_pg_attr(pg89); ++sdev_vpd_pg_attr(pg0); + + static ssize_t show_inquiry(struct file *filep, struct kobject *kobj, + struct bin_attribute *bin_attr, +@@ -1215,12 +1226,18 @@ static umode_t scsi_sdev_bin_attr_is_vis + struct scsi_device *sdev = to_scsi_device(dev); + + ++ if (attr == &dev_attr_vpd_pg0 && !sdev->vpd_pg0) ++ return 0; ++ + if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80) + return 0; + + if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83) + return 0; + ++ if (attr == &dev_attr_vpd_pg89 && !sdev->vpd_pg89) ++ return 0; ++ + return S_IRUGO; + } + +@@ -1263,8 +1280,10 @@ static struct attribute *scsi_sdev_attrs + }; + + static struct bin_attribute *scsi_sdev_bin_attrs[] = { ++ &dev_attr_vpd_pg0, + &dev_attr_vpd_pg83, + &dev_attr_vpd_pg80, ++ &dev_attr_vpd_pg89, + &dev_attr_inquiry, + NULL + }; +--- a/include/scsi/scsi_device.h ++++ b/include/scsi/scsi_device.h +@@ -140,8 +140,10 @@ struct scsi_device { + const char * rev; /* ... "nullnullnullnull" before scan */ + + #define SCSI_VPD_PG_LEN 255 ++ struct scsi_vpd __rcu *vpd_pg0; + struct scsi_vpd __rcu *vpd_pg83; + struct scsi_vpd __rcu *vpd_pg80; ++ struct scsi_vpd __rcu *vpd_pg89; + unsigned char current_tag; /* current tag */ + struct scsi_target *sdev_target; /* used only for single_lun */ + diff --git a/ipq806x/backport-5.4/801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch b/ipq806x/backport-5.4/801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch new file mode 100644 index 0000000..32a6297 --- /dev/null +++ b/ipq806x/backport-5.4/801-v5.5-hwmon-Driver-for-disk-and-solid-state-drives-with-te.patch @@ -0,0 +1,737 @@ +From 5b46903d8bf372e563bf2150d46b87fff197a109 Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Thu, 28 Nov 2019 21:34:40 -0800 +Subject: [PATCH] hwmon: Driver for disk and solid state drives with + temperature sensors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reading the temperature of ATA drives has been supported for years +by userspace tools such as smarttools or hddtemp. The downside of +such tools is that they need to run with super-user privilege, that +the temperatures are not reported by standard tools such as 'sensors' +or 'libsensors', and that drive temperatures are not available for use +in the kernel's thermal subsystem. + +This driver solves this problem by adding support for reading the +temperature of ATA drives from the kernel using the hwmon API and +by adding a temperature zone for each drive. + +With this driver, the hard disk temperature can be read using the +unprivileged 'sensors' application: + +$ sensors drivetemp-scsi-1-0 +drivetemp-scsi-1-0 +Adapter: SCSI adapter +temp1: +23.0°C + +or directly from sysfs: + +$ grep . /sys/class/hwmon/hwmon9/{name,temp1_input} +/sys/class/hwmon/hwmon9/name:drivetemp +/sys/class/hwmon/hwmon9/temp1_input:23000 + +If the drive supports SCT transport and reports temperature limits, +those are reported as well. + +drivetemp-scsi-0-0 +Adapter: SCSI adapter +temp1: +27.0°C (low = +0.0°C, high = +60.0°C) + (crit low = -41.0°C, crit = +85.0°C) + (lowest = +23.0°C, highest = +34.0°C) + +The driver attempts to use SCT Command Transport to read the drive +temperature. If the SCT Command Transport feature set is not available, +or if it does not report the drive temperature, drive temperatures may +be readable through SMART attributes. Since SMART attributes are not well +defined, this method is only used as fallback mechanism. + +Cc: Chris Healy +Cc: Linus Walleij +Cc: Martin K. Petersen +Cc: Bart Van Assche +Reviewed-by: Linus Walleij +Tested-by: Linus Walleij +Signed-off-by: Guenter Roeck +--- + Documentation/hwmon/drivetemp.rst | 52 +++ + Documentation/hwmon/index.rst | 1 + + drivers/hwmon/Kconfig | 10 + + drivers/hwmon/Makefile | 1 + + drivers/hwmon/drivetemp.c | 574 ++++++++++++++++++++++++++++++ + 5 files changed, 638 insertions(+) + create mode 100644 Documentation/hwmon/drivetemp.rst + create mode 100644 drivers/hwmon/drivetemp.c + +--- /dev/null ++++ b/Documentation/hwmon/drivetemp.rst +@@ -0,0 +1,52 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++Kernel driver drivetemp ++======================= ++ ++ ++References ++---------- ++ ++ANS T13/1699-D ++Information technology - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) ++ ++ANS Project T10/BSR INCITS 513 ++Information technology - SCSI Primary Commands - 4 (SPC-4) ++ ++ANS Project INCITS 557 ++Information technology - SCSI / ATA Translation - 5 (SAT-5) ++ ++ ++Description ++----------- ++ ++This driver supports reporting the temperature of disk and solid state ++drives with temperature sensors. ++ ++If supported, it uses the ATA SCT Command Transport feature to read ++the current drive temperature and, if available, temperature limits ++as well as historic minimum and maximum temperatures. If SCT Command ++Transport is not supported, the driver uses SMART attributes to read ++the drive temperature. ++ ++ ++Sysfs entries ++------------- ++ ++Only the temp1_input attribute is always available. Other attributes are ++available only if reported by the drive. All temperatures are reported in ++milli-degrees Celsius. ++ ++======================= ===================================================== ++temp1_input Current drive temperature ++temp1_lcrit Minimum temperature limit. Operating the device below ++ this temperature may cause physical damage to the ++ device. ++temp1_min Minimum recommended continuous operating limit ++temp1_max Maximum recommended continuous operating temperature ++temp1_crit Maximum temperature limit. Operating the device above ++ this temperature may cause physical damage to the ++ device. ++temp1_lowest Minimum temperature seen this power cycle ++temp1_highest Maximum temperature seen this power cycle ++======================= ===================================================== +--- a/Documentation/hwmon/index.rst ++++ b/Documentation/hwmon/index.rst +@@ -45,6 +45,7 @@ Hardware Monitoring Kernel Drivers + da9052 + da9055 + dme1737 ++ drivetemp + ds1621 + ds620 + emc1403 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -385,6 +385,16 @@ config SENSORS_ATXP1 + This driver can also be built as a module. If so, the module + will be called atxp1. + ++config SENSORS_DRIVETEMP ++ tristate "Hard disk drives with temperature sensors" ++ depends on SCSI && ATA ++ help ++ If you say yes you get support for the temperature sensor on ++ hard disk drives. ++ ++ This driver can also be built as a module. If so, the module ++ will be called satatemp. ++ + config SENSORS_DS620 + tristate "Dallas Semiconductor DS620" + depends on I2C +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -56,6 +56,7 @@ obj-$(CONFIG_SENSORS_DA9052_ADC)+= da905 + obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o + obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o + obj-$(CONFIG_SENSORS_DME1737) += dme1737.o ++obj-$(CONFIG_SENSORS_DRIVETEMP) += drivetemp.o + obj-$(CONFIG_SENSORS_DS620) += ds620.o + obj-$(CONFIG_SENSORS_DS1621) += ds1621.o + obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o +--- /dev/null ++++ b/drivers/hwmon/drivetemp.c +@@ -0,0 +1,574 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Hwmon client for disk and solid state drives with temperature sensors ++ * Copyright (C) 2019 Zodiac Inflight Innovations ++ * ++ * With input from: ++ * Hwmon client for S.M.A.R.T. hard disk drives with temperature sensors. ++ * (C) 2018 Linus Walleij ++ * ++ * hwmon: Driver for SCSI/ATA temperature sensors ++ * by Constantin Baranov , submitted September 2009 ++ * ++ * This drive supports reporting the temperatire of SATA drives. It can be ++ * easily extended to report the temperature of SCSI drives. ++ * ++ * The primary means to read drive temperatures and temperature limits ++ * for ATA drives is the SCT Command Transport feature set as specified in ++ * ATA8-ACS. ++ * It can be used to read the current drive temperature, temperature limits, ++ * and historic minimum and maximum temperatures. The SCT Command Transport ++ * feature set is documented in "AT Attachment 8 - ATA/ATAPI Command Set ++ * (ATA8-ACS)". ++ * ++ * If the SCT Command Transport feature set is not available, drive temperatures ++ * may be readable through SMART attributes. Since SMART attributes are not well ++ * defined, this method is only used as fallback mechanism. ++ * ++ * There are three SMART attributes which may report drive temperatures. ++ * Those are defined as follows (from ++ * http://www.cropel.com/library/smart-attribute-list.aspx). ++ * ++ * 190 Temperature Temperature, monitored by a sensor somewhere inside ++ * the drive. Raw value typicaly holds the actual ++ * temperature (hexadecimal) in its rightmost two digits. ++ * ++ * 194 Temperature Temperature, monitored by a sensor somewhere inside ++ * the drive. Raw value typicaly holds the actual ++ * temperature (hexadecimal) in its rightmost two digits. ++ * ++ * 231 Temperature Temperature, monitored by a sensor somewhere inside ++ * the drive. Raw value typicaly holds the actual ++ * temperature (hexadecimal) in its rightmost two digits. ++ * ++ * Wikipedia defines attributes a bit differently. ++ * ++ * 190 Temperature Value is equal to (100-temp. °C), allowing manufacturer ++ * Difference or to set a minimum threshold which corresponds to a ++ * Airflow maximum temperature. This also follows the convention of ++ * Temperature 100 being a best-case value and lower values being ++ * undesirable. However, some older drives may instead ++ * report raw Temperature (identical to 0xC2) or ++ * Temperature minus 50 here. ++ * 194 Temperature or Indicates the device temperature, if the appropriate ++ * Temperature sensor is fitted. Lowest byte of the raw value contains ++ * Celsius the exact temperature value (Celsius degrees). ++ * 231 Life Left Indicates the approximate SSD life left, in terms of ++ * (SSDs) or program/erase cycles or available reserved blocks. ++ * Temperature A normalized value of 100 represents a new drive, with ++ * a threshold value at 10 indicating a need for ++ * replacement. A value of 0 may mean that the drive is ++ * operating in read-only mode to allow data recovery. ++ * Previously (pre-2010) occasionally used for Drive ++ * Temperature (more typically reported at 0xC2). ++ * ++ * Common denominator is that the first raw byte reports the temperature ++ * in degrees C on almost all drives. Some drives may report a fractional ++ * temperature in the second raw byte. ++ * ++ * Known exceptions (from libatasmart): ++ * - SAMSUNG SV0412H and SAMSUNG SV1204H) report the temperature in 10th ++ * degrees C in the first two raw bytes. ++ * - A few Maxtor drives report an unknown or bad value in attribute 194. ++ * - Certain Apple SSD drives report an unknown value in attribute 190. ++ * Only certain firmware versions are affected. ++ * ++ * Those exceptions affect older ATA drives and are currently ignored. ++ * Also, the second raw byte (possibly reporting the fractional temperature) ++ * is currently ignored. ++ * ++ * Many drives also report temperature limits in additional SMART data raw ++ * bytes. The format of those is not well defined and varies widely. ++ * The driver does not currently attempt to report those limits. ++ * ++ * According to data in smartmontools, attribute 231 is rarely used to report ++ * drive temperatures. At the same time, several drives report SSD life left ++ * in attribute 231, but do not support temperature sensors. For this reason, ++ * attribute 231 is currently ignored. ++ * ++ * Following above definitions, temperatures are reported as follows. ++ * If SCT Command Transport is supported, it is used to read the ++ * temperature and, if available, temperature limits. ++ * - Otherwise, if SMART attribute 194 is supported, it is used to read ++ * the temperature. ++ * - Otherwise, if SMART attribute 190 is supported, it is used to read ++ * the temperature. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct drivetemp_data { ++ struct list_head list; /* list of instantiated devices */ ++ struct mutex lock; /* protect data buffer accesses */ ++ struct scsi_device *sdev; /* SCSI device */ ++ struct device *dev; /* instantiating device */ ++ struct device *hwdev; /* hardware monitoring device */ ++ u8 smartdata[ATA_SECT_SIZE]; /* local buffer */ ++ int (*get_temp)(struct drivetemp_data *st, u32 attr, long *val); ++ bool have_temp_lowest; /* lowest temp in SCT status */ ++ bool have_temp_highest; /* highest temp in SCT status */ ++ bool have_temp_min; /* have min temp */ ++ bool have_temp_max; /* have max temp */ ++ bool have_temp_lcrit; /* have lower critical limit */ ++ bool have_temp_crit; /* have critical limit */ ++ int temp_min; /* min temp */ ++ int temp_max; /* max temp */ ++ int temp_lcrit; /* lower critical limit */ ++ int temp_crit; /* critical limit */ ++}; ++ ++static LIST_HEAD(drivetemp_devlist); ++ ++#define ATA_MAX_SMART_ATTRS 30 ++#define SMART_TEMP_PROP_190 190 ++#define SMART_TEMP_PROP_194 194 ++ ++#define SCT_STATUS_REQ_ADDR 0xe0 ++#define SCT_STATUS_VERSION_LOW 0 /* log byte offsets */ ++#define SCT_STATUS_VERSION_HIGH 1 ++#define SCT_STATUS_TEMP 200 ++#define SCT_STATUS_TEMP_LOWEST 201 ++#define SCT_STATUS_TEMP_HIGHEST 202 ++#define SCT_READ_LOG_ADDR 0xe1 ++#define SMART_READ_LOG 0xd5 ++#define SMART_WRITE_LOG 0xd6 ++ ++#define INVALID_TEMP 0x80 ++ ++#define temp_is_valid(temp) ((temp) != INVALID_TEMP) ++#define temp_from_sct(temp) (((s8)(temp)) * 1000) ++ ++static inline bool ata_id_smart_supported(u16 *id) ++{ ++ return id[ATA_ID_COMMAND_SET_1] & BIT(0); ++} ++ ++static inline bool ata_id_smart_enabled(u16 *id) ++{ ++ return id[ATA_ID_CFS_ENABLE_1] & BIT(0); ++} ++ ++static int drivetemp_scsi_command(struct drivetemp_data *st, ++ u8 ata_command, u8 feature, ++ u8 lba_low, u8 lba_mid, u8 lba_high) ++{ ++ u8 scsi_cmd[MAX_COMMAND_SIZE]; ++ int data_dir; ++ ++ memset(scsi_cmd, 0, sizeof(scsi_cmd)); ++ scsi_cmd[0] = ATA_16; ++ if (ata_command == ATA_CMD_SMART && feature == SMART_WRITE_LOG) { ++ scsi_cmd[1] = (5 << 1); /* PIO Data-out */ ++ /* ++ * No off.line or cc, write to dev, block count in sector count ++ * field. ++ */ ++ scsi_cmd[2] = 0x06; ++ data_dir = DMA_TO_DEVICE; ++ } else { ++ scsi_cmd[1] = (4 << 1); /* PIO Data-in */ ++ /* ++ * No off.line or cc, read from dev, block count in sector count ++ * field. ++ */ ++ scsi_cmd[2] = 0x0e; ++ data_dir = DMA_FROM_DEVICE; ++ } ++ scsi_cmd[4] = feature; ++ scsi_cmd[6] = 1; /* 1 sector */ ++ scsi_cmd[8] = lba_low; ++ scsi_cmd[10] = lba_mid; ++ scsi_cmd[12] = lba_high; ++ scsi_cmd[14] = ata_command; ++ ++ return scsi_execute_req(st->sdev, scsi_cmd, data_dir, ++ st->smartdata, ATA_SECT_SIZE, NULL, HZ, 5, ++ NULL); ++} ++ ++static int drivetemp_ata_command(struct drivetemp_data *st, u8 feature, ++ u8 select) ++{ ++ return drivetemp_scsi_command(st, ATA_CMD_SMART, feature, select, ++ ATA_SMART_LBAM_PASS, ATA_SMART_LBAH_PASS); ++} ++ ++static int drivetemp_get_smarttemp(struct drivetemp_data *st, u32 attr, ++ long *temp) ++{ ++ u8 *buf = st->smartdata; ++ bool have_temp = false; ++ u8 temp_raw; ++ u8 csum; ++ int err; ++ int i; ++ ++ err = drivetemp_ata_command(st, ATA_SMART_READ_VALUES, 0); ++ if (err) ++ return err; ++ ++ /* Checksum the read value table */ ++ csum = 0; ++ for (i = 0; i < ATA_SECT_SIZE; i++) ++ csum += buf[i]; ++ if (csum) { ++ dev_dbg(&st->sdev->sdev_gendev, ++ "checksum error reading SMART values\n"); ++ return -EIO; ++ } ++ ++ for (i = 0; i < ATA_MAX_SMART_ATTRS; i++) { ++ u8 *attr = buf + i * 12; ++ int id = attr[2]; ++ ++ if (!id) ++ continue; ++ ++ if (id == SMART_TEMP_PROP_190) { ++ temp_raw = attr[7]; ++ have_temp = true; ++ } ++ if (id == SMART_TEMP_PROP_194) { ++ temp_raw = attr[7]; ++ have_temp = true; ++ break; ++ } ++ } ++ ++ if (have_temp) { ++ *temp = temp_raw * 1000; ++ return 0; ++ } ++ ++ return -ENXIO; ++} ++ ++static int drivetemp_get_scttemp(struct drivetemp_data *st, u32 attr, long *val) ++{ ++ u8 *buf = st->smartdata; ++ int err; ++ ++ err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR); ++ if (err) ++ return err; ++ switch (attr) { ++ case hwmon_temp_input: ++ *val = temp_from_sct(buf[SCT_STATUS_TEMP]); ++ break; ++ case hwmon_temp_lowest: ++ *val = temp_from_sct(buf[SCT_STATUS_TEMP_LOWEST]); ++ break; ++ case hwmon_temp_highest: ++ *val = temp_from_sct(buf[SCT_STATUS_TEMP_HIGHEST]); ++ break; ++ default: ++ err = -EINVAL; ++ break; ++ } ++ return err; ++} ++ ++static int drivetemp_identify_sata(struct drivetemp_data *st) ++{ ++ struct scsi_device *sdev = st->sdev; ++ u8 *buf = st->smartdata; ++ struct scsi_vpd *vpd; ++ bool is_ata, is_sata; ++ bool have_sct_data_table; ++ bool have_sct_temp; ++ bool have_smart; ++ bool have_sct; ++ u16 *ata_id; ++ u16 version; ++ long temp; ++ int err; ++ ++ /* SCSI-ATA Translation present? */ ++ rcu_read_lock(); ++ vpd = rcu_dereference(sdev->vpd_pg89); ++ ++ /* ++ * Verify that ATA IDENTIFY DEVICE data is included in ATA Information ++ * VPD and that the drive implements the SATA protocol. ++ */ ++ if (!vpd || vpd->len < 572 || vpd->data[56] != ATA_CMD_ID_ATA || ++ vpd->data[36] != 0x34) { ++ rcu_read_unlock(); ++ return -ENODEV; ++ } ++ ata_id = (u16 *)&vpd->data[60]; ++ is_ata = ata_id_is_ata(ata_id); ++ is_sata = ata_id_is_sata(ata_id); ++ have_sct = ata_id_sct_supported(ata_id); ++ have_sct_data_table = ata_id_sct_data_tables(ata_id); ++ have_smart = ata_id_smart_supported(ata_id) && ++ ata_id_smart_enabled(ata_id); ++ ++ rcu_read_unlock(); ++ ++ /* bail out if this is not a SATA device */ ++ if (!is_ata || !is_sata) ++ return -ENODEV; ++ if (!have_sct) ++ goto skip_sct; ++ ++ err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR); ++ if (err) ++ goto skip_sct; ++ ++ version = (buf[SCT_STATUS_VERSION_HIGH] << 8) | ++ buf[SCT_STATUS_VERSION_LOW]; ++ if (version != 2 && version != 3) ++ goto skip_sct; ++ ++ have_sct_temp = temp_is_valid(buf[SCT_STATUS_TEMP]); ++ if (!have_sct_temp) ++ goto skip_sct; ++ ++ st->have_temp_lowest = temp_is_valid(buf[SCT_STATUS_TEMP_LOWEST]); ++ st->have_temp_highest = temp_is_valid(buf[SCT_STATUS_TEMP_HIGHEST]); ++ ++ if (!have_sct_data_table) ++ goto skip_sct; ++ ++ /* Request and read temperature history table */ ++ memset(buf, '\0', sizeof(st->smartdata)); ++ buf[0] = 5; /* data table command */ ++ buf[2] = 1; /* read table */ ++ buf[4] = 2; /* temperature history table */ ++ ++ err = drivetemp_ata_command(st, SMART_WRITE_LOG, SCT_STATUS_REQ_ADDR); ++ if (err) ++ goto skip_sct_data; ++ ++ err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_READ_LOG_ADDR); ++ if (err) ++ goto skip_sct_data; ++ ++ /* ++ * Temperature limits per AT Attachment 8 - ++ * ATA/ATAPI Command Set (ATA8-ACS) ++ */ ++ st->have_temp_max = temp_is_valid(buf[6]); ++ st->have_temp_crit = temp_is_valid(buf[7]); ++ st->have_temp_min = temp_is_valid(buf[8]); ++ st->have_temp_lcrit = temp_is_valid(buf[9]); ++ ++ st->temp_max = temp_from_sct(buf[6]); ++ st->temp_crit = temp_from_sct(buf[7]); ++ st->temp_min = temp_from_sct(buf[8]); ++ st->temp_lcrit = temp_from_sct(buf[9]); ++ ++skip_sct_data: ++ if (have_sct_temp) { ++ st->get_temp = drivetemp_get_scttemp; ++ return 0; ++ } ++skip_sct: ++ if (!have_smart) ++ return -ENODEV; ++ st->get_temp = drivetemp_get_smarttemp; ++ return drivetemp_get_smarttemp(st, hwmon_temp_input, &temp); ++} ++ ++static int drivetemp_identify(struct drivetemp_data *st) ++{ ++ struct scsi_device *sdev = st->sdev; ++ ++ /* Bail out immediately if there is no inquiry data */ ++ if (!sdev->inquiry || sdev->inquiry_len < 16) ++ return -ENODEV; ++ ++ /* Disk device? */ ++ if (sdev->type != TYPE_DISK && sdev->type != TYPE_ZBC) ++ return -ENODEV; ++ ++ return drivetemp_identify_sata(st); ++} ++ ++static int drivetemp_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct drivetemp_data *st = dev_get_drvdata(dev); ++ int err = 0; ++ ++ if (type != hwmon_temp) ++ return -EINVAL; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ case hwmon_temp_lowest: ++ case hwmon_temp_highest: ++ mutex_lock(&st->lock); ++ err = st->get_temp(st, attr, val); ++ mutex_unlock(&st->lock); ++ break; ++ case hwmon_temp_lcrit: ++ *val = st->temp_lcrit; ++ break; ++ case hwmon_temp_min: ++ *val = st->temp_min; ++ break; ++ case hwmon_temp_max: ++ *val = st->temp_max; ++ break; ++ case hwmon_temp_crit: ++ *val = st->temp_crit; ++ break; ++ default: ++ err = -EINVAL; ++ break; ++ } ++ return err; ++} ++ ++static umode_t drivetemp_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct drivetemp_data *st = data; ++ ++ switch (type) { ++ case hwmon_temp: ++ switch (attr) { ++ case hwmon_temp_input: ++ return 0444; ++ case hwmon_temp_lowest: ++ if (st->have_temp_lowest) ++ return 0444; ++ break; ++ case hwmon_temp_highest: ++ if (st->have_temp_highest) ++ return 0444; ++ break; ++ case hwmon_temp_min: ++ if (st->have_temp_min) ++ return 0444; ++ break; ++ case hwmon_temp_max: ++ if (st->have_temp_max) ++ return 0444; ++ break; ++ case hwmon_temp_lcrit: ++ if (st->have_temp_lcrit) ++ return 0444; ++ break; ++ case hwmon_temp_crit: ++ if (st->have_temp_crit) ++ return 0444; ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static const struct hwmon_channel_info *drivetemp_info[] = { ++ HWMON_CHANNEL_INFO(chip, ++ HWMON_C_REGISTER_TZ), ++ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | ++ HWMON_T_LOWEST | HWMON_T_HIGHEST | ++ HWMON_T_MIN | HWMON_T_MAX | ++ HWMON_T_LCRIT | HWMON_T_CRIT), ++ NULL ++}; ++ ++static const struct hwmon_ops drivetemp_ops = { ++ .is_visible = drivetemp_is_visible, ++ .read = drivetemp_read, ++}; ++ ++static const struct hwmon_chip_info drivetemp_chip_info = { ++ .ops = &drivetemp_ops, ++ .info = drivetemp_info, ++}; ++ ++/* ++ * The device argument points to sdev->sdev_dev. Its parent is ++ * sdev->sdev_gendev, which we can use to get the scsi_device pointer. ++ */ ++static int drivetemp_add(struct device *dev, struct class_interface *intf) ++{ ++ struct scsi_device *sdev = to_scsi_device(dev->parent); ++ struct drivetemp_data *st; ++ int err; ++ ++ st = kzalloc(sizeof(*st), GFP_KERNEL); ++ if (!st) ++ return -ENOMEM; ++ ++ st->sdev = sdev; ++ st->dev = dev; ++ mutex_init(&st->lock); ++ ++ if (drivetemp_identify(st)) { ++ err = -ENODEV; ++ goto abort; ++ } ++ ++ st->hwdev = hwmon_device_register_with_info(dev->parent, "drivetemp", ++ st, &drivetemp_chip_info, ++ NULL); ++ if (IS_ERR(st->hwdev)) { ++ err = PTR_ERR(st->hwdev); ++ goto abort; ++ } ++ ++ list_add(&st->list, &drivetemp_devlist); ++ return 0; ++ ++abort: ++ kfree(st); ++ return err; ++} ++ ++static void drivetemp_remove(struct device *dev, struct class_interface *intf) ++{ ++ struct drivetemp_data *st, *tmp; ++ ++ list_for_each_entry_safe(st, tmp, &drivetemp_devlist, list) { ++ if (st->dev == dev) { ++ list_del(&st->list); ++ hwmon_device_unregister(st->hwdev); ++ kfree(st); ++ break; ++ } ++ } ++} ++ ++static struct class_interface drivetemp_interface = { ++ .add_dev = drivetemp_add, ++ .remove_dev = drivetemp_remove, ++}; ++ ++static int __init drivetemp_init(void) ++{ ++ return scsi_register_interface(&drivetemp_interface); ++} ++ ++static void __exit drivetemp_exit(void) ++{ ++ scsi_unregister_interface(&drivetemp_interface); ++} ++ ++module_init(drivetemp_init); ++module_exit(drivetemp_exit); ++ ++MODULE_AUTHOR("Guenter Roeck "); ++MODULE_DESCRIPTION("Hard drive temperature monitor"); ++MODULE_LICENSE("GPL"); diff --git a/ipq806x/backport-5.4/801-v5.6-leds-populate-the-device-s-of_node.patch b/ipq806x/backport-5.4/801-v5.6-leds-populate-the-device-s-of_node.patch new file mode 100644 index 0000000..5c3b58c --- /dev/null +++ b/ipq806x/backport-5.4/801-v5.6-leds-populate-the-device-s-of_node.patch @@ -0,0 +1,36 @@ +From 7a349e8c535d7327bf80710323c725df47149b8d Mon Sep 17 00:00:00 2001 +From: Jean-Jacques Hiblot +Date: Sun, 5 Jan 2020 23:31:14 +0100 +Subject: [PATCH] leds: populate the device's of_node + +If initialization data is available and its fwnode is actually a +of_node, store this information in the led device's structure. This +will allow the device to use or provide OF-based API such (devm_xxx). + +Signed-off-by: Jean-Jacques Hiblot +Signed-off-by: Pavel Machek +[backport to 5.4] +--- + +--- a/drivers/leds/led-class.c ++++ b/drivers/leds/led-class.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include "leds.h" + + static struct class *leds_class; +@@ -277,8 +278,10 @@ int led_classdev_register_ext(struct dev + mutex_unlock(&led_cdev->led_access); + return PTR_ERR(led_cdev->dev); + } +- if (init_data && init_data->fwnode) ++ if (init_data && init_data->fwnode) { + led_cdev->dev->fwnode = init_data->fwnode; ++ led_cdev->dev->of_node = to_of_node(init_data->fwnode); ++ } + + if (ret) + dev_warn(parent, "Led %s renamed to %s due to name collision", diff --git a/ipq806x/backport-5.4/803-v5.8-i2c-pxa-use-official-address-byte-helper.patch b/ipq806x/backport-5.4/803-v5.8-i2c-pxa-use-official-address-byte-helper.patch new file mode 100644 index 0000000..a937b52 --- /dev/null +++ b/ipq806x/backport-5.4/803-v5.8-i2c-pxa-use-official-address-byte-helper.patch @@ -0,0 +1,59 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 01/17] i2c: pxa: use official address byte helper +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +i2c-pxa was created before i2c_8bit_addr_from_msg() was implemented, +and used its own i2c_pxa_addr_byte() which is functionally the same. +Sadly, it was never updated to use this new helper. Switch it over. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 21 +++++++-------------- + 1 file changed, 7 insertions(+), 14 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -674,16 +674,6 @@ static void i2c_pxa_slave_stop(struct px + * PXA I2C Master mode + */ + +-static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg) +-{ +- unsigned int addr = (msg->addr & 0x7f) << 1; +- +- if (msg->flags & I2C_M_RD) +- addr |= 1; +- +- return addr; +-} +- + static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) + { + u32 icr; +@@ -691,8 +681,8 @@ static inline void i2c_pxa_start_message + /* + * Step 1: target slave address into IDBR + */ +- writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); +- i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg); ++ i2c->req_slave_addr = i2c_8bit_addr_from_msg(i2c->msg); ++ writel(i2c->req_slave_addr, _IDBR(i2c)); + + /* + * Step 2: initiate the write. +@@ -1003,8 +993,8 @@ static void i2c_pxa_irq_txempty(struct p + /* + * Write the next address. + */ +- writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); +- i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg); ++ i2c->req_slave_addr = i2c_8bit_addr_from_msg(i2c->msg); ++ writel(i2c->req_slave_addr, _IDBR(i2c)); + + /* + * And trigger a repeated start, and send the byte. diff --git a/ipq806x/backport-5.4/804-v5.8-i2c-pxa-remove-unneeded-includes.patch b/ipq806x/backport-5.4/804-v5.8-i2c-pxa-remove-unneeded-includes.patch new file mode 100644 index 0000000..6a91132 --- /dev/null +++ b/ipq806x/backport-5.4/804-v5.8-i2c-pxa-remove-unneeded-includes.patch @@ -0,0 +1,37 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 02/17] i2c: pxa: remove unneeded includes +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +i2c-pxa does not need linux/sched.h nor linux/time.h includes, so +remove these. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -20,8 +20,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +@@ -35,8 +33,6 @@ + #include + #include + +-#include +- + struct pxa_reg_layout { + u32 ibmr; + u32 idbr; diff --git a/ipq806x/backport-5.4/805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch b/ipq806x/backport-5.4/805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch new file mode 100644 index 0000000..4d6dc7f --- /dev/null +++ b/ipq806x/backport-5.4/805-v5.8-i2c-pxa-re-arrange-includes-to-be-in-alphabetical-or.patch @@ -0,0 +1,52 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 03/17] i2c: pxa: re-arrange includes to be in alphabetical + order +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Arrange the includes to be in alphabetical order to help avoid +duplicated includes. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -16,22 +16,22 @@ + * Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood] + * Feb 2005: Rework slave mode handling [RMK] + */ +-#include +-#include +-#include +-#include ++#include + #include ++#include + #include +-#include ++#include + #include ++#include ++#include ++#include ++#include ++#include + #include + #include + #include +-#include +-#include +-#include +-#include + #include ++#include + + struct pxa_reg_layout { + u32 ibmr; diff --git a/ipq806x/backport-5.4/806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch b/ipq806x/backport-5.4/806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch new file mode 100644 index 0000000..9f09f9d --- /dev/null +++ b/ipq806x/backport-5.4/806-v5.8-i2c-pxa-re-arrange-functions-to-flow-better.patch @@ -0,0 +1,380 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 04/17] i2c: pxa: re-arrange functions to flow better +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Re-arrange the PXA I2C code to avoid forward declarations, and keep +similar functionality (e.g. the non-IRQ mode support) together. This +improves code readability. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 325 +++++++++++++++++------------------ + 1 file changed, 162 insertions(+), 163 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -326,7 +326,6 @@ static void i2c_pxa_scream_blue_murder(s + #endif /* ifdef DEBUG / else */ + + static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret); +-static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id); + + static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c) + { +@@ -697,34 +696,6 @@ static inline void i2c_pxa_stop_message( + writel(icr, _ICR(i2c)); + } + +-static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c) +-{ +- /* make timeout the same as for interrupt based functions */ +- long timeout = 2 * DEF_TIMEOUT; +- +- /* +- * Wait for the bus to become free. +- */ +- while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { +- udelay(1000); +- show_state(i2c); +- } +- +- if (timeout < 0) { +- show_state(i2c); +- dev_err(&i2c->adap.dev, +- "i2c_pxa: timeout waiting for bus free\n"); +- return I2C_RETRY; +- } +- +- /* +- * Set master mode. +- */ +- writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c)); +- +- return 0; +-} +- + /* + * PXA I2C send master code + * 1. Load master code to IDBR and send it. +@@ -753,140 +724,6 @@ static int i2c_pxa_send_mastercode(struc + return (timeout == 0) ? I2C_RETRY : 0; + } + +-static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c, +- struct i2c_msg *msg, int num) +-{ +- unsigned long timeout = 500000; /* 5 seconds */ +- int ret = 0; +- +- ret = i2c_pxa_pio_set_master(i2c); +- if (ret) +- goto out; +- +- i2c->msg = msg; +- i2c->msg_num = num; +- i2c->msg_idx = 0; +- i2c->msg_ptr = 0; +- i2c->irqlogidx = 0; +- +- i2c_pxa_start_message(i2c); +- +- while (i2c->msg_num > 0 && --timeout) { +- i2c_pxa_handler(0, i2c); +- udelay(10); +- } +- +- i2c_pxa_stop_message(i2c); +- +- /* +- * We place the return code in i2c->msg_idx. +- */ +- ret = i2c->msg_idx; +- +-out: +- if (timeout == 0) { +- i2c_pxa_scream_blue_murder(i2c, "timeout"); +- ret = I2C_RETRY; +- } +- +- return ret; +-} +- +-/* +- * We are protected by the adapter bus mutex. +- */ +-static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) +-{ +- long timeout; +- int ret; +- +- /* +- * Wait for the bus to become free. +- */ +- ret = i2c_pxa_wait_bus_not_busy(i2c); +- if (ret) { +- dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n"); +- goto out; +- } +- +- /* +- * Set master mode. +- */ +- ret = i2c_pxa_set_master(i2c); +- if (ret) { +- dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret); +- goto out; +- } +- +- if (i2c->high_mode) { +- ret = i2c_pxa_send_mastercode(i2c); +- if (ret) { +- dev_err(&i2c->adap.dev, "i2c_pxa_send_mastercode timeout\n"); +- goto out; +- } +- } +- +- spin_lock_irq(&i2c->lock); +- +- i2c->msg = msg; +- i2c->msg_num = num; +- i2c->msg_idx = 0; +- i2c->msg_ptr = 0; +- i2c->irqlogidx = 0; +- +- i2c_pxa_start_message(i2c); +- +- spin_unlock_irq(&i2c->lock); +- +- /* +- * The rest of the processing occurs in the interrupt handler. +- */ +- timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); +- i2c_pxa_stop_message(i2c); +- +- /* +- * We place the return code in i2c->msg_idx. +- */ +- ret = i2c->msg_idx; +- +- if (!timeout && i2c->msg_num) { +- i2c_pxa_scream_blue_murder(i2c, "timeout"); +- ret = I2C_RETRY; +- } +- +- out: +- return ret; +-} +- +-static int i2c_pxa_pio_xfer(struct i2c_adapter *adap, +- struct i2c_msg msgs[], int num) +-{ +- struct pxa_i2c *i2c = adap->algo_data; +- int ret, i; +- +- /* If the I2C controller is disabled we need to reset it +- (probably due to a suspend/resume destroying state). We do +- this here as we can then avoid worrying about resuming the +- controller before its users. */ +- if (!(readl(_ICR(i2c)) & ICR_IUE)) +- i2c_pxa_reset(i2c); +- +- for (i = adap->retries; i >= 0; i--) { +- ret = i2c_pxa_do_pio_xfer(i2c, msgs, num); +- if (ret != I2C_RETRY) +- goto out; +- +- if (i2c_debug) +- dev_dbg(&adap->dev, "Retrying transmission\n"); +- udelay(100); +- } +- i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); +- ret = -EREMOTEIO; +- out: +- i2c_pxa_set_slave(i2c, ret); +- return ret; +-} +- + /* + * i2c_pxa_master_complete - complete the message and wake up. + */ +@@ -1093,6 +930,71 @@ static irqreturn_t i2c_pxa_handler(int t + return IRQ_HANDLED; + } + ++/* ++ * We are protected by the adapter bus mutex. ++ */ ++static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) ++{ ++ long timeout; ++ int ret; ++ ++ /* ++ * Wait for the bus to become free. ++ */ ++ ret = i2c_pxa_wait_bus_not_busy(i2c); ++ if (ret) { ++ dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n"); ++ goto out; ++ } ++ ++ /* ++ * Set master mode. ++ */ ++ ret = i2c_pxa_set_master(i2c); ++ if (ret) { ++ dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret); ++ goto out; ++ } ++ ++ if (i2c->high_mode) { ++ ret = i2c_pxa_send_mastercode(i2c); ++ if (ret) { ++ dev_err(&i2c->adap.dev, "i2c_pxa_send_mastercode timeout\n"); ++ goto out; ++ } ++ } ++ ++ spin_lock_irq(&i2c->lock); ++ ++ i2c->msg = msg; ++ i2c->msg_num = num; ++ i2c->msg_idx = 0; ++ i2c->msg_ptr = 0; ++ i2c->irqlogidx = 0; ++ ++ i2c_pxa_start_message(i2c); ++ ++ spin_unlock_irq(&i2c->lock); ++ ++ /* ++ * The rest of the processing occurs in the interrupt handler. ++ */ ++ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); ++ i2c_pxa_stop_message(i2c); ++ ++ /* ++ * We place the return code in i2c->msg_idx. ++ */ ++ ret = i2c->msg_idx; ++ ++ if (!timeout && i2c->msg_num) { ++ i2c_pxa_scream_blue_murder(i2c, "timeout"); ++ ret = I2C_RETRY; ++ } ++ ++ out: ++ return ret; ++} + + static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) + { +@@ -1126,6 +1028,103 @@ static const struct i2c_algorithm i2c_px + .functionality = i2c_pxa_functionality, + }; + ++/* Non-interrupt mode support */ ++static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c) ++{ ++ /* make timeout the same as for interrupt based functions */ ++ long timeout = 2 * DEF_TIMEOUT; ++ ++ /* ++ * Wait for the bus to become free. ++ */ ++ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { ++ udelay(1000); ++ show_state(i2c); ++ } ++ ++ if (timeout < 0) { ++ show_state(i2c); ++ dev_err(&i2c->adap.dev, ++ "i2c_pxa: timeout waiting for bus free\n"); ++ return I2C_RETRY; ++ } ++ ++ /* ++ * Set master mode. ++ */ ++ writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c)); ++ ++ return 0; ++} ++ ++static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c, ++ struct i2c_msg *msg, int num) ++{ ++ unsigned long timeout = 500000; /* 5 seconds */ ++ int ret = 0; ++ ++ ret = i2c_pxa_pio_set_master(i2c); ++ if (ret) ++ goto out; ++ ++ i2c->msg = msg; ++ i2c->msg_num = num; ++ i2c->msg_idx = 0; ++ i2c->msg_ptr = 0; ++ i2c->irqlogidx = 0; ++ ++ i2c_pxa_start_message(i2c); ++ ++ while (i2c->msg_num > 0 && --timeout) { ++ i2c_pxa_handler(0, i2c); ++ udelay(10); ++ } ++ ++ i2c_pxa_stop_message(i2c); ++ ++ /* ++ * We place the return code in i2c->msg_idx. ++ */ ++ ret = i2c->msg_idx; ++ ++out: ++ if (timeout == 0) { ++ i2c_pxa_scream_blue_murder(i2c, "timeout"); ++ ret = I2C_RETRY; ++ } ++ ++ return ret; ++} ++ ++static int i2c_pxa_pio_xfer(struct i2c_adapter *adap, ++ struct i2c_msg msgs[], int num) ++{ ++ struct pxa_i2c *i2c = adap->algo_data; ++ int ret, i; ++ ++ /* If the I2C controller is disabled we need to reset it ++ (probably due to a suspend/resume destroying state). We do ++ this here as we can then avoid worrying about resuming the ++ controller before its users. */ ++ if (!(readl(_ICR(i2c)) & ICR_IUE)) ++ i2c_pxa_reset(i2c); ++ ++ for (i = adap->retries; i >= 0; i--) { ++ ret = i2c_pxa_do_pio_xfer(i2c, msgs, num); ++ if (ret != I2C_RETRY) ++ goto out; ++ ++ if (i2c_debug) ++ dev_dbg(&adap->dev, "Retrying transmission\n"); ++ udelay(100); ++ } ++ i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); ++ ret = -EREMOTEIO; ++ out: ++ i2c_pxa_set_slave(i2c, ret); ++ return ret; ++} ++ + static const struct i2c_algorithm i2c_pxa_pio_algorithm = { + .master_xfer = i2c_pxa_pio_xfer, + .functionality = i2c_pxa_functionality, diff --git a/ipq806x/backport-5.4/807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch b/ipq806x/backport-5.4/807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch new file mode 100644 index 0000000..afade04 --- /dev/null +++ b/ipq806x/backport-5.4/807-v5.8-i2c-pxa-re-arrange-register-field-definitions.patch @@ -0,0 +1,161 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 05/17] i2c: pxa: re-arrange register field definitions +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Arrange the register field definitions to be grouped together, rather +than the Armada-3700 definitions being separated from the rest of the +definitions. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 113 ++++++++++++++++------------------- + 1 file changed, 53 insertions(+), 60 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -33,6 +33,56 @@ + #include + #include + ++/* I2C register field definitions */ ++#define ICR_START (1 << 0) /* start bit */ ++#define ICR_STOP (1 << 1) /* stop bit */ ++#define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */ ++#define ICR_TB (1 << 3) /* transfer byte bit */ ++#define ICR_MA (1 << 4) /* master abort */ ++#define ICR_SCLE (1 << 5) /* master clock enable */ ++#define ICR_IUE (1 << 6) /* unit enable */ ++#define ICR_GCD (1 << 7) /* general call disable */ ++#define ICR_ITEIE (1 << 8) /* enable tx interrupts */ ++#define ICR_IRFIE (1 << 9) /* enable rx interrupts */ ++#define ICR_BEIE (1 << 10) /* enable bus error ints */ ++#define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */ ++#define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */ ++#define ICR_SADIE (1 << 13) /* slave address detected int enable */ ++#define ICR_UR (1 << 14) /* unit reset */ ++#define ICR_FM (1 << 15) /* fast mode */ ++#define ICR_HS (1 << 16) /* High Speed mode */ ++#define ICR_A3700_FM (1 << 16) /* fast mode for armada-3700 */ ++#define ICR_A3700_HS (1 << 17) /* high speed mode for armada-3700 */ ++#define ICR_GPIOEN (1 << 19) /* enable GPIO mode for SCL in HS */ ++ ++#define ISR_RWM (1 << 0) /* read/write mode */ ++#define ISR_ACKNAK (1 << 1) /* ack/nak status */ ++#define ISR_UB (1 << 2) /* unit busy */ ++#define ISR_IBB (1 << 3) /* bus busy */ ++#define ISR_SSD (1 << 4) /* slave stop detected */ ++#define ISR_ALD (1 << 5) /* arbitration loss detected */ ++#define ISR_ITE (1 << 6) /* tx buffer empty */ ++#define ISR_IRF (1 << 7) /* rx buffer full */ ++#define ISR_GCAD (1 << 8) /* general call address detected */ ++#define ISR_SAD (1 << 9) /* slave address detected */ ++#define ISR_BED (1 << 10) /* bus error no ACK/NAK */ ++ ++#define ILCR_SLV_SHIFT 0 ++#define ILCR_SLV_MASK (0x1FF << ILCR_SLV_SHIFT) ++#define ILCR_FLV_SHIFT 9 ++#define ILCR_FLV_MASK (0x1FF << ILCR_FLV_SHIFT) ++#define ILCR_HLVL_SHIFT 18 ++#define ILCR_HLVL_MASK (0x1FF << ILCR_HLVL_SHIFT) ++#define ILCR_HLVH_SHIFT 27 ++#define ILCR_HLVH_MASK (0x1F << ILCR_HLVH_SHIFT) ++ ++#define IWCR_CNT_SHIFT 0 ++#define IWCR_CNT_MASK (0x1F << IWCR_CNT_SHIFT) ++#define IWCR_HS_CNT1_SHIFT 5 ++#define IWCR_HS_CNT1_MASK (0x1F << IWCR_HS_CNT1_SHIFT) ++#define IWCR_HS_CNT2_SHIFT 10 ++#define IWCR_HS_CNT2_MASK (0x1F << IWCR_HS_CNT2_SHIFT) ++ + struct pxa_reg_layout { + u32 ibmr; + u32 idbr; +@@ -53,12 +103,7 @@ enum pxa_i2c_types { + REGS_A3700, + }; + +-#define ICR_BUSMODE_FM (1 << 16) /* shifted fast mode for armada-3700 */ +-#define ICR_BUSMODE_HS (1 << 17) /* shifted high speed mode for armada-3700 */ +- +-/* +- * I2C registers definitions +- */ ++/* I2C register layout definitions */ + static struct pxa_reg_layout pxa_reg_layout[] = { + [REGS_PXA2XX] = { + .ibmr = 0x00, +@@ -96,8 +141,8 @@ static struct pxa_reg_layout pxa_reg_lay + .icr = 0x08, + .isr = 0x0c, + .isar = 0x10, +- .fm = ICR_BUSMODE_FM, +- .hs = ICR_BUSMODE_HS, ++ .fm = ICR_A3700_FM, ++ .hs = ICR_A3700_HS, + }, + }; + +@@ -111,58 +156,6 @@ static const struct platform_device_id i + }; + MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); + +-/* +- * I2C bit definitions +- */ +- +-#define ICR_START (1 << 0) /* start bit */ +-#define ICR_STOP (1 << 1) /* stop bit */ +-#define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */ +-#define ICR_TB (1 << 3) /* transfer byte bit */ +-#define ICR_MA (1 << 4) /* master abort */ +-#define ICR_SCLE (1 << 5) /* master clock enable */ +-#define ICR_IUE (1 << 6) /* unit enable */ +-#define ICR_GCD (1 << 7) /* general call disable */ +-#define ICR_ITEIE (1 << 8) /* enable tx interrupts */ +-#define ICR_IRFIE (1 << 9) /* enable rx interrupts */ +-#define ICR_BEIE (1 << 10) /* enable bus error ints */ +-#define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */ +-#define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */ +-#define ICR_SADIE (1 << 13) /* slave address detected int enable */ +-#define ICR_UR (1 << 14) /* unit reset */ +-#define ICR_FM (1 << 15) /* fast mode */ +-#define ICR_HS (1 << 16) /* High Speed mode */ +-#define ICR_GPIOEN (1 << 19) /* enable GPIO mode for SCL in HS */ +- +-#define ISR_RWM (1 << 0) /* read/write mode */ +-#define ISR_ACKNAK (1 << 1) /* ack/nak status */ +-#define ISR_UB (1 << 2) /* unit busy */ +-#define ISR_IBB (1 << 3) /* bus busy */ +-#define ISR_SSD (1 << 4) /* slave stop detected */ +-#define ISR_ALD (1 << 5) /* arbitration loss detected */ +-#define ISR_ITE (1 << 6) /* tx buffer empty */ +-#define ISR_IRF (1 << 7) /* rx buffer full */ +-#define ISR_GCAD (1 << 8) /* general call address detected */ +-#define ISR_SAD (1 << 9) /* slave address detected */ +-#define ISR_BED (1 << 10) /* bus error no ACK/NAK */ +- +-/* bit field shift & mask */ +-#define ILCR_SLV_SHIFT 0 +-#define ILCR_SLV_MASK (0x1FF << ILCR_SLV_SHIFT) +-#define ILCR_FLV_SHIFT 9 +-#define ILCR_FLV_MASK (0x1FF << ILCR_FLV_SHIFT) +-#define ILCR_HLVL_SHIFT 18 +-#define ILCR_HLVL_MASK (0x1FF << ILCR_HLVL_SHIFT) +-#define ILCR_HLVH_SHIFT 27 +-#define ILCR_HLVH_MASK (0x1F << ILCR_HLVH_SHIFT) +- +-#define IWCR_CNT_SHIFT 0 +-#define IWCR_CNT_MASK (0x1F << IWCR_CNT_SHIFT) +-#define IWCR_HS_CNT1_SHIFT 5 +-#define IWCR_HS_CNT1_MASK (0x1F << IWCR_HS_CNT1_SHIFT) +-#define IWCR_HS_CNT2_SHIFT 10 +-#define IWCR_HS_CNT2_MASK (0x1F << IWCR_HS_CNT2_SHIFT) +- + struct pxa_i2c { + spinlock_t lock; + wait_queue_head_t wait; diff --git a/ipq806x/backport-5.4/808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch b/ipq806x/backport-5.4/808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch new file mode 100644 index 0000000..f197808 --- /dev/null +++ b/ipq806x/backport-5.4/808-v5.8-i2c-pxa-add-and-use-definitions-for-IBMR-register.patch @@ -0,0 +1,66 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 06/17] i2c: pxa: add and use definitions for IBMR register +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Add definitions for the bits in the IBMR register, and use them in the +code. This improves readability. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -34,6 +34,9 @@ + #include + + /* I2C register field definitions */ ++#define IBMR_SDAS (1 << 0) ++#define IBMR_SCLS (1 << 1) ++ + #define ICR_START (1 << 0) /* start bit */ + #define ICR_STOP (1 << 1) /* stop bit */ + #define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */ +@@ -334,7 +337,7 @@ static void i2c_pxa_abort(struct pxa_i2c + return; + } + +- while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) { ++ while ((i > 0) && (readl(_IBMR(i2c)) & IBMR_SDAS) == 0) { + unsigned long icr = readl(_ICR(i2c)); + + icr &= ~ICR_START; +@@ -389,7 +392,8 @@ static int i2c_pxa_wait_master(struct px + * quick check of the i2c lines themselves to ensure they've + * gone high... + */ +- if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) { ++ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && ++ readl(_IBMR(i2c)) == (IBMR_SCLS | IBMR_SDAS)) { + if (i2c_debug > 0) + dev_dbg(&i2c->adap.dev, "%s: done\n", __func__); + return 1; +@@ -574,7 +578,7 @@ static void i2c_pxa_slave_start(struct p + timeout = 0x10000; + + while (1) { +- if ((readl(_IBMR(i2c)) & 2) == 2) ++ if ((readl(_IBMR(i2c)) & IBMR_SCLS) == IBMR_SCLS) + break; + + timeout--; +@@ -637,7 +641,7 @@ static void i2c_pxa_slave_start(struct p + timeout = 0x10000; + + while (1) { +- if ((readl(_IBMR(i2c)) & 2) == 2) ++ if ((readl(_IBMR(i2c)) & IBMR_SCLS) == IBMR_SCLS) + break; + + timeout--; diff --git a/ipq806x/backport-5.4/809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch b/ipq806x/backport-5.4/809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch new file mode 100644 index 0000000..9b1dee6 --- /dev/null +++ b/ipq806x/backport-5.4/809-v5.8-i2c-pxa-always-set-fm-and-hs-members-for-each-type.patch @@ -0,0 +1,66 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 07/17] i2c: pxa: always set fm and hs members for each type +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Always set the fm and hs members of struct pxa_reg_layout. These +members are already taking space, we don't need code as well. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -114,6 +114,8 @@ static struct pxa_reg_layout pxa_reg_lay + .icr = 0x10, + .isr = 0x18, + .isar = 0x20, ++ .fm = ICR_FM, ++ .hs = ICR_HS, + }, + [REGS_PXA3XX] = { + .ibmr = 0x00, +@@ -121,6 +123,8 @@ static struct pxa_reg_layout pxa_reg_lay + .icr = 0x08, + .isr = 0x0c, + .isar = 0x10, ++ .fm = ICR_FM, ++ .hs = ICR_HS, + }, + [REGS_CE4100] = { + .ibmr = 0x14, +@@ -128,6 +132,8 @@ static struct pxa_reg_layout pxa_reg_lay + .icr = 0x00, + .isr = 0x04, + /* no isar register */ ++ .fm = ICR_FM, ++ .hs = ICR_HS, + }, + [REGS_PXA910] = { + .ibmr = 0x00, +@@ -137,6 +143,8 @@ static struct pxa_reg_layout pxa_reg_lay + .isar = 0x20, + .ilcr = 0x28, + .iwcr = 0x30, ++ .fm = ICR_FM, ++ .hs = ICR_HS, + }, + [REGS_A3700] = { + .ibmr = 0x00, +@@ -1229,8 +1237,8 @@ static int i2c_pxa_probe(struct platform + i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; + i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr; + i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr; +- i2c->fm_mask = pxa_reg_layout[i2c_type].fm ? : ICR_FM; +- i2c->hs_mask = pxa_reg_layout[i2c_type].hs ? : ICR_HS; ++ i2c->fm_mask = pxa_reg_layout[i2c_type].fm; ++ i2c->hs_mask = pxa_reg_layout[i2c_type].hs; + + if (i2c_type != REGS_CE4100) + i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; diff --git a/ipq806x/backport-5.4/810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch b/ipq806x/backport-5.4/810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch new file mode 100644 index 0000000..dda4630 --- /dev/null +++ b/ipq806x/backport-5.4/810-v5.8-i2c-pxa-move-private-definitions-to-i2c-pxa.c.patch @@ -0,0 +1,128 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 08/17] i2c: pxa: move private definitions to i2c-pxa.c +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Move driver-private definitions out of the i2c-pxa.h platform data +header file into the driver itself. Nothing outside of the driver +makes use of these constants. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 43 ++++++++++++++++++++++++ + include/linux/platform_data/i2c-pxa.h | 48 --------------------------- + 2 files changed, 43 insertions(+), 48 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -86,6 +86,49 @@ + #define IWCR_HS_CNT2_SHIFT 10 + #define IWCR_HS_CNT2_MASK (0x1F << IWCR_HS_CNT2_SHIFT) + ++/* need a longer timeout if we're dealing with the fact we may well be ++ * looking at a multi-master environment ++ */ ++#define DEF_TIMEOUT 32 ++ ++#define BUS_ERROR (-EREMOTEIO) ++#define XFER_NAKED (-ECONNREFUSED) ++#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ ++ ++/* ICR initialize bit values ++ * ++ * 15 FM 0 (100 kHz operation) ++ * 14 UR 0 (No unit reset) ++ * 13 SADIE 0 (Disables the unit from interrupting on slave addresses ++ * matching its slave address) ++ * 12 ALDIE 0 (Disables the unit from interrupt when it loses arbitration ++ * in master mode) ++ * 11 SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) ++ * 10 BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) ++ * 9 IRFIE 1 (Enable interrupts from full buffer received) ++ * 8 ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) ++ * 7 GCD 1 (Disables i2c unit response to general call messages as a slave) ++ * 6 IUE 0 (Disable unit until we change settings) ++ * 5 SCLE 1 (Enables the i2c clock output for master mode (drives SCL) ++ * 4 MA 0 (Only send stop with the ICR stop bit) ++ * 3 TB 0 (We are not transmitting a byte initially) ++ * 2 ACKNAK 0 (Send an ACK after the unit receives a byte) ++ * 1 STOP 0 (Do not send a STOP) ++ * 0 START 0 (Do not send a START) ++ */ ++#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) ++ ++/* I2C status register init values ++ * ++ * 10 BED 1 (Clear bus error detected) ++ * 9 SAD 1 (Clear slave address detected) ++ * 7 IRF 1 (Clear IDBR Receive Full) ++ * 6 ITE 1 (Clear IDBR Transmit Empty) ++ * 5 ALD 1 (Clear Arbitration Loss Detected) ++ * 4 SSD 1 (Clear Slave Stop Detected) ++ */ ++#define I2C_ISR_INIT 0x7FF /* status register init */ ++ + struct pxa_reg_layout { + u32 ibmr; + u32 idbr; +--- a/include/linux/platform_data/i2c-pxa.h ++++ b/include/linux/platform_data/i2c-pxa.h +@@ -7,54 +7,6 @@ + #ifndef _I2C_PXA_H_ + #define _I2C_PXA_H_ + +-#if 0 +-#define DEF_TIMEOUT 3 +-#else +-/* need a longer timeout if we're dealing with the fact we may well be +- * looking at a multi-master environment +-*/ +-#define DEF_TIMEOUT 32 +-#endif +- +-#define BUS_ERROR (-EREMOTEIO) +-#define XFER_NAKED (-ECONNREFUSED) +-#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ +- +-/* ICR initialize bit values +-* +-* 15. FM 0 (100 Khz operation) +-* 14. UR 0 (No unit reset) +-* 13. SADIE 0 (Disables the unit from interrupting on slave addresses +-* matching its slave address) +-* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration +-* in master mode) +-* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) +-* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) +-* 9. IRFIE 1 (Enable interrupts from full buffer received) +-* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) +-* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) +-* 6. IUE 0 (Disable unit until we change settings) +-* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) +-* 4. MA 0 (Only send stop with the ICR stop bit) +-* 3. TB 0 (We are not transmitting a byte initially) +-* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) +-* 1. STOP 0 (Do not send a STOP) +-* 0. START 0 (Do not send a START) +-* +-*/ +-#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) +- +-/* I2C status register init values +- * +- * 10. BED 1 (Clear bus error detected) +- * 9. SAD 1 (Clear slave address detected) +- * 7. IRF 1 (Clear IDBR Receive Full) +- * 6. ITE 1 (Clear IDBR Transmit Empty) +- * 5. ALD 1 (Clear Arbitration Loss Detected) +- * 4. SSD 1 (Clear Slave Stop Detected) +- */ +-#define I2C_ISR_INIT 0x7FF /* status register init */ +- + struct i2c_slave_client; + + struct i2c_pxa_platform_data { diff --git a/ipq806x/backport-5.4/811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch b/ipq806x/backport-5.4/811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch new file mode 100644 index 0000000..0256522 --- /dev/null +++ b/ipq806x/backport-5.4/811-v5.8-i2c-pxa-move-DT-IDs-along-side-platform-IDs.patch @@ -0,0 +1,50 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 09/17] i2c: pxa: move DT IDs along side platform IDs +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Move the ID tables into one place, near the device dependent data. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -200,6 +200,15 @@ static struct pxa_reg_layout pxa_reg_lay + }, + }; + ++static const struct of_device_id i2c_pxa_dt_ids[] = { ++ { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, ++ { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, ++ { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 }, ++ { .compatible = "marvell,armada-3700-i2c", .data = (void *)REGS_A3700 }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); ++ + static const struct platform_device_id i2c_pxa_id_table[] = { + { "pxa2xx-i2c", REGS_PXA2XX }, + { "pxa3xx-pwri2c", REGS_PXA3XX }, +@@ -1178,15 +1187,6 @@ static const struct i2c_algorithm i2c_px + .functionality = i2c_pxa_functionality, + }; + +-static const struct of_device_id i2c_pxa_dt_ids[] = { +- { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, +- { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, +- { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 }, +- { .compatible = "marvell,armada-3700-i2c", .data = (void *)REGS_A3700 }, +- {} +-}; +-MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); +- + static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, + enum pxa_i2c_types *i2c_types) + { diff --git a/ipq806x/backport-5.4/813-v5.8-i2c-pxa-clean-up-decode_bits.patch b/ipq806x/backport-5.4/813-v5.8-i2c-pxa-clean-up-decode_bits.patch new file mode 100644 index 0000000..adcf969 --- /dev/null +++ b/ipq806x/backport-5.4/813-v5.8-i2c-pxa-clean-up-decode_bits.patch @@ -0,0 +1,53 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 11/17] i2c: pxa: clean up decode_bits() +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Clean up decode_bits() to use pr_cont(), and move the newline into the +function rather than at its two callsites. Avoid printing an +unnecessary space before the newline. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -287,13 +287,14 @@ struct bits { + static inline void + decode_bits(const char *prefix, const struct bits *bits, int num, u32 val) + { +- printk("%s %08x: ", prefix, val); ++ printk("%s %08x:", prefix, val); + while (num--) { + const char *str = val & bits->mask ? bits->set : bits->unset; + if (str) +- printk("%s ", str); ++ pr_cont(" %s", str); + bits++; + } ++ pr_cont("\n"); + } + + static const struct bits isr_bits[] = { +@@ -313,7 +314,6 @@ static const struct bits isr_bits[] = { + static void decode_ISR(unsigned int val) + { + decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val); +- printk("\n"); + } + + static const struct bits icr_bits[] = { +@@ -338,7 +338,6 @@ static const struct bits icr_bits[] = { + static void decode_ICR(unsigned int val) + { + decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val); +- printk("\n"); + } + #endif + diff --git a/ipq806x/backport-5.4/814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch b/ipq806x/backport-5.4/814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch new file mode 100644 index 0000000..2aadecc --- /dev/null +++ b/ipq806x/backport-5.4/814-v5.8-i2c-pxa-fix-i2c_pxa_wait_bus_not_busy-boundary-condi.patch @@ -0,0 +1,53 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Cc: linux-i2c@vger.kernel.org +Subject: [PATCH 12/17] i2c: pxa: fix i2c_pxa_wait_bus_not_busy() boundary + condition +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Fix i2c_pxa_wait_bus_not_busy()'s boundary conditions, so that a +coincidental success and timeout results in the function returning +success. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -417,19 +417,26 @@ static void i2c_pxa_abort(struct pxa_i2c + static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c) + { + int timeout = DEF_TIMEOUT; ++ u32 isr; + +- while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { +- if ((readl(_ISR(i2c)) & ISR_SAD) != 0) ++ while (1) { ++ isr = readl(_ISR(i2c)); ++ if (!(isr & (ISR_IBB | ISR_UB))) ++ return 0; ++ ++ if (isr & ISR_SAD) + timeout += 4; + ++ if (!timeout--) ++ break; ++ + msleep(2); + show_state(i2c); + } + +- if (timeout < 0) +- show_state(i2c); ++ show_state(i2c); + +- return timeout < 0 ? I2C_RETRY : 0; ++ return I2C_RETRY; + } + + static int i2c_pxa_wait_master(struct pxa_i2c *i2c) diff --git a/ipq806x/backport-5.4/815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch b/ipq806x/backport-5.4/815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch new file mode 100644 index 0000000..2debd4c --- /dev/null +++ b/ipq806x/backport-5.4/815-v5.8-i2c-pxa-consolidate-i2c_pxa_-xfer-implementations.patch @@ -0,0 +1,91 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Subject: [PATCH 1/7] i2c: pxa: consolidate i2c_pxa_*xfer() implementations +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Most of i2c_pxa_pio_xfer() and i2c_pxa_xfer() are identical; the only +differences are that i2c_pxa_pio_xfer() may reset the bus, and they +use different underlying transfer functions. The retry loop is the +same. Consolidate these two functions. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 36 ++++++++++++++++-------------------- + 1 file changed, 16 insertions(+), 20 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -1059,18 +1059,20 @@ static int i2c_pxa_do_xfer(struct pxa_i2 + return ret; + } + +-static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ++static int i2c_pxa_internal_xfer(struct pxa_i2c *i2c, ++ struct i2c_msg *msgs, int num, ++ int (*xfer)(struct pxa_i2c *, ++ struct i2c_msg *, int num)) + { +- struct pxa_i2c *i2c = adap->algo_data; + int ret, i; + +- for (i = adap->retries; i >= 0; i--) { +- ret = i2c_pxa_do_xfer(i2c, msgs, num); ++ for (i = i2c->adap.retries; i >= 0; i--) { ++ ret = xfer(i2c, msgs, num); + if (ret != I2C_RETRY) + goto out; + + if (i2c_debug) +- dev_dbg(&adap->dev, "Retrying transmission\n"); ++ dev_dbg(&i2c->adap.dev, "Retrying transmission\n"); + udelay(100); + } + i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); +@@ -1080,6 +1082,14 @@ static int i2c_pxa_xfer(struct i2c_adapt + return ret; + } + ++static int i2c_pxa_xfer(struct i2c_adapter *adap, ++ struct i2c_msg msgs[], int num) ++{ ++ struct pxa_i2c *i2c = adap->algo_data; ++ ++ return i2c_pxa_internal_xfer(i2c, msgs, num, i2c_pxa_do_xfer); ++} ++ + static u32 i2c_pxa_functionality(struct i2c_adapter *adap) + { + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | +@@ -1163,7 +1173,6 @@ static int i2c_pxa_pio_xfer(struct i2c_a + struct i2c_msg msgs[], int num) + { + struct pxa_i2c *i2c = adap->algo_data; +- int ret, i; + + /* If the I2C controller is disabled we need to reset it + (probably due to a suspend/resume destroying state). We do +@@ -1172,20 +1181,7 @@ static int i2c_pxa_pio_xfer(struct i2c_a + if (!(readl(_ICR(i2c)) & ICR_IUE)) + i2c_pxa_reset(i2c); + +- for (i = adap->retries; i >= 0; i--) { +- ret = i2c_pxa_do_pio_xfer(i2c, msgs, num); +- if (ret != I2C_RETRY) +- goto out; +- +- if (i2c_debug) +- dev_dbg(&adap->dev, "Retrying transmission\n"); +- udelay(100); +- } +- i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); +- ret = -EREMOTEIO; +- out: +- i2c_pxa_set_slave(i2c, ret); +- return ret; ++ return i2c_pxa_internal_xfer(i2c, msgs, num, i2c_pxa_do_pio_xfer); + } + + static const struct i2c_algorithm i2c_pxa_pio_algorithm = { diff --git a/ipq806x/backport-5.4/816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch b/ipq806x/backport-5.4/816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch new file mode 100644 index 0000000..63e6db8 --- /dev/null +++ b/ipq806x/backport-5.4/816-v5.8-i2c-pxa-avoid-complaints-with-non-responsive-slaves.patch @@ -0,0 +1,67 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Subject: [PATCH 2/7] i2c: pxa: avoid complaints with non-responsive slaves +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Running i2cdetect on a PXA I2C adapter is very noisy; it complains +whenever a slave fails to respond to the address cycle. Since it is +normal to probe for slaves in this way, we should not fill the kernel +log. This is especially true with SFP modules that take a while to +respond on the I2C bus, and probing via the I2C bus is the only way to +detect that they are ready. + +Fix this by changing the internal transfer return code from I2C_RETRY +to a new NO_SLAVE code (mapped to -ENXIO, as per the I2C documentation +for this condition, but we still return -EREMOTEIO to the I2C stack to +maintain long established driver behaviour.) + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -91,6 +91,7 @@ + */ + #define DEF_TIMEOUT 32 + ++#define NO_SLAVE (-ENXIO) + #define BUS_ERROR (-EREMOTEIO) + #define XFER_NAKED (-ECONNREFUSED) + #define I2C_RETRY (-2000) /* an error has occurred retry transmit */ +@@ -838,7 +839,7 @@ static void i2c_pxa_irq_txempty(struct p + */ + if (isr & ISR_ACKNAK) { + if (i2c->msg_ptr == 0 && i2c->msg_idx == 0) +- ret = I2C_RETRY; ++ ret = NO_SLAVE; + else + ret = XFER_NAKED; + } +@@ -1066,16 +1067,19 @@ static int i2c_pxa_internal_xfer(struct + { + int ret, i; + +- for (i = i2c->adap.retries; i >= 0; i--) { ++ for (i = 0; ; ) { + ret = xfer(i2c, msgs, num); +- if (ret != I2C_RETRY) ++ if (ret != I2C_RETRY && ret != NO_SLAVE) + goto out; ++ if (++i >= i2c->adap.retries) ++ break; + + if (i2c_debug) + dev_dbg(&i2c->adap.dev, "Retrying transmission\n"); + udelay(100); + } +- i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); ++ if (ret != NO_SLAVE) ++ i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); + ret = -EREMOTEIO; + out: + i2c_pxa_set_slave(i2c, ret); diff --git a/ipq806x/backport-5.4/817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch b/ipq806x/backport-5.4/817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch new file mode 100644 index 0000000..37a77b6 --- /dev/null +++ b/ipq806x/backport-5.4/817-v5.8-i2c-pxa-ensure-timeout-messages-are-unique.patch @@ -0,0 +1,45 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Subject: [PATCH 3/7] i2c: pxa: ensure timeout messages are unique +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Ensure that the various timeout messages can identify where in the code +they were produced from to aid debugging. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -1052,7 +1052,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2 + ret = i2c->msg_idx; + + if (!timeout && i2c->msg_num) { +- i2c_pxa_scream_blue_murder(i2c, "timeout"); ++ i2c_pxa_scream_blue_murder(i2c, "timeout with active message"); + ret = I2C_RETRY; + } + +@@ -1122,7 +1122,7 @@ static int i2c_pxa_pio_set_master(struct + if (timeout < 0) { + show_state(i2c); + dev_err(&i2c->adap.dev, +- "i2c_pxa: timeout waiting for bus free\n"); ++ "i2c_pxa: timeout waiting for bus free (set_master)\n"); + return I2C_RETRY; + } + +@@ -1166,7 +1166,7 @@ static int i2c_pxa_do_pio_xfer(struct px + + out: + if (timeout == 0) { +- i2c_pxa_scream_blue_murder(i2c, "timeout"); ++ i2c_pxa_scream_blue_murder(i2c, "timeout (do_pio_xfer)"); + ret = I2C_RETRY; + } + diff --git a/ipq806x/backport-5.4/818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch b/ipq806x/backport-5.4/818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch new file mode 100644 index 0000000..5438588 --- /dev/null +++ b/ipq806x/backport-5.4/818-v5.8-i2c-pxa-remove-some-unnecessary-debug.patch @@ -0,0 +1,34 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Subject: [PATCH 4/7] i2c: pxa: remove some unnecessary debug +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Remove unnecessary show_state() in the loop inside +i2c_pxa_pio_set_master(), which can be unnecessarily verbose. + +Remove the i2c_pxa_scream_blue_murder() in i2c_pxa_pio_xfer(), which +will trigger if we are probing the I2C bus and a slave does not +respond; this is a normal event, and not something to report. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -1114,10 +1114,8 @@ static int i2c_pxa_pio_set_master(struct + /* + * Wait for the bus to become free. + */ +- while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { ++ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) + udelay(1000); +- show_state(i2c); +- } + + if (timeout < 0) { + show_state(i2c); diff --git a/ipq806x/backport-5.4/820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch b/ipq806x/backport-5.4/820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch new file mode 100644 index 0000000..cde9e3f --- /dev/null +++ b/ipq806x/backport-5.4/820-v5.8-i2c-pxa-use-master-abort-for-device-probes.patch @@ -0,0 +1,35 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Subject: [PATCH 6/7] i2c: pxa: use master-abort for device probes +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Use master-abort to send the stop condition after an address cycle +rather than resetting the controller. + +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -899,14 +899,8 @@ static void i2c_pxa_irq_txempty(struct p + icr &= ~ICR_ALDIE; + icr |= ICR_START | ICR_TB; + } else { +- if (i2c->msg->len == 0) { +- /* +- * Device probes have a message length of zero +- * and need the bus to be reset before it can +- * be used again. +- */ +- i2c_pxa_reset(i2c); +- } ++ if (i2c->msg->len == 0) ++ icr |= ICR_MA; + i2c_pxa_master_complete(i2c, 0); + } + diff --git a/ipq806x/backport-5.4/821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch b/ipq806x/backport-5.4/821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch new file mode 100644 index 0000000..592b763 --- /dev/null +++ b/ipq806x/backport-5.4/821-v5.8-i2c-pxa-implement-generic-i2c-bus-recovery.patch @@ -0,0 +1,285 @@ +From: Russell King +Bcc: linux@mail.armlinux.org.uk +Subject: [PATCH 7/7] i2c: pxa: implement generic i2c bus recovery +MIME-Version: 1.0 +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset="utf-8" + +Implement generic GPIO-based I2C bus recovery for the PXA I2C driver. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King +--- + drivers/i2c/busses/i2c-pxa.c | 176 +++++++++++++++++++++++++++++++---- + 1 file changed, 159 insertions(+), 17 deletions(-) + +--- a/drivers/i2c/busses/i2c-pxa.c ++++ b/drivers/i2c/busses/i2c-pxa.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -29,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -261,6 +263,11 @@ struct pxa_i2c { + bool highmode_enter; + u32 fm_mask; + u32 hs_mask; ++ ++ struct i2c_bus_recovery_info recovery; ++ struct pinctrl *pinctrl; ++ struct pinctrl_state *pinctrl_default; ++ struct pinctrl_state *pinctrl_recovery; + }; + + #define _IBMR(i2c) ((i2c)->reg_ibmr) +@@ -560,13 +567,8 @@ static void i2c_pxa_set_slave(struct pxa + #define i2c_pxa_set_slave(i2c, err) do { } while (0) + #endif + +-static void i2c_pxa_reset(struct pxa_i2c *i2c) ++static void i2c_pxa_do_reset(struct pxa_i2c *i2c) + { +- pr_debug("Resetting I2C Controller Unit\n"); +- +- /* abort any transfer currently under way */ +- i2c_pxa_abort(i2c); +- + /* reset according to 9.8 */ + writel(ICR_UR, _ICR(i2c)); + writel(I2C_ISR_INIT, _ISR(i2c)); +@@ -585,12 +587,25 @@ static void i2c_pxa_reset(struct pxa_i2c + #endif + + i2c_pxa_set_slave(i2c, 0); ++} + ++static void i2c_pxa_enable(struct pxa_i2c *i2c) ++{ + /* enable unit */ + writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c)); + udelay(100); + } + ++static void i2c_pxa_reset(struct pxa_i2c *i2c) ++{ ++ pr_debug("Resetting I2C Controller Unit\n"); ++ ++ /* abort any transfer currently under way */ ++ i2c_pxa_abort(i2c); ++ i2c_pxa_do_reset(i2c); ++ i2c_pxa_enable(i2c); ++} ++ + + #ifdef CONFIG_I2C_PXA_SLAVE + /* +@@ -1002,6 +1017,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2 + ret = i2c_pxa_wait_bus_not_busy(i2c); + if (ret) { + dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n"); ++ i2c_recover_bus(&i2c->adap); + goto out; + } + +@@ -1047,6 +1063,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2 + + if (!timeout && i2c->msg_num) { + i2c_pxa_scream_blue_murder(i2c, "timeout with active message"); ++ i2c_recover_bus(&i2c->adap); + ret = I2C_RETRY; + } + +@@ -1228,6 +1245,129 @@ static int i2c_pxa_probe_pdata(struct pl + return 0; + } + ++static void i2c_pxa_prepare_recovery(struct i2c_adapter *adap) ++{ ++ struct pxa_i2c *i2c = adap->algo_data; ++ u32 ibmr = readl(_IBMR(i2c)); ++ ++ /* ++ * Program the GPIOs to reflect the current I2C bus state while ++ * we transition to recovery; this avoids glitching the bus. ++ */ ++ gpiod_set_value(i2c->recovery.scl_gpiod, ibmr & IBMR_SCLS); ++ gpiod_set_value(i2c->recovery.sda_gpiod, ibmr & IBMR_SDAS); ++ ++ WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery)); ++} ++ ++static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap) ++{ ++ struct pxa_i2c *i2c = adap->algo_data; ++ u32 isr; ++ ++ /* ++ * The bus should now be free. Clear up the I2C controller before ++ * handing control of the bus back to avoid the bus changing state. ++ */ ++ isr = readl(_ISR(i2c)); ++ if (isr & (ISR_UB | ISR_IBB)) { ++ dev_dbg(&i2c->adap.dev, ++ "recovery: resetting controller, ISR=0x%08x\n", isr); ++ i2c_pxa_do_reset(i2c); ++ } ++ ++ WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default)); ++ ++ dev_dbg(&i2c->adap.dev, "recovery: IBMR 0x%08x ISR 0x%08x\n", ++ readl(_IBMR(i2c)), readl(_ISR(i2c))); ++ ++ i2c_pxa_enable(i2c); ++} ++ ++static int i2c_pxa_init_recovery(struct pxa_i2c *i2c) ++{ ++ struct i2c_bus_recovery_info *bri = &i2c->recovery; ++ struct device *dev = i2c->adap.dev.parent; ++ ++ /* ++ * When slave mode is enabled, we are not the only master on the bus. ++ * Bus recovery can only be performed when we are the master, which ++ * we can't be certain of. Therefore, when slave mode is enabled, do ++ * not configure bus recovery. ++ */ ++ if (IS_ENABLED(CONFIG_I2C_PXA_SLAVE)) ++ return 0; ++ ++ i2c->pinctrl = devm_pinctrl_get(dev); ++ if (IS_ERR(i2c->pinctrl)) ++ return PTR_ERR(i2c->pinctrl); ++ ++ if (!i2c->pinctrl) ++ return 0; ++ ++ i2c->pinctrl_default = pinctrl_lookup_state(i2c->pinctrl, ++ PINCTRL_STATE_DEFAULT); ++ i2c->pinctrl_recovery = pinctrl_lookup_state(i2c->pinctrl, "recovery"); ++ ++ if (IS_ERR(i2c->pinctrl_default) || IS_ERR(i2c->pinctrl_recovery)) { ++ dev_info(dev, "missing pinmux recovery information: %ld %ld\n", ++ PTR_ERR(i2c->pinctrl_default), ++ PTR_ERR(i2c->pinctrl_recovery)); ++ return 0; ++ } ++ ++ /* ++ * Claiming GPIOs can influence the pinmux state, and may glitch the ++ * I2C bus. Do this carefully. ++ */ ++ bri->scl_gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN); ++ if (bri->scl_gpiod == ERR_PTR(-EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ if (IS_ERR(bri->scl_gpiod)) { ++ dev_info(dev, "missing scl gpio recovery information: %pe\n", ++ bri->scl_gpiod); ++ return 0; ++ } ++ ++ /* ++ * We have SCL. Pull SCL low and wait a bit so that SDA glitches ++ * have no effect. ++ */ ++ gpiod_direction_output(bri->scl_gpiod, 0); ++ udelay(10); ++ bri->sda_gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN); ++ ++ /* Wait a bit in case of a SDA glitch, and then release SCL. */ ++ udelay(10); ++ gpiod_direction_output(bri->scl_gpiod, 1); ++ ++ if (bri->sda_gpiod == ERR_PTR(-EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ ++ if (IS_ERR(bri->sda_gpiod)) { ++ dev_info(dev, "missing sda gpio recovery information: %pe\n", ++ bri->sda_gpiod); ++ return 0; ++ } ++ ++ bri->prepare_recovery = i2c_pxa_prepare_recovery; ++ bri->unprepare_recovery = i2c_pxa_unprepare_recovery; ++ bri->recover_bus = i2c_generic_scl_recovery; ++ ++ i2c->adap.bus_recovery_info = bri; ++ ++ /* ++ * Claiming GPIOs can change the pinmux state, which confuses the ++ * pinctrl since pinctrl's idea of the current setting is unaffected ++ * by the pinmux change caused by claiming the GPIO. Work around that ++ * by switching pinctrl to the GPIO state here. We do it this way to ++ * avoid glitching the I2C bus. ++ */ ++ pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery); ++ ++ return pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default); ++} ++ + static int i2c_pxa_probe(struct platform_device *dev) + { + struct i2c_pxa_platform_data *plat = dev_get_platdata(&dev->dev); +@@ -1240,6 +1380,16 @@ static int i2c_pxa_probe(struct platform + if (!i2c) + return -ENOMEM; + ++ /* Default adapter num to device id; i2c_pxa_probe_dt can override. */ ++ i2c->adap.nr = dev->id; ++ i2c->adap.owner = THIS_MODULE; ++ i2c->adap.retries = 5; ++ i2c->adap.algo_data = i2c; ++ i2c->adap.dev.parent = &dev->dev; ++#ifdef CONFIG_OF ++ i2c->adap.dev.of_node = dev->dev.of_node; ++#endif ++ + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + i2c->reg_base = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(i2c->reg_base)) +@@ -1251,8 +1401,9 @@ static int i2c_pxa_probe(struct platform + return irq; + } + +- /* Default adapter num to device id; i2c_pxa_probe_dt can override. */ +- i2c->adap.nr = dev->id; ++ ret = i2c_pxa_init_recovery(i2c); ++ if (ret) ++ return ret; + + ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type); + if (ret > 0) +@@ -1260,9 +1411,6 @@ static int i2c_pxa_probe(struct platform + if (ret < 0) + return ret; + +- i2c->adap.owner = THIS_MODULE; +- i2c->adap.retries = 5; +- + spin_lock_init(&i2c->lock); + init_waitqueue_head(&i2c->wait); + +@@ -1332,12 +1480,6 @@ static int i2c_pxa_probe(struct platform + + i2c_pxa_reset(i2c); + +- i2c->adap.algo_data = i2c; +- i2c->adap.dev.parent = &dev->dev; +-#ifdef CONFIG_OF +- i2c->adap.dev.of_node = dev->dev.of_node; +-#endif +- + ret = i2c_add_numbered_adapter(&i2c->adap); + if (ret < 0) + goto ereqirq; diff --git a/ipq806x/backport-5.4/825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch b/ipq806x/backport-5.4/825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch new file mode 100644 index 0000000..71e26d5 --- /dev/null +++ b/ipq806x/backport-5.4/825-v5.8-spi-rb4xx-null-pointer-bug-fix.patch @@ -0,0 +1,48 @@ +From: Christopher Hill +To: Mark Brown +Cc: Christopher Hill , linux-spi@vger.kernel.org, + linux-kernel@vger.kernel.org +Subject: [PATCH 1/3] spi: rb4xx: null pointer bug fix +Date: Thu, 21 May 2020 14:36:29 -0400 +Message-Id: <20200521183631.37806-1-ch6574@gmail.com> +X-Mailer: git-send-email 2.25.1 +MIME-Version: 1.0 +Sender: linux-spi-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-spi@vger.kernel.org + +This patch fixes a null pointer bug in the spi driver spi-rb4xx.c by +moving the private data initialization to earlier in probe + +Signed-off-by: Christopher Hill +--- + drivers/spi/spi-rb4xx.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/spi/spi-rb4xx.c ++++ b/drivers/spi/spi-rb4xx.c +@@ -158,6 +158,11 @@ static int rb4xx_spi_probe(struct platfo + master->transfer_one = rb4xx_transfer_one; + master->set_cs = rb4xx_set_cs; + ++ rbspi = spi_master_get_devdata(master); ++ rbspi->base = spi_base; ++ rbspi->clk = ahb_clk; ++ platform_set_drvdata(pdev, rbspi); ++ + err = devm_spi_register_master(&pdev->dev, master); + if (err) { + dev_err(&pdev->dev, "failed to register SPI master\n"); +@@ -168,11 +173,6 @@ static int rb4xx_spi_probe(struct platfo + if (err) + return err; + +- rbspi = spi_master_get_devdata(master); +- rbspi->base = spi_base; +- rbspi->clk = ahb_clk; +- platform_set_drvdata(pdev, rbspi); +- + /* Enable SPI */ + rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); + diff --git a/ipq806x/backport-5.4/826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch b/ipq806x/backport-5.4/826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch new file mode 100644 index 0000000..0ce4f2b --- /dev/null +++ b/ipq806x/backport-5.4/826-v5.8-spi-rb4xx-update-driver-to-be-device-tree-aware.patch @@ -0,0 +1,60 @@ +From: Christopher Hill +To: Mark Brown +Cc: Christopher Hill , linux-spi@vger.kernel.org, + linux-kernel@vger.kernel.org +Subject: [PATCH 2/3] spi: rb4xx: update driver to be device tree aware +Date: Thu, 21 May 2020 14:36:30 -0400 +Message-Id: <20200521183631.37806-2-ch6574@gmail.com> +X-Mailer: git-send-email 2.25.1 +In-Reply-To: <20200521183631.37806-1-ch6574@gmail.com> +References: <20200521183631.37806-1-ch6574@gmail.com> +MIME-Version: 1.0 +Sender: linux-spi-owner@vger.kernel.org +Precedence: bulk +List-ID: +X-Mailing-List: linux-spi@vger.kernel.org + +This patch updates the spi driver spi-rb4xx.c to be device tree aware + +Signed-off-by: Christopher Hill +--- + drivers/spi/spi-rb4xx.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/spi/spi-rb4xx.c ++++ b/drivers/spi/spi-rb4xx.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include + +@@ -150,6 +151,7 @@ static int rb4xx_spi_probe(struct platfo + if (IS_ERR(ahb_clk)) + return PTR_ERR(ahb_clk); + ++ master->dev.of_node = pdev->dev.of_node; + master->bus_num = 0; + master->num_chipselect = 3; + master->mode_bits = SPI_TX_DUAL; +@@ -188,11 +190,18 @@ static int rb4xx_spi_remove(struct platf + return 0; + } + ++static const struct of_device_id rb4xx_spi_dt_match[] = { ++ { .compatible = "mikrotik,rb4xx-spi" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match); ++ + static struct platform_driver rb4xx_spi_drv = { + .probe = rb4xx_spi_probe, + .remove = rb4xx_spi_remove, + .driver = { + .name = "rb4xx-spi", ++ .of_match_table = of_match_ptr(rb4xx_spi_dt_match), + }, + }; + diff --git a/ipq806x/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch b/ipq806x/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch new file mode 100644 index 0000000..1993870 --- /dev/null +++ b/ipq806x/backport-5.4/831-v5.13-0001-firmware-bcm47xx_nvram-rename-finding-function-and-i.patch @@ -0,0 +1,80 @@ +From fb009cbdd0693bd633f11e99526617b3d392cfad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:16 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: rename finding function and its + variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. Use "bcm47xx_" function name prefix for consistency +2. It takes flash start as argument so s/iobase/flash_start/ +3. "off" was used for finding flash end so just call it "flash_size" + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 24 ++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -48,11 +48,13 @@ static u32 find_nvram_size(void __iomem + return 0; + } + +-/* Probe for NVRAM header */ +-static int nvram_find_and_copy(void __iomem *iobase, u32 lim) ++/** ++ * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it ++ */ ++static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size) + { + struct nvram_header __iomem *header; +- u32 off; ++ size_t flash_size; + u32 size; + + if (nvram_len) { +@@ -61,25 +63,25 @@ static int nvram_find_and_copy(void __io + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ +- off = FLASH_MIN; +- while (off <= lim) { ++ flash_size = FLASH_MIN; ++ while (flash_size <= res_size) { + /* Windowed flash access */ +- size = find_nvram_size(iobase + off); ++ size = find_nvram_size(flash_start + flash_size); + if (size) { +- header = (struct nvram_header *)(iobase + off - size); ++ header = (struct nvram_header *)(flash_start + flash_size - size); + goto found; + } +- off <<= 1; ++ flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ +- header = (struct nvram_header *)(iobase + 4096); ++ header = (struct nvram_header *)(flash_start + 4096); + if (header->magic == NVRAM_MAGIC) { + size = NVRAM_SPACE; + goto found; + } + +- header = (struct nvram_header *)(iobase + 1024); ++ header = (struct nvram_header *)(flash_start + 1024); + if (header->magic == NVRAM_MAGIC) { + size = NVRAM_SPACE; + goto found; +@@ -124,7 +126,7 @@ int bcm47xx_nvram_init_from_mem(u32 base + if (!iobase) + return -ENOMEM; + +- err = nvram_find_and_copy(iobase, lim); ++ err = bcm47xx_nvram_find_and_copy(iobase, lim); + + iounmap(iobase); + diff --git a/ipq806x/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch b/ipq806x/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch new file mode 100644 index 0000000..6ab0728 --- /dev/null +++ b/ipq806x/backport-5.4/831-v5.13-0002-firmware-bcm47xx_nvram-add-helper-checking-for-NVRAM.patch @@ -0,0 +1,90 @@ +From 0a24b51a3264a3f942a75025ea5ff6133c8989b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:17 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: add helper checking for NVRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This avoids duplicating code doing casting and checking for NVRAM magic. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 30 ++++++++++++++--------- + 1 file changed, 18 insertions(+), 12 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -34,14 +34,20 @@ static char nvram_buf[NVRAM_SPACE]; + static size_t nvram_len; + static const u32 nvram_sizes[] = {0x6000, 0x8000, 0xF000, 0x10000}; + ++/** ++ * bcm47xx_nvram_is_valid - check for a valid NVRAM at specified memory ++ */ ++static bool bcm47xx_nvram_is_valid(void __iomem *nvram) ++{ ++ return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC; ++} ++ + static u32 find_nvram_size(void __iomem *end) + { +- struct nvram_header __iomem *header; + int i; + + for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { +- header = (struct nvram_header *)(end - nvram_sizes[i]); +- if (header->magic == NVRAM_MAGIC) ++ if (bcm47xx_nvram_is_valid(end - nvram_sizes[i])) + return nvram_sizes[i]; + } + +@@ -55,6 +61,7 @@ static int bcm47xx_nvram_find_and_copy(v + { + struct nvram_header __iomem *header; + size_t flash_size; ++ size_t offset; + u32 size; + + if (nvram_len) { +@@ -68,31 +75,30 @@ static int bcm47xx_nvram_find_and_copy(v + /* Windowed flash access */ + size = find_nvram_size(flash_start + flash_size); + if (size) { +- header = (struct nvram_header *)(flash_start + flash_size - size); ++ offset = flash_size - size; + goto found; + } + flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ +- header = (struct nvram_header *)(flash_start + 4096); +- if (header->magic == NVRAM_MAGIC) { +- size = NVRAM_SPACE; ++ ++ offset = 4096; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) + goto found; +- } + +- header = (struct nvram_header *)(flash_start + 1024); +- if (header->magic == NVRAM_MAGIC) { +- size = NVRAM_SPACE; ++ offset = 1024; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) + goto found; +- } + + pr_err("no nvram found\n"); + return -ENXIO; + + found: ++ header = (struct nvram_header *)(flash_start + offset); + __ioread32_copy(nvram_buf, header, sizeof(*header) / 4); + nvram_len = ((struct nvram_header *)(nvram_buf))->len; ++ size = res_size - offset; + if (nvram_len > size) { + pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); + nvram_len = size; diff --git a/ipq806x/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch b/ipq806x/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch new file mode 100644 index 0000000..a1351f1 --- /dev/null +++ b/ipq806x/backport-5.4/831-v5.13-0003-firmware-bcm47xx_nvram-extract-code-copying-NVRAM.patch @@ -0,0 +1,80 @@ +From 298923cf999cecd2ef06df126f85a3d68da8c4d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:18 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: extract code copying NVRAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This simplifies function finding NVRAM. It doesn't directly deal with +NVRAM structure anymore and is a bit smaller. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 43 +++++++++++++---------- + 1 file changed, 25 insertions(+), 18 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -55,11 +55,34 @@ static u32 find_nvram_size(void __iomem + } + + /** ++ * bcm47xx_nvram_copy - copy NVRAM to internal buffer ++ */ ++static void bcm47xx_nvram_copy(void __iomem *nvram_start, size_t res_size) ++{ ++ struct nvram_header __iomem *header = nvram_start; ++ size_t copy_size; ++ ++ copy_size = header->len; ++ if (copy_size > res_size) { ++ pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); ++ copy_size = res_size; ++ } ++ if (copy_size >= NVRAM_SPACE) { ++ pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", ++ copy_size, NVRAM_SPACE - 1); ++ copy_size = NVRAM_SPACE - 1; ++ } ++ ++ __ioread32_copy(nvram_buf, nvram_start, DIV_ROUND_UP(copy_size, 4)); ++ nvram_buf[NVRAM_SPACE - 1] = '\0'; ++ nvram_len = copy_size; ++} ++ ++/** + * bcm47xx_nvram_find_and_copy - find NVRAM on flash mapping & copy it + */ + static int bcm47xx_nvram_find_and_copy(void __iomem *flash_start, size_t res_size) + { +- struct nvram_header __iomem *header; + size_t flash_size; + size_t offset; + u32 size; +@@ -95,23 +118,7 @@ static int bcm47xx_nvram_find_and_copy(v + return -ENXIO; + + found: +- header = (struct nvram_header *)(flash_start + offset); +- __ioread32_copy(nvram_buf, header, sizeof(*header) / 4); +- nvram_len = ((struct nvram_header *)(nvram_buf))->len; +- size = res_size - offset; +- if (nvram_len > size) { +- pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n"); +- nvram_len = size; +- } +- if (nvram_len >= NVRAM_SPACE) { +- pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n", +- nvram_len, NVRAM_SPACE - 1); +- nvram_len = NVRAM_SPACE - 1; +- } +- /* proceed reading data after header */ +- __ioread32_copy(nvram_buf + sizeof(*header), header + 1, +- DIV_ROUND_UP(nvram_len, 4)); +- nvram_buf[NVRAM_SPACE - 1] = '\0'; ++ bcm47xx_nvram_copy(flash_start + offset, res_size - offset); + + return 0; + } diff --git a/ipq806x/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch b/ipq806x/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch new file mode 100644 index 0000000..059a132 --- /dev/null +++ b/ipq806x/backport-5.4/831-v5.13-0004-firmware-bcm47xx_nvram-look-for-NVRAM-with-for-inste.patch @@ -0,0 +1,37 @@ +From 98b68324f67236e8c9152976535dc1f27fb67ba8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:19 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: look for NVRAM with for instead of + while +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This loop requires variable initialization, stop condition and post +iteration increment. It's pretty much a for loop definition. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -93,15 +93,13 @@ static int bcm47xx_nvram_find_and_copy(v + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ +- flash_size = FLASH_MIN; +- while (flash_size <= res_size) { ++ for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) { + /* Windowed flash access */ + size = find_nvram_size(flash_start + flash_size); + if (size) { + offset = flash_size - size; + goto found; + } +- flash_size <<= 1; + } + + /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */ diff --git a/ipq806x/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch b/ipq806x/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch new file mode 100644 index 0000000..21d2500 --- /dev/null +++ b/ipq806x/backport-5.4/831-v5.13-0005-firmware-bcm47xx_nvram-inline-code-checking-NVRAM-si.patch @@ -0,0 +1,70 @@ +From f52da4ccfec9192e17f5c16260dfdd6d3ea76f65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 8 Mar 2021 10:03:20 +0100 +Subject: [PATCH] firmware: bcm47xx_nvram: inline code checking NVRAM size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Separated function was not improving code quality much (or at all). +Moreover it expected possible flash end address as argument and it was +returning NVRAM size. + +The new code always operates on offsets which means less logic and less +calculations. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Thomas Bogendoerfer +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 25 +++++++---------------- + 1 file changed, 7 insertions(+), 18 deletions(-) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -42,18 +42,6 @@ static bool bcm47xx_nvram_is_valid(void + return ((struct nvram_header *)nvram)->magic == NVRAM_MAGIC; + } + +-static u32 find_nvram_size(void __iomem *end) +-{ +- int i; +- +- for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { +- if (bcm47xx_nvram_is_valid(end - nvram_sizes[i])) +- return nvram_sizes[i]; +- } +- +- return 0; +-} +- + /** + * bcm47xx_nvram_copy - copy NVRAM to internal buffer + */ +@@ -85,7 +73,7 @@ static int bcm47xx_nvram_find_and_copy(v + { + size_t flash_size; + size_t offset; +- u32 size; ++ int i; + + if (nvram_len) { + pr_warn("nvram already initialized\n"); +@@ -93,12 +81,13 @@ static int bcm47xx_nvram_find_and_copy(v + } + + /* TODO: when nvram is on nand flash check for bad blocks first. */ ++ ++ /* Try every possible flash size and check for NVRAM at its end */ + for (flash_size = FLASH_MIN; flash_size <= res_size; flash_size <<= 1) { +- /* Windowed flash access */ +- size = find_nvram_size(flash_start + flash_size); +- if (size) { +- offset = flash_size - size; +- goto found; ++ for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) { ++ offset = flash_size - nvram_sizes[i]; ++ if (bcm47xx_nvram_is_valid(flash_start + offset)) ++ goto found; + } + } + diff --git a/ipq806x/backport-5.4/999-bpf-off-by-one-backport.patch b/ipq806x/backport-5.4/999-bpf-off-by-one-backport.patch new file mode 100644 index 0000000..271eac6 --- /dev/null +++ b/ipq806x/backport-5.4/999-bpf-off-by-one-backport.patch @@ -0,0 +1,13 @@ +Index: linux-5.4.158/kernel/bpf/verifier.c +=================================================================== +--- linux-5.4.158.orig/kernel/bpf/verifier.c ++++ linux-5.4.158/kernel/bpf/verifier.c +@@ -5372,7 +5372,7 @@ static void find_good_pkt_pointers(struc + + new_range = dst_reg->off; + if (range_right_open) +- new_range--; ++ new_range++; + + /* Examples for register markings: + * diff --git a/ipq806x/backport-5.4/999-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch b/ipq806x/backport-5.4/999-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch new file mode 100644 index 0000000..20f7156 --- /dev/null +++ b/ipq806x/backport-5.4/999-net-bridge-clear-bridge-s-private-skb-space-on-xmit.patch @@ -0,0 +1,36 @@ +From fd65e5a95d08389444e8591a20538b3edece0e15 Mon Sep 17 00:00:00 2001 +From: Nikolay Aleksandrov +Date: Fri, 31 Jul 2020 19:26:16 +0300 +Subject: [PATCH] net: bridge: clear bridge's private skb space on xmit + +We need to clear all of the bridge private skb variables as they can be +stale due to the packet being recirculated through the stack and then +transmitted through the bridge device. Similar memset is already done on +bridge's input. We've seen cases where proxyarp_replied was 1 on routed +multicast packets transmitted through the bridge to ports with neigh +suppress which were getting dropped. Same thing can in theory happen with +the port isolation bit as well. + +Fixes: 821f1b21cabb ("bridge: add new BR_NEIGH_SUPPRESS port flag to suppress arp and nd flood") +Signed-off-by: Nikolay Aleksandrov +Signed-off-by: David S. Miller +--- + net/bridge/br_device.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c +index 8c7b78f8bc23..9a2fb4aa1a10 100644 +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -36,6 +36,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) + const unsigned char *dest; + u16 vid = 0; + ++ memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); ++ + rcu_read_lock(); + nf_ops = rcu_dereference(nf_br_ops); + if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) { +-- +2.25.1 + diff --git a/ipq806x/base-files/etc/board.d/01_leds b/ipq806x/base-files/etc/board.d/01_leds new file mode 100755 index 0000000..05c63c8 --- /dev/null +++ b/ipq806x/base-files/etc/board.d/01_leds @@ -0,0 +1,71 @@ +# +# Copyright (C) 2015 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh + +board_config_update + +board=$(board_name) + +case "$board" in +buffalo,wxr-2533dhp) + ucidef_set_led_wlan "wlan" "WLAN" "white:wireless" "phy0tpt" + ucidef_set_led_switch "wan" "WAN" "white:internet" "switch0" "0x20" + ;; +compex,wpq864) + ucidef_set_led_usbport "usb" "USB" "green:usb" "usb1-port1" "usb2-port1" + ucidef_set_led_usbport "pcie-usb" "PCIe USB" "green:usb-pcie" "usb3-port1" + ;; +edgecore,ssw2ac2600 |\ +edgecore,ecw5410) + ucidef_set_led_wlan "wlan2g" "WLAN2G" "green:wlan2g" "phy1tpt" + ucidef_set_led_wlan "wlan5g" "WLAN5G" "green:wlan5g" "phy0tpt" + ;; +nec,wg2600hp) + ucidef_set_led_wlan "wlan2g" "WLAN2G" "green:wlan2g" "phy1tpt" + ucidef_set_led_wlan "wlan5g" "WLAN5G" "green:wlan5g" "phy0tpt" + ucidef_set_led_switch "wan" "WAN" "green:active" "switch0" "0x2" + ;; +nec,wg2600hp3) + ucidef_set_led_switch "wan" "WAN" "green:active" "switch0" "0x2" + ;; +netgear,d7800 |\ +netgear,r7500 |\ +netgear,r7500v2 |\ +netgear,r7800) + ucidef_set_led_usbport "usb1" "USB 1" "white:usb1" "usb1-port1" "usb2-port1" + ucidef_set_led_usbport "usb2" "USB 2" "white:usb2" "usb3-port1" "usb4-port1" + ucidef_set_led_switch "wan" "WAN" "white:wan" "switch0" "0x20" + ucidef_set_led_ide "esata" "eSATA" "white:esata" + ;; +tplink,ad7200) + ucidef_set_led_usbport "usb1" "USB 1" "blue:usb1" "usb1-port1" "usb2-port1" + ucidef_set_led_usbport "usb2" "USB 2" "blue:usb3" "usb3-port1" "usb4-port1" + ucidef_set_led_switch "wan" "wan" "blue:wan" "switch0" "0x02" + ucidef_set_led_switch "lan" "lan" "blue:lan" "switch0" "0x3c" + ucidef_set_led_wlan "wlan2g" "wlan2g" "blue:wlan2g" "phy2tpt" + ucidef_set_led_wlan "wlan5g" "wlan5g" "blue:wlan5g" "phy1tpt" + ucidef_set_led_netdev "wlan60g" "wlan60g" "blue:wlan60g" "wlan0" + ;; +tplink,c2600) + ucidef_set_led_usbport "usb1" "USB 1" "white:usb_2" "usb1-port1" "usb2-port1" + ucidef_set_led_usbport "usb2" "USB 2" "white:usb_4" "usb3-port1" "usb4-port1" + ucidef_set_led_switch "wan" "wan" "white:wan" "switch0" "0x20" + ucidef_set_led_switch "lan" "lan" "white:lan" "switch0" "0x1e" + ;; +tplink,vr2600v) + ucidef_set_led_usbport "usb" "USB" "white:usb" "usb1-port1" "usb2-port1" "usb3-port1" "usb4-port1" + ucidef_set_led_switch "lan" "lan" "white:lan" "switch0" "0x1e" + ucidef_set_led_wlan "wlan2g" "WLAN2G" "white:wlan2g" "phy0tpt" + ucidef_set_led_wlan "wlan5g" "WLAN5G" "white:wlan5g" "phy1tpt" + ucidef_set_led_switch "wan" "wan" "white:wan" "switch0" "0x20" + ;; +zyxel,nbg6817) + ucidef_set_led_netdev "wan" "WAN" "white:internet" "eth1" + ;; +esac + +board_config_flush + +exit 0 diff --git a/ipq806x/base-files/etc/board.d/02_network b/ipq806x/base-files/etc/board.d/02_network new file mode 100755 index 0000000..078de50 --- /dev/null +++ b/ipq806x/base-files/etc/board.d/02_network @@ -0,0 +1,101 @@ +# +# Copyright (c) 2015 The Linux Foundation. All rights reserved. +# Copyright (c) 2011-2015 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh +. /lib/functions/system.sh + +board_config_update + +board=$(board_name) + +case "$board" in +askey,rt4230w-rev6 |\ +asrock,g10 |\ +nec,wg2600hp) + ucidef_add_switch "switch0" \ + "2:lan" "3:lan" "4:lan" "5:lan" "6@eth1" "1:wan" "0@eth0" + ;; +buffalo,wxr-2533dhp |\ +compex,wpq864 |\ +netgear,d7800 |\ +netgear,r7500 |\ +netgear,r7500v2 |\ +qcom,ipq8064-ap148 |\ +tplink,vr2600v) + ucidef_add_switch "switch0" \ + "1:lan" "2:lan" "3:lan" "4:lan" "6@eth1" "5:wan" "0@eth0" + ;; +edgecore,ssw2ac2600 |\ +edgecore,ecw5410) + ucidef_set_interfaces_lan_wan "eth1" "eth0" + if [ -b "$(find_mtd_part 0:art)" ]; then + ucidef_set_interface_macaddr "lan" "$(mtd_get_mac_binary "0:art" 0x6)" + ucidef_set_interface_macaddr "wan" "$(mtd_get_mac_binary "0:art" 0x0)" + ucidef_set_network_device_mac "eth1" "$(mtd_get_mac_binary "0:art" 0x6)" + ucidef_set_network_device_mac "eth0" "$(mtd_get_mac_binary "0:art" 0x0)" + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + ucidef_set_interface_macaddr "lan" "$(mtd_get_mac_binary "0:ART" 0x6)" + ucidef_set_interface_macaddr "wan" "$(mtd_get_mac_binary "0:ART" 0x0)" + fi + ;; +linksys,ea7500-v1) + hw_mac_addr=$(mtd_get_mac_ascii devinfo hw_mac_addr) + ucidef_add_switch "switch0" \ + "2:lan:1" "3:lan:2" "4:lan:3" "5:lan:4" "6@eth1" "1:wan" "0@eth0" + ucidef_set_interface_macaddr "lan" "$hw_mac_addr" + ucidef_set_interface_macaddr "wan" "$hw_mac_addr" + ;; +linksys,ea8500) + hw_mac_addr=$(mtd_get_mac_ascii devinfo hw_mac_addr) + ucidef_add_switch "switch0" \ + "1:lan" "2:lan" "3:lan" "4:lan" "6@eth1" "5:wan" "0@eth0" + ucidef_set_interface_macaddr "lan" "$hw_mac_addr" + ucidef_set_interface_macaddr "wan" "$hw_mac_addr" + ;; +nec,wg2600hp3) + ucidef_add_switch "switch0" \ + "2:lan" "3:lan" "4:lan" "5:lan" "0@eth1" "1:wan" "6@eth0" + ;; +netgear,r7800 |\ +tplink,c2600) + ucidef_add_switch "switch0" \ + "1:lan:4" "2:lan:3" "3:lan:2" "4:lan:1" "6@eth1" "5:wan" "0@eth0" + ;; +qcom,ipq8064-ap161) + ucidef_set_interface_lan "eth1 eth2" + ucidef_add_switch "switch0" \ + "0:lan" "1:lan" "2:lan" "3u@eth1" "6:wan" "4u@eth0" + ;; +qcom,ipq8064-db149) + ucidef_set_interface_lan "eth1 eth2 eth3" + ucidef_add_switch "switch0" \ + "1:lan" "2:lan" "3:lan" "4:lan" "6u@eth1" "5:wan" "0u@eth0" + ;; +tplink,ad7200) + ucidef_add_switch "switch0" \ + "2:lan:1" "3:lan:2" "4:lan:3" "5:lan:4" "6@eth1" "1:wan" "0@eth0" + ;; +ubnt,unifi-ac-hd) + ucidef_set_interface_lan "eth0 eth1" + ;; +zyxel,nbg6817) + hw_mac_addr=$(mtd_get_mac_ascii 0:appsblenv ethaddr) + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + [ -n "$hw_mac_addr" ] || \ + hw_mac_addr=$(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + ucidef_add_switch "switch0" \ + "1:lan" "2:lan" "3:lan" "4:lan" "6@eth1" "5:wan" "0@eth0" + ucidef_set_interface_macaddr "lan" "$(macaddr_add $hw_mac_addr 2)" + ucidef_set_interface_macaddr "wan" "$(macaddr_add $hw_mac_addr 3)" + ;; +*) + echo "Unsupported hardware. Network interfaces not intialized" + ;; +esac + +board_config_flush + +exit 0 diff --git a/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata new file mode 100644 index 0000000..ae8feba --- /dev/null +++ b/ipq806x/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -0,0 +1,139 @@ +#!/bin/sh + +[ -e /lib/firmware/$FIRMWARE ] && exit 0 + +. /lib/functions/caldata.sh + +board=$(board_name) + +case "$FIRMWARE" in +"ath10k/pre-cal-pci-0000:01:00.0.bin") + case $board in + askey,rt4230w-rev6 |\ + asrock,g10) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x1000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x1000 0x2f20 + fi + ;; + buffalo,wxr-2533dhp) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary ART 0x1e) + ;; + linksys,ea7500-v1 |\ + linksys,ea8500) + caldata_extract "art" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii devinfo hw_mac_addr) 1) + ;; + nec,wg2600hp |\ + nec,wg2600hp3) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary PRODUCTDATA 0x12) + ;; + netgear,d7800 |\ + netgear,r7500v2 |\ + netgear,r7800) + caldata_extract "art" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary art 0x6) 1) + ;; + tplink,ad7200 |\ + tplink,c2600) + caldata_extract "radio" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary default-mac 0x8) -1) + ;; + tplink,vr2600v) + caldata_extract "ART" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary default-mac 0x0) -1) + ;; + zyxel,nbg6817) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:appsblenv ethaddr) 1) + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x1000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) 1) + fi + ;; + esac + ;; +"ath10k/pre-cal-pci-0001:01:00.0.bin") + case $board in + askey,rt4230w-rev6 |\ + asrock,g10) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x5000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x5000 0x2f20 + fi + ;; + buffalo,wxr-2533dhp) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary ART 0x18) + ;; + edgecore,ssw2ac2600 |\ + edgecore,ecw5410) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x1000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x1000 0x2f20 + fi + ;; + linksys,ea7500-v1 |\ + linksys,ea8500) + caldata_extract "art" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_ascii devinfo hw_mac_addr) 2) + ;; + nec,wg2600hp |\ + nec,wg2600hp3) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary PRODUCTDATA 0xc) + ;; + netgear,d7800 |\ + netgear,r7500v2 |\ + netgear,r7800) + caldata_extract "art" 0x5000 0x2f20 + ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary art 0x6) 2) + ;; + tplink,ad7200 |\ + tplink,c2600) + caldata_extract "radio" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary default-mac 0x8) + ;; + tplink,vr2600v) + caldata_extract "ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_binary default-mac 0x0) + ;; + zyxel,nbg6817) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii 0:appsblenv ethaddr) + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x5000 0x2f20 + ath10k_patch_mac $(mtd_get_mac_ascii 0:APPSBLENV ethaddr) + fi + ;; + esac + ;; +"ath10k/pre-cal-pci-0002:01:00.0.bin") + case $board in + edgecore,ssw2ac2600 |\ + edgecore,ecw5410) + if [ -b "$(find_mtd_part 0:art)" ]; then + caldata_extract "0:art" 0x5000 0x2f20 + else + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + caldata_extract "0:ART" 0x5000 0x2f20 + fi + ;; + esac + ;; +*) + exit 1 + ;; +esac diff --git a/ipq806x/base-files/etc/hotplug.d/firmware/40-ct-fw-cfg b/ipq806x/base-files/etc/hotplug.d/firmware/40-ct-fw-cfg new file mode 100644 index 0000000..c33bbea --- /dev/null +++ b/ipq806x/base-files/etc/hotplug.d/firmware/40-ct-fw-cfg @@ -0,0 +1,32 @@ +#!/bin/sh + +[ -e /lib/firmware/$FIRMWARE ] && exit 0 + + +fwcfg_symlink() { + local chip=$1 + local path=$2 + + ln -s /lib/firmware/ath10k/fwcfg-${chip}.txt /lib/firmware/${FIRMWARE} +} + +case "$FIRMWARE" in +ath10k/fwcfg-pci-0001:01:00.0.txt) + case "$(board_name)" in + edgecore,ssw2ac2600|\ + edgecore,ecw5410) + fwcfg_symlink qca9984 + ;; + esac + ;; +ath10k/fwcfg-pci-0002:01:00.0.txt) + case "$(board_name)" in + edgecore,ssw2ac2600|\ + edgecore,ecw5410) + fwcfg_symlink qca9984 + ;; + esac + ;; +esac + +exit 0 diff --git a/ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac b/ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac new file mode 100644 index 0000000..5af3a5b --- /dev/null +++ b/ipq806x/base-files/etc/hotplug.d/ieee80211/10_fix_wifi_mac @@ -0,0 +1,39 @@ +#!/bin/ash + +[ "$ACTION" == "add" ] || exit 0 + +PHYNBR=${DEVPATH##*/phy} + +[ -n $PHYNBR ] || exit 0 + +. /lib/functions.sh +. /lib/functions/system.sh + +board=$(board_name) + +case "$board" in + ubnt,unifi-ac-hd) + macaddr_add $(mtd_get_mac_binary EEPROM 0x6) $(($PHYNBR + 1)) > /sys${DEVPATH}/macaddress + ;; +esac + +OPATH=${DEVPATH##/devices/platform/} +OPATH=${OPATH%%/ieee*} + +# 10 radios is enough for anyone! +for i in $(seq 0 9); + do + BUS=$(uci get wireless.@wifi-device[$i].path) + if [ "$BUS " == "$OPATH " ] + then + PHYNAME=${DEVPATH##*ieee80211/} + NPHYNAME=$(uci get wireless.@wifi-device[$i].phyname) + if [ "$NPHYNAME " != " " ] + then + if [ "$PHYNAME " != "$NPHYNAME " ] + then + iw $PHYNAME set name $NPHYNAME + fi + fi + fi +done diff --git a/ipq806x/base-files/etc/init.d/bootcount b/ipq806x/base-files/etc/init.d/bootcount new file mode 100755 index 0000000..f555e1a --- /dev/null +++ b/ipq806x/base-files/etc/init.d/bootcount @@ -0,0 +1,21 @@ +#!/bin/sh /etc/rc.common + +START=99 + +. "$IPKG_INSTROOT/lib/upgrade/asrock.sh" + +boot() { + case $(board_name) in + asrock,g10) + asrock_bootconfig_mangle "bootcheck" && reboot + ;; + edgecore,ssw2ac2600|\ + edgecore,ecw5410) + fw_setenv bootcount 0 + ;; + linksys,ea7500-v1 |\ + linksys,ea8500) + mtd resetbc s_env || true + ;; + esac +} diff --git a/ipq806x/base-files/etc/init.d/cpufreq b/ipq806x/base-files/etc/init.d/cpufreq new file mode 100755 index 0000000..1927890 --- /dev/null +++ b/ipq806x/base-files/etc/init.d/cpufreq @@ -0,0 +1,17 @@ +#!/bin/sh /etc/rc.common + +START=15 + +boot() { + local governor + + governor=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor) + + if [ "$governor" = "ondemand" ]; then + # Effective only with ondemand + echo 600000 > /sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq + echo 600000 > /sys/devices/system/cpu/cpufreq/policy1/scaling_min_freq + echo 10 > /sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor + echo 50 > /sys/devices/system/cpu/cpufreq/ondemand/up_threshold + fi +} diff --git a/ipq806x/base-files/etc/inittab b/ipq806x/base-files/etc/inittab new file mode 100644 index 0000000..809bba5 --- /dev/null +++ b/ipq806x/base-files/etc/inittab @@ -0,0 +1,4 @@ +# Copyright (c) 2013 The Linux Foundation. All rights reserved. +::sysinit:/etc/init.d/rcS S boot +::shutdown:/etc/init.d/rcS K shutdown +ttyMSM0::askfirst:/usr/libexec/login.sh diff --git a/ipq806x/base-files/etc/uci-defaults/04_led_migration b/ipq806x/base-files/etc/uci-defaults/04_led_migration new file mode 100644 index 0000000..e56062b --- /dev/null +++ b/ipq806x/base-files/etc/uci-defaults/04_led_migration @@ -0,0 +1,7 @@ +. /lib/functions/migrations.sh + +remove_devicename_leds + +migrations_apply system + +exit 0 diff --git a/ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9888.txt b/ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9888.txt new file mode 100644 index 0000000..560c810 --- /dev/null +++ b/ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9888.txt @@ -0,0 +1,16 @@ +# 9888 chip +vdevs = 8 +peers = 202 +active_peers = 202 +stations = 202 +rate_ctrl_objs = 7 +#regdom = 840 +#fwname = firmware-5-htt-mgt-b.bin +#fwver = 5 +nohwcrypt = 0 +ct_sta_mode = 0 +tx_desc = 2200 +#max_nss = 3 +tids = 450 +skid_limit = 360 +max_amsdus = 3 diff --git a/ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9984.txt b/ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9984.txt new file mode 100644 index 0000000..924a689 --- /dev/null +++ b/ipq806x/base-files/lib/firmware/ath10k/fwcfg-qca9984.txt @@ -0,0 +1,16 @@ +# 9984 +vdevs = 8 +peers = 180 +active_peers = 180 +stations = 180 +rate_ctrl_objs = 7 +#regdom = 840 +#fwname = firmware-5-htt-mgt-b.bin +#fwver = 5 +nohwcrypt = 0 +ct_sta_mode = 0 +tx_desc = 2400 +#max_nss = 3 +tids = 450 +skid_limit = 360 +max_amsdus = 3 diff --git a/ipq806x/base-files/lib/preinit/04_reorder_eth b/ipq806x/base-files/lib/preinit/04_reorder_eth new file mode 100644 index 0000000..9f58473 --- /dev/null +++ b/ipq806x/base-files/lib/preinit/04_reorder_eth @@ -0,0 +1,13 @@ +. /lib/functions.sh + +preinit_reorder_eth() { + case $(board_name) in + ubnt,unifi-ac-hd) + ip link set eth0 name ethtmp + ip link set eth1 name eth0 + ip link set ethtmp name eth1 + ;; + esac +} + +boot_hook_add preinit_main preinit_reorder_eth diff --git a/ipq806x/base-files/lib/preinit/05_set_iface_mac_ipq806x.sh b/ipq806x/base-files/lib/preinit/05_set_iface_mac_ipq806x.sh new file mode 100644 index 0000000..ca8d0b1 --- /dev/null +++ b/ipq806x/base-files/lib/preinit/05_set_iface_mac_ipq806x.sh @@ -0,0 +1,14 @@ +. /lib/functions.sh + +preinit_set_mac_address() { + case $(board_name) in + asrock,g10) + lan_mac=$(mtd_get_mac_ascii hwconfig HW.LAN.MAC.Address) + wan_mac=$(mtd_get_mac_ascii hwconfig HW.WAN.MAC.Address) + ip link set dev eth0 address "${lan_mac}" + ip link set dev eth1 address "${wan_mac}" + ;; + esac +} + +boot_hook_add preinit_main preinit_set_mac_address diff --git a/ipq806x/base-files/lib/upgrade/asrock.sh b/ipq806x/base-files/lib/upgrade/asrock.sh new file mode 100644 index 0000000..8be737d --- /dev/null +++ b/ipq806x/base-files/lib/upgrade/asrock.sh @@ -0,0 +1,56 @@ +. /lib/functions.sh + +asrock_bootconfig_mangle() { + local mtdnum="$(find_mtd_index 0:bootconfig)" + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + [ -n "$mtdnum" ] || mtdnum="$(find_mtd_index 0:BOOTCONFIG)" + + if [ -z "$mtdnum" ]; then + echo "cannot find bootconfig mtd partition" + return 1 + fi + dd if=/dev/mtd$mtdnum of=/tmp/mtd$mtdnum bs=1k + + local partition_byte="$(dd if=/tmp/mtd$mtdnum bs=1 skip=52 count=1)" + local upgrade_byte="$(dd if=/tmp/mtd$mtdnum bs=1 skip=4 count=1)" + + if [ $1 = "bootcheck" ]; then + if [ ! -s $upgrade_byte ]; then + dd if=/dev/mtd$mtdnum of=/tmp/mtd$mtdnum bs=1k + printf '\x00' | dd of=/tmp/mtd$mtdnum conv=notrunc bs=1 seek=4 + printf '\x00' | dd of=/tmp/mtd$mtdnum conv=notrunc bs=1 seek=56 + else + return 1 + fi + elif [ $1 = "sysupgrade" ]; then + printf '\x01' | dd of=/tmp/mtd$mtdnum conv=notrunc bs=1 seek=4 + printf '\x01' | dd of=/tmp/mtd$mtdnum conv=notrunc bs=1 seek=56 + fi + + if [ -s $partition_byte ]; then + printf '\x01' | dd of=/tmp/mtd$mtdnum conv=notrunc bs=1 seek=52 + else + printf '\x00' | dd of=/tmp/mtd$mtdnum conv=notrunc bs=1 seek=52 + fi + + mtd write /tmp/mtd$mtdnum /dev/mtd$mtdnum + return 0 +} + +asrock_upgrade_prepare() { + local ubidev="$( nand_find_ubi ubi )" + + #Set upgrade flag. If something goes wrong, router will boot with + #factory firmware. + asrock_bootconfig_mangle 'sysupgrade' + + if [ $? -ne 0 ]; then + echo "cannot find bootconfig mtd partition" + exit 1 + fi + + # Just delete these partitions if present and use + # OpenWrt's standard names for those. + ubirmvol /dev/$ubidev -N ubi_rootfs &> /dev/null || true + ubirmvol /dev/$ubidev -N ubi_rootfs_data &> /dev/null || true +} diff --git a/ipq806x/base-files/lib/upgrade/buffalo.sh b/ipq806x/base-files/lib/upgrade/buffalo.sh new file mode 100644 index 0000000..6a51de4 --- /dev/null +++ b/ipq806x/base-files/lib/upgrade/buffalo.sh @@ -0,0 +1,44 @@ +# Copyright (C) 2018 OpenWrt.org +# + +. /lib/functions.sh + +# The mtd partition 'ubi' and 'rootfs_1' on NAND flash are os-image +# partitions. These partitions are called as "Bank1/Bank2" in U-Boot +# on WXR-2533DHP, and they are checked conditions when booting. +# Then, U-Boot checks kernel and rootfs volumes in ubi, but U-Boot +# needs "ubi_rootfs" as rootfs volume name. And, U-Boot checks the +# checksum at the end of rootfs (ubi_rootfs). +# When U-Boot writes os-image into the Bank, only kernel, rootfs +# (ubi_rootfs) and rootfs_data (ubi_rootfs_data) volumes are wrote +# into the Bank. (not full ubi image) +# +# == U-Boot Behaviors == +# - Bank1/Bank2 images are good, images are different +# -> writes os-image to Bank1 from Bank2 +# (this behavior is used to firmware upgrade in stock firmware) +# - Bank1 image is broken (or checksum error) +# -> writes os-image to Bank1 from Bank2 +# - Bank2 image is broken (or checksum error) +# -> writes os-image to Bank2 from Bank1 +# - Bank1/Bank2 images are broken (or checksum error) +# -> start tftp + +buffalo_upgrade_prepare_ubi() { + local ubidev="$( nand_find_ubi ubi )" + local mtdnum2="$( find_mtd_index rootfs_1 )" + + if [ ! "$mtdnum2" ]; then + echo "cannot find second ubi mtd partition rootfs_1" + return 1 + fi + + local ubidev2="$( nand_find_ubi rootfs_1 )" + if [ ! "$ubidev2" ] && [ -n "$mtdnum2" ]; then + ubiattach -m "$mtdnum2" + ubidev2="$( nand_find_ubi rootfs_1 )" + fi + + ubirmvol /dev/$ubidev -N ubi_rootfs_data &> /dev/null || true + ubirmvol /dev/$ubidev2 -N kernel &> /dev/null || true +} diff --git a/ipq806x/base-files/lib/upgrade/linksys.sh b/ipq806x/base-files/lib/upgrade/linksys.sh new file mode 100644 index 0000000..2277127 --- /dev/null +++ b/ipq806x/base-files/lib/upgrade/linksys.sh @@ -0,0 +1,118 @@ +# +# Copyright (C) 2014-2015 OpenWrt.org +# + +linksys_get_target_firmware() { + + local cur_boot_part mtd_ubi0 + + cur_boot_part=$(/usr/sbin/fw_printenv -n boot_part) + if [ -z "${cur_boot_part}" ] ; then + mtd_ubi0=$(cat /sys/devices/virtual/ubi/ubi0/mtd_num) + case $(egrep ^mtd${mtd_ubi0}: /proc/mtd | cut -d '"' -f 2) in + kernel1|rootfs1) + cur_boot_part=1 + ;; + kernel2|rootfs2) + cur_boot_part=2 + ;; + esac + >&2 printf "Current boot_part='%s' selected from ubi0/mtd_num='%s'" \ + "${cur_boot_part}" "${mtd_ubi0}" + fi + + case $cur_boot_part in + 1) + fw_setenv -s - <<-EOF + boot_part 2 + auto_recovery yes + EOF + printf "kernel2" + return + ;; + 2) + fw_setenv -s - <<-EOF + boot_part 1 + auto_recovery yes + EOF + printf "kernel1" + return + ;; + *) + return + ;; + esac +} + +linksys_get_root_magic() { + (get_image "$@" | dd skip=786432 bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2>/dev/null +} + +platform_do_upgrade_linksys() { + local magic_long="$(get_magic_long "$1")" + + mkdir -p /var/lock + local part_label="$(linksys_get_target_firmware)" + touch /var/lock/fw_printenv.lock + + if [ ! -n "$part_label" ] + then + echo "cannot find target partition" + exit 1 + fi + + local target_mtd=$(find_mtd_part $part_label) + + [ "$magic_long" = "73797375" ] && { + CI_KERNPART="$part_label" + if [ "$part_label" = "kernel1" ] + then + CI_UBIPART="rootfs1" + else + CI_UBIPART="rootfs2" + fi + + + # remove "squashfs" vol (in case we are flashing over a stock image, which is also UBI) + + local mtdnum="$( find_mtd_index "$CI_UBIPART" )" + if [ ! "$mtdnum" ]; then + echo "cannot find ubi mtd partition $CI_UBIPART" + return 1 + fi + + local ubidev="$( nand_find_ubi "$CI_UBIPART" )" + if [ ! "$ubidev" ]; then + ubiattach -m "$mtdnum" + sync + ubidev="$( nand_find_ubi "$CI_UBIPART" )" + fi + + if [ "$ubidev" ]; then + + local squash_ubivol="$( nand_find_volume $ubidev squashfs )" + + # kill volume + [ "$squash_ubivol" ] && ubirmvol /dev/$ubidev -N squashfs || true + fi + + + # complete std upgrade + nand_upgrade_tar "$1" + } + [ "$magic_long" = "27051956" ] && { + # check firmwares' rootfs types + local oldroot="$(linksys_get_root_magic $target_mtd)" + local newroot="$(linksys_get_root_magic "$1")" + + if [ "$newroot" = "55424923" -a "$oldroot" = "55424923" ] + # we're upgrading from a firmware with UBI to one with UBI + then + # erase everything to be safe + mtd erase $part_label + get_image "$1" | mtd -n write - $part_label + else + get_image "$1" | mtd write - $part_label + fi + } +} diff --git a/ipq806x/base-files/lib/upgrade/platform.sh b/ipq806x/base-files/lib/upgrade/platform.sh new file mode 100644 index 0000000..f3ac923 --- /dev/null +++ b/ipq806x/base-files/lib/upgrade/platform.sh @@ -0,0 +1,66 @@ +PART_NAME=firmware +REQUIRE_IMAGE_METADATA=1 + +RAMFS_COPY_BIN='fw_printenv fw_setenv' +RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock' + +platform_check_image() { + return 0; +} + +platform_do_upgrade() { + case "$(board_name)" in + askey,rt4230w-rev6 |\ + compex,wpq864|\ + netgear,d7800 |\ + netgear,r7500 |\ + netgear,r7500v2 |\ + netgear,r7800 |\ + qcom,ipq8064-ap148 |\ + qcom,ipq8064-ap161) + nand_do_upgrade "$1" + ;; + asrock,g10) + asrock_upgrade_prepare + nand_do_upgrade "$1" + ;; + buffalo,wxr-2533dhp) + buffalo_upgrade_prepare_ubi + CI_ROOTPART="ubi_rootfs" + nand_do_upgrade "$1" + ;; + edgecore,ssw2ac2600|\ + edgecore,ecw5410) + part="$(awk -F 'ubi.mtd=' '{printf $2}' /proc/cmdline | sed -e 's/ .*$//')" + if [ "$part" = "rootfs1" ]; then + fw_setenv active 2 || exit 1 + CI_UBIPART="rootfs2" + else + fw_setenv active 1 || exit 1 + CI_UBIPART="rootfs1" + fi + nand_do_upgrade "$1" + ;; + linksys,ea7500-v1 |\ + linksys,ea8500) + platform_do_upgrade_linksys "$1" + ;; + tplink,ad7200 |\ + tplink,c2600) + PART_NAME="os-image:rootfs" + MTD_CONFIG_ARGS="-s 0x200000" + default_do_upgrade "$1" + ;; + tplink,vr2600v) + PART_NAME="kernel:rootfs" + MTD_CONFIG_ARGS="-s 0x200000" + default_do_upgrade "$1" + ;; + zyxel,nbg6817) + zyxel_do_upgrade "$1" + ;; + *) + default_do_upgrade "$1" + ;; + esac +} diff --git a/ipq806x/base-files/lib/upgrade/zyxel.sh b/ipq806x/base-files/lib/upgrade/zyxel.sh new file mode 100644 index 0000000..50f8a3c --- /dev/null +++ b/ipq806x/base-files/lib/upgrade/zyxel.sh @@ -0,0 +1,127 @@ +# +# Copyright (C) 2016 lede-project.org +# + +zyxel_get_rootfs() { + local rootfsdev + + if read cmdline < /proc/cmdline; then + case "$cmdline" in + *root=*) + rootfsdev="${cmdline##*root=}" + rootfsdev="${rootfsdev%% *}" + ;; + esac + + echo "${rootfsdev}" + fi +} + +zyxel_do_flash() { + local tar_file=$1 + local kernel=$2 + local rootfs=$3 + local dualflagmtd=$4 + + # keep sure its unbound + losetup --detach-all || { + echo Failed to detach all loop devices. Skip this try. + reboot -f + } + + # use the first found directory in the tar archive + local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') + board_dir=${board_dir%/} + + echo "flashing kernel to $kernel" + tar xf $tar_file ${board_dir}/kernel -O >$kernel + + echo "flashing rootfs to ${rootfs}" + tar xf $tar_file ${board_dir}/root -O >"${rootfs}" + + # a padded rootfs is needed for overlay fs creation + local offset=$(tar xf $tar_file ${board_dir}/root -O | wc -c) + [ $offset -lt 65536 ] && { + echo Wrong size for rootfs: $offset + sleep 10 + reboot -f + } + + # Mount loop for rootfs_data + local loopdev="$(losetup -f)" + losetup -o $offset $loopdev $rootfs || { + echo "Failed to mount looped rootfs_data." + sleep 10 + reboot -f + } + + echo "Format new rootfs_data at position ${offset}." + mkfs.ext4 -F -L rootfs_data $loopdev + mkdir /tmp/new_root + mount -t ext4 $loopdev /tmp/new_root && { + echo "Saving config to rootfs_data at position ${offset}." + cp -v "$UPGRADE_BACKUP" "/tmp/new_root/$BACKUP_FILE" + umount /tmp/new_root + } + + # flashing successful, toggle the dualflag + case "$rootfs" in + "/dev/mmcblk0p5") + printf "\xff" >$dualflagmtd + ;; + "/dev/mmcblk0p8") + printf "\x01" >$dualflagmtd + ;; + esac + + # Cleanup + losetup -d $loopdev >/dev/null 2>&1 + sync + umount -a + reboot -f +} + +zyxel_do_upgrade() { + local tar_file="$1" + local board=$(board_name) + local rootfs="$(zyxel_get_rootfs)" + local kernel= + + [ -b "${rootfs}" ] || return 1 + case "$board" in + zyxel,nbg6817) + local dualflagmtd="$(find_mtd_part 0:dual_flag)" + # XXX: drop upper case after kernel v5.4 is gone (qcom-smem) + [ -b $dualflagmtd ] || \ + dualflagmtd="$(find_mtd_part 0:DUAL_FLAG)" + [ -b $dualflagmtd ] || return 1 + + case "$rootfs" in + "/dev/mmcblk0p5") + # booted from the primary partition set + # write to the alternative set + kernel="/dev/mmcblk0p7" + rootfs="/dev/mmcblk0p8" + ;; + "/dev/mmcblk0p8") + # booted from the alternative partition set + # write to the primary set + kernel="/dev/mmcblk0p4" + rootfs="/dev/mmcblk0p5" + ;; + *) + return 1 + ;; + esac + ;; + *) + return 1 + ;; + esac + + zyxel_do_flash $tar_file $kernel $rootfs $dualflagmtd + + nand_do_upgrade "$1" + + return 0 +} diff --git a/ipq806x/base-files/sbin/asrock_g10_back_to_factory b/ipq806x/base-files/sbin/asrock_g10_back_to_factory new file mode 100755 index 0000000..0ab6f17 --- /dev/null +++ b/ipq806x/base-files/sbin/asrock_g10_back_to_factory @@ -0,0 +1,15 @@ +#!/bin/sh + +. /lib/upgrade/asrock.sh + +case $(board_name) in +asrock,g10) + asrock_bootconfig_mangle "factory" + if [ $? -eq 0 ]; then + reboot + fi + ;; +*) + echo "Unsupported hardware." + ;; +esac diff --git a/ipq806x/config-5.10 b/ipq806x/config-5.10 new file mode 100644 index 0000000..6b8a418 --- /dev/null +++ b/ipq806x/config-5.10 @@ -0,0 +1,508 @@ +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_APQ_GCC_8084 is not set +# CONFIG_APQ_MMCC_8084 is not set +CONFIG_AR8216_PHY=y +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +# CONFIG_ARCH_IPQ40XX is not set +CONFIG_ARCH_KEEP_MEMBLOCK=y +# CONFIG_ARCH_MDM9615 is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MSM8960=y +CONFIG_ARCH_MSM8974=y +CONFIG_ARCH_MSM8X60=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_MODULE_PLTS=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_QCOM_CPUFREQ_HW is not set +CONFIG_ARM_QCOM_CPUFREQ_KRAIT=y +CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y +CONFIG_ARM_QCOM_SPM_CPUIDLE=y +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_AT803X_PHY=y +CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_QCOM=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE_OVERRIDE=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +CONFIG_CPU_THERMAL=y +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_QCOM_RNG=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +# CONFIG_DEVFREQ_GOV_PASSIVE is not set +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set +# CONFIG_DEVFREQ_THERMAL is not set +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_OPS=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DTC=y +CONFIG_DT_IDLE_STATES=y +# CONFIG_DWMAC_GENERIC is not set +CONFIG_DWMAC_IPQ806X=y +# CONFIG_DWMAC_QCOM_ETHQOS is not set +CONFIG_DYNAMIC_DEBUG=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_VDSO_32=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GRO_CELLS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_SMP=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HWMON=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_HW_RANDOM=y +CONFIG_HZ=100 +CONFIG_HZ_100=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y +# CONFIG_I2C_QCOM_CCI is not set +CONFIG_I2C_QUP=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +# CONFIG_IPQ_APSS_PLL is not set +# CONFIG_IPQ_GCC_4019 is not set +# CONFIG_IPQ_GCC_6018 is not set +CONFIG_IPQ_GCC_806X=y +# CONFIG_IPQ_GCC_8074 is not set +# CONFIG_IPQ_LCC_806X is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_KPSS_XCC=y +CONFIG_KRAITCC=y +CONFIG_KRAIT_CLOCKS=y +CONFIG_KRAIT_L2_ACCESSORS=y +CONFIG_LIBFDT=y +CONFIG_LLD_VERSION=0 +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_GPIO=y +CONFIG_MDIO_IPQ8064=y +# CONFIG_MDM_GCC_9615 is not set +# CONFIG_MDM_LCC_9615 is not set +CONFIG_MEMFD_CREATE=y +# CONFIG_MFD_HI6421_SPMI is not set +CONFIG_MFD_QCOM_RPM=y +# CONFIG_MFD_SPMI_PMIC is not set +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_CQHCI=y +CONFIG_MMC_QCOM_DML=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MSM_GCC_8660=y +# CONFIG_MSM_GCC_8916 is not set +# CONFIG_MSM_GCC_8939 is not set +# CONFIG_MSM_GCC_8960 is not set +# CONFIG_MSM_GCC_8974 is not set +# CONFIG_MSM_GCC_8994 is not set +# CONFIG_MSM_GCC_8996 is not set +# CONFIG_MSM_GCC_8998 is not set +# CONFIG_MSM_GPUCC_8998 is not set +# CONFIG_MSM_IOMMU is not set +# CONFIG_MSM_LCC_8960 is not set +# CONFIG_MSM_MMCC_8960 is not set +# CONFIG_MSM_MMCC_8974 is not set +# CONFIG_MSM_MMCC_8996 is not set +# CONFIG_MSM_MMCC_8998 is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_ECC_SW_HAMMING=y +CONFIG_MTD_NAND_QCOM=y +CONFIG_MTD_QCOMSMEM_PARTS=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_FIT_FW=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DEVLINK=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_QCA8K=y +CONFIG_NET_DSA_TAG_QCA=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SWITCHDEV=y +CONFIG_NLS=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=2 +CONFIG_NVMEM=y +# CONFIG_NVMEM_SPMI_SDAM is not set +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PAGE_POOL=y +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_HOST=y +CONFIG_PCIE_QCOM=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_DISABLE_COMMON_QUIRKS=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCS_XPCS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +# CONFIG_PHY_QCOM_APQ8064_SATA is not set +# CONFIG_PHY_QCOM_IPQ4019_USB is not set +CONFIG_PHY_QCOM_IPQ806X_SATA=y +# CONFIG_PHY_QCOM_IPQ806X_USB is not set +# CONFIG_PHY_QCOM_PCIE2 is not set +# CONFIG_PHY_QCOM_QMP is not set +# CONFIG_PHY_QCOM_QUSB2 is not set +# CONFIG_PHY_QCOM_USB_HS_28NM is not set +# CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2 is not set +# CONFIG_PHY_QCOM_USB_SS is not set +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_APQ8064 is not set +# CONFIG_PINCTRL_APQ8084 is not set +# CONFIG_PINCTRL_IPQ4019 is not set +# CONFIG_PINCTRL_IPQ6018 is not set +CONFIG_PINCTRL_IPQ8064=y +# CONFIG_PINCTRL_IPQ8074 is not set +# CONFIG_PINCTRL_MDM9615 is not set +CONFIG_PINCTRL_MSM=y +# CONFIG_PINCTRL_MSM8226 is not set +# CONFIG_PINCTRL_MSM8660 is not set +# CONFIG_PINCTRL_MSM8916 is not set +# CONFIG_PINCTRL_MSM8960 is not set +# CONFIG_PINCTRL_MSM8976 is not set +# CONFIG_PINCTRL_MSM8994 is not set +# CONFIG_PINCTRL_MSM8996 is not set +# CONFIG_PINCTRL_MSM8998 is not set +# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set +# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set +# CONFIG_PINCTRL_QCS404 is not set +# CONFIG_PINCTRL_SC7180 is not set +# CONFIG_PINCTRL_SDM660 is not set +# CONFIG_PINCTRL_SDM845 is not set +# CONFIG_PINCTRL_SM8150 is not set +# CONFIG_PINCTRL_SM8250 is not set +CONFIG_PM_DEVFREQ=y +# CONFIG_PM_DEVFREQ_EVENT is not set +CONFIG_PM_OPP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_MSM=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +# CONFIG_QCOM_A53PLL is not set +CONFIG_QCOM_ADM=y +CONFIG_QCOM_BAM_DMA=y +CONFIG_QCOM_CLK_RPM=y +# CONFIG_QCOM_COMMAND_DB is not set +# CONFIG_QCOM_CPR is not set +# CONFIG_QCOM_EBI2 is not set +# CONFIG_QCOM_GENI_SE is not set +CONFIG_QCOM_GSBI=y +CONFIG_QCOM_HFPLL=y +# CONFIG_QCOM_IOMMU is not set +# CONFIG_QCOM_LLCC is not set +# CONFIG_QCOM_OCMEM is not set +# CONFIG_QCOM_PDC is not set +CONFIG_QCOM_QFPROM=y +# CONFIG_QCOM_RMTFS_MEM is not set +CONFIG_QCOM_RPMCC=y +# CONFIG_QCOM_RPMH is not set +CONFIG_QCOM_SCM=y +# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set +CONFIG_QCOM_SMEM=y +# CONFIG_QCOM_SMSM is not set +# CONFIG_QCOM_SOCINFO is not set +CONFIG_QCOM_TCSR=y +CONFIG_QCOM_TSENS=y +CONFIG_QCOM_WDT=y +# CONFIG_QCS_GCC_404 is not set +# CONFIG_QCS_Q6SSTOP_404 is not set +# CONFIG_QCS_TURING_404 is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_QCOM_LABIBB is not set +CONFIG_REGULATOR_QCOM_RPM=y +# CONFIG_REGULATOR_QCOM_SPMI is not set +# CONFIG_REGULATOR_QCOM_USB_VBUS is not set +# CONFIG_REGULATOR_VQMMC_IPQ4019 is not set +CONFIG_RESET_CONTROLLER=y +# CONFIG_RESET_QCOM_AOSS is not set +# CONFIG_RESET_QCOM_PDC is not set +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SC_DISPCC_7180 is not set +# CONFIG_SC_GCC_7180 is not set +# CONFIG_SC_GPUCC_7180 is not set +# CONFIG_SC_LPASS_CORECC_7180 is not set +# CONFIG_SC_MSS_7180 is not set +# CONFIG_SC_VIDEOCC_7180 is not set +# CONFIG_SDM_CAMCC_845 is not set +# CONFIG_SDM_DISPCC_845 is not set +# CONFIG_SDM_GCC_660 is not set +# CONFIG_SDM_GCC_845 is not set +# CONFIG_SDM_GPUCC_845 is not set +# CONFIG_SDM_LPASSCC_845 is not set +# CONFIG_SDM_VIDEOCC_845 is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SGL_ALLOC=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +# CONFIG_SM_GCC_8150 is not set +# CONFIG_SM_GCC_8250 is not set +# CONFIG_SM_GPUCC_8150 is not set +# CONFIG_SM_GPUCC_8250 is not set +# CONFIG_SM_VIDEOCC_8150 is not set +# CONFIG_SM_VIDEOCC_8250 is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_QUP=y +CONFIG_SPMI=y +# CONFIG_SPMI_HISI3670 is not set +CONFIG_SPMI_MSM_PMIC_ARB=y +# CONFIG_SPMI_PMIC_CLKDIV is not set +CONFIG_SRCU=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +# CONFIG_STMMAC_SELFTESTS is not set +CONFIG_SWCONFIG=y +CONFIG_SWCONFIG_LEDS=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UBIFS_FS_ZSTD=y +# CONFIG_UCLAMP_TASK is not set +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNWINDER_ARM=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_SUPPORT=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XXHASH=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/ipq806x/config-5.4 b/ipq806x/config-5.4 new file mode 100644 index 0000000..fd42d37 --- /dev/null +++ b/ipq806x/config-5.4 @@ -0,0 +1,456 @@ +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_APQ_GCC_8084 is not set +# CONFIG_APQ_MMCC_8084 is not set +CONFIG_AR8216_PHY=y +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +# CONFIG_ARCH_MDM9615 is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MSM8960=y +CONFIG_ARCH_MSM8974=y +CONFIG_ARCH_MSM8X60=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_MODULE_PLTS=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_QCOM_CPUFREQ_HW is not set +CONFIG_ARM_QCOM_CPUFREQ_KRAIT=y +CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y +CONFIG_ARM_QCOM_CPUIDLE=y +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_AT803X_PHY=y +CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_QCOM=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE_OVERRIDE=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +CONFIG_CPU_THERMAL=y +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_QCOM_RNG=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DTC=y +CONFIG_DT_IDLE_STATES=y +# CONFIG_DWMAC_GENERIC is not set +CONFIG_DWMAC_IPQ806X=y +# CONFIG_DWMAC_QCOM_ETHQOS is not set +CONFIG_DYNAMIC_DEBUG=y +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ETHERNET_PACKET_MANGLE=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GRO_CELLS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_SMP=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HWMON=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_HW_RANDOM=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_QUP=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +# CONFIG_IPQ_GCC_4019 is not set +CONFIG_IPQ_GCC_806X=y +# CONFIG_IPQ_GCC_8074 is not set +# CONFIG_IPQ_LCC_806X is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_KPSS_XCC=y +CONFIG_KRAITCC=y +CONFIG_KRAIT_CLOCKS=y +CONFIG_KRAIT_L2_ACCESSORS=y +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_GPIO=y +CONFIG_MDIO_IPQ8064=y +# CONFIG_MDM_GCC_9615 is not set +# CONFIG_MDM_LCC_9615 is not set +CONFIG_MEMFD_CREATE=y +CONFIG_MFD_QCOM_RPM=y +# CONFIG_MFD_SPMI_PMIC is not set +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_QCOM_DML=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MSM_GCC_8660=y +# CONFIG_MSM_GCC_8916 is not set +# CONFIG_MSM_GCC_8960 is not set +# CONFIG_MSM_GCC_8974 is not set +# CONFIG_MSM_GCC_8994 is not set +# CONFIG_MSM_GCC_8996 is not set +# CONFIG_MSM_GCC_8998 is not set +# CONFIG_MSM_IOMMU is not set +# CONFIG_MSM_LCC_8960 is not set +# CONFIG_MSM_MMCC_8960 is not set +# CONFIG_MSM_MMCC_8974 is not set +# CONFIG_MSM_MMCC_8996 is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC_SW_HAMMING=y +CONFIG_MTD_NAND_QCOM=y +CONFIG_MTD_QCOMSMEM_PARTS=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_FIT_FW=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DEVLINK=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_QCA8K=y +CONFIG_NET_DSA_TAG_QCA=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SWITCHDEV=y +CONFIG_NLS=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=2 +CONFIG_NVMEM=y +# CONFIG_NVME_TCP is not set +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PAGE_POOL=y +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_HOST=y +CONFIG_PCIE_QCOM=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_DISABLE_COMMON_QUIRKS=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +# CONFIG_PHY_QCOM_APQ8064_SATA is not set +CONFIG_PHY_QCOM_IPQ806X_SATA=y +# CONFIG_PHY_QCOM_IPQ806X_USB is not set +# CONFIG_PHY_QCOM_PCIE2 is not set +# CONFIG_PHY_QCOM_QMP is not set +# CONFIG_PHY_QCOM_QUSB2 is not set +# CONFIG_PHY_QCOM_UFS is not set +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_APQ8064 is not set +# CONFIG_PINCTRL_APQ8084 is not set +# CONFIG_PINCTRL_IPQ4019 is not set +CONFIG_PINCTRL_IPQ8064=y +# CONFIG_PINCTRL_IPQ8074 is not set +# CONFIG_PINCTRL_MDM9615 is not set +CONFIG_PINCTRL_MSM=y +# CONFIG_PINCTRL_MSM8660 is not set +# CONFIG_PINCTRL_MSM8916 is not set +# CONFIG_PINCTRL_MSM8960 is not set +# CONFIG_PINCTRL_MSM8994 is not set +# CONFIG_PINCTRL_MSM8996 is not set +# CONFIG_PINCTRL_MSM8998 is not set +# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set +# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set +# CONFIG_PINCTRL_QCS404 is not set +# CONFIG_PINCTRL_SC7180 is not set +# CONFIG_PINCTRL_SDM660 is not set +# CONFIG_PINCTRL_SDM845 is not set +# CONFIG_PINCTRL_SM8150 is not set +CONFIG_PM_OPP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_MSM=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +# CONFIG_QCOM_A53PLL is not set +CONFIG_QCOM_ADM=y +CONFIG_QCOM_BAM_DMA=y +CONFIG_QCOM_CLK_RPM=y +# CONFIG_QCOM_COMMAND_DB is not set +# CONFIG_QCOM_EBI2 is not set +# CONFIG_QCOM_GENI_SE is not set +CONFIG_QCOM_GSBI=y +CONFIG_QCOM_HFPLL=y +# CONFIG_QCOM_IOMMU is not set +# CONFIG_QCOM_LLCC is not set +# CONFIG_QCOM_PDC is not set +CONFIG_QCOM_PM=y +CONFIG_QCOM_QFPROM=y +# CONFIG_QCOM_RMTFS_MEM is not set +CONFIG_QCOM_RPMCC=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_SCM_32=y +# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set +CONFIG_QCOM_SMEM=y +# CONFIG_QCOM_SMSM is not set +# CONFIG_QCOM_SOCINFO is not set +CONFIG_QCOM_TCSR=y +CONFIG_QCOM_TSENS=y +CONFIG_QCOM_WDT=y +# CONFIG_QCS_GCC_404 is not set +# CONFIG_QCS_TURING_404 is not set +# CONFIG_QRTR is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_REFCOUNT_FULL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_QCOM_RPM=y +# CONFIG_REGULATOR_QCOM_SPMI is not set +CONFIG_RESET_CONTROLLER=y +# CONFIG_RESET_QCOM_AOSS is not set +# CONFIG_RESET_QCOM_PDC is not set +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SDM_CAMCC_845 is not set +# CONFIG_SDM_DISPCC_845 is not set +# CONFIG_SDM_GCC_660 is not set +# CONFIG_SDM_GCC_845 is not set +# CONFIG_SDM_GPUCC_845 is not set +# CONFIG_SDM_LPASSCC_845 is not set +# CONFIG_SDM_VIDEOCC_845 is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SGL_ALLOC=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +# CONFIG_SM_GCC_8150 is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_QUP=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB=y +# CONFIG_SPMI_PMIC_CLKDIV is not set +CONFIG_SRCU=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +# CONFIG_STMMAC_SELFTESTS is not set +CONFIG_SWCONFIG=y +CONFIG_SWCONFIG_LEDS=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +# CONFIG_UCLAMP_TASK is not set +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNWINDER_ARM=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_SUPPORT=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XXHASH=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/ipq806x/config-5.4-generic b/ipq806x/config-5.4-generic new file mode 100644 index 0000000..a2d9886 --- /dev/null +++ b/ipq806x/config-5.4-generic @@ -0,0 +1,6572 @@ +# CONFIG_104_QUAD_8 is not set +CONFIG_32BIT=y +CONFIG_64BIT_TIME=y +# CONFIG_6LOWPAN is not set +# CONFIG_6LOWPAN_DEBUGFS is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABP060MG is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_ALS is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_NFIT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_TABLE_UPGRADE is not set +# CONFIG_ACPI_VIDEO is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5272 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5686_SPI is not set +# CONFIG_AD5696_I2C is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5758 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7124 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7606_IFACE_PARALLEL is not set +# CONFIG_AD7606_IFACE_SPI is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7766 is not set +# CONFIG_AD7768_1 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD7949 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD8801 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADF4371 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16460 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +CONFIG_ADVISE_SYSCALLS=y +# CONFIG_ADXL345_I2C is not set +# CONFIG_ADXL345_SPI is not set +# CONFIG_ADXL372_I2C is not set +# CONFIG_ADXL372_SPI is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_DEBUG_CURSOR is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_KCM is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_RXRPC_INJECT_LOSS is not set +# CONFIG_AF_RXRPC_IPV6 is not set +# CONFIG_AGP is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_IMX is not set +# CONFIG_AHCI_MVEBU is not set +# CONFIG_AHCI_QORIQ is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8974 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AL_FIC is not set +# CONFIG_AM2315 is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_HAVE_ECC is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9960 is not set +# CONFIG_APM8018X is not set +# CONFIG_APM_EMULATION is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_APPLE_PROPERTIES is not set +# CONFIG_APPLICOM is not set +# CONFIG_AQTION is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_AGILEX is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_ARTPEC is not set +# CONFIG_ARCH_ASPEED is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_AXXIA is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_21664 is not set +# CONFIG_ARCH_BCM_23550 is not set +# CONFIG_ARCH_BCM_281XX is not set +# CONFIG_ARCH_BCM_5301X is not set +# CONFIG_ARCH_BCM_53573 is not set +# CONFIG_ARCH_BCM_63XX is not set +# CONFIG_ARCH_BCM_CYGNUS is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BCM_NSP is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BITMAIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MILBEAUT is not set +CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NPCM is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_OXNAS is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_RDA is not set +# CONFIG_ARCH_REALTEK is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_STM32 is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TANGO is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_VULCAN is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WANTS_THP_SWAP is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8750 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCH_ZYNQMP is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARC_IRQ_NO_AUTOSAVE is not set +# CONFIG_ARM64_16K_PAGES is not set +# CONFIG_ARM64_64K_PAGES is not set +# CONFIG_ARM64_CRYPTO is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +# CONFIG_ARM64_ERRATUM_1542419 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_834220 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +# CONFIG_ARM64_MODULE_PLTS is not set +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PSEUDO_NMI is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_RELOC_TEST is not set +CONFIG_ARM64_SW_TTBR0_PAN=y +# CONFIG_ARM64_UAO is not set +# CONFIG_ARM64_VA_BITS_48 is not set +# CONFIG_ARM64_VHE is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCI400_PMU is not set +# CONFIG_ARM_CCI5xx_PMU is not set +# CONFIG_ARM_CCI_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CPUIDLE is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_ARM_CRYPTO is not set +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_DSU_PMU is not set +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_814220 is not set +# CONFIG_ARM_ERRATA_818325_852422 is not set +# CONFIG_ARM_ERRATA_821420 is not set +# CONFIG_ARM_ERRATA_825619 is not set +# CONFIG_ARM_ERRATA_852421 is not set +# CONFIG_ARM_ERRATA_852423 is not set +# CONFIG_ARM_ERRATA_857271 is not set +# CONFIG_ARM_ERRATA_857272 is not set +CONFIG_ARM_GIC_MAX_NR=1 +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_LPAE is not set +# CONFIG_ARM_MHU is not set +# CONFIG_ARM_MODULE_PLTS is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PSCI_CHECKER is not set +# CONFIG_ARM_PSCI_CPUIDLE is not set +# CONFIG_ARM_PTDUMP_DEBUGFS is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_SDE_INTERFACE is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_ARM_SPE_PMU is not set +# CONFIG_ARM_THUMBEE is not set +# CONFIG_ARM_TIMER_SP804 is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +# CONFIG_AS3935 is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_AT91_SAMA5D2_ADC is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_LEDS is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AURORA_NB8800 is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_AXP20X_ADC is not set +# CONFIG_AXP20X_POWER is not set +# CONFIG_AXP288_ADC is not set +# CONFIG_AXP288_FUEL_GAUGE is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_RPI is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_BQ27XXX_HDQ is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_LEGO_EV3 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_MAX1721X is not set +# CONFIG_BATTERY_RT5033 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7038_WDT is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_IPROC_ADC is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +# CONFIG_BINARY_PRINTF is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_ELF_FDPIC is not set +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CGROUP_IOCOST is not set +# CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_WBT is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMC150_MAGN is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_BME680 is not set +# CONFIG_BMG160 is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BNX2X_SRIOV is not set +# CONFIG_BNXT is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +CONFIG_BPF=y +# CONFIG_BPFILTER is not set +CONFIG_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +# CONFIG_BPF_STREAM_PARSER is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_BRIDGE_VLAN_FILTERING=y +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set +# CONFIG_BT_HCIBTUSB_MTK is not set +# CONFIG_BT_HCIBTUSB_RTL is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_AG6XX is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_MRVL is not set +# CONFIG_BT_HCIUART_QCA is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +# CONFIG_BT_HS is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_LEDS is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_MTKSDIO is not set +# CONFIG_BT_MTKUART is not set +# CONFIG_BT_RFCOMM is not set +CONFIG_BT_RFCOMM_TTY=y +# CONFIG_BT_SELFTEST is not set +CONFIG_BUG=y +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# CONFIG_BUILDTIME_EXTABLE_SORT is not set +# CONFIG_BUILD_BIN2C is not set +CONFIG_BUILD_SALT="" +# CONFIG_C2PORT is not set +CONFIG_CACHE_L2X0_PMU=y +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_BCM is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_CAN_DEV is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_GW is not set +# CONFIG_CAN_HI311X is not set +# CONFIG_CAN_IFI_CANFD is not set +# CONFIG_CAN_J1939 is not set +# CONFIG_CAN_KVASER_PCIEFD is not set +# CONFIG_CAN_MCBA_USB is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_PEAK_PCIEFD is not set +# CONFIG_CAN_RAW is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAN_RCAR_CANFD is not set +# CONFIG_CAN_SLCAN is not set +# CONFIG_CAN_SUN4I is not set +# CONFIG_CAN_UCAN is not set +# CONFIG_CAN_VCAN is not set +# CONFIG_CAN_VXCAN is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CASSINI is not set +# CONFIG_CAVIUM_CPT is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23144 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CAVIUM_PTP is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CCS811 is not set +CONFIG_CC_CAN_LINK=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +CONFIG_CC_HAS_STACKPROTECTOR_NONE=y +CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_LT3651 is not set +# CONFIG_CHARGER_LTC3651 is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHARGER_UCS1002 is not set +# CONFIG_CHASH_SELFTEST is not set +# CONFIG_CHASH_STATS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +CONFIG_CIFS_XATTR=y +# CONFIG_CIO_DAC is not set +CONFIG_CLANG_VERSION=0 +# CONFIG_CLEANCACHE is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLK_HSDK is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM3605 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_COMMON_CLK_IPROC is not set +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_NXP is not set +# CONFIG_COMMON_CLK_PIC32 is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_VERSATILE is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +CONFIG_COMPACTION=y +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONFIG_KVM_AMD_SEV is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_COUNTER is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CPU_ISOLATION is not set +# CONFIG_CPU_NO_EFFICIENT_FFS is not set +CONFIG_CPU_SW_DOMAIN_PAN=y +# CONFIG_CRAMFS is not set +CONFIG_CRAMFS_BLOCKDEV=y +# CONFIG_CRAMFS_MTD is not set +CONFIG_CRASHLOG=y +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_AEAD is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128L is not set +# CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS256 is not set +# CONFIG_CRYPTO_AEGIS256_AESNI_SSE2 is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_ARM_CE is not set +# CONFIG_CRYPTO_AES_ARM64 is not set +# CONFIG_CRYPTO_AES_ARM64_BS is not set +# CONFIG_CRYPTO_AES_ARM64_CE is not set +# CONFIG_CRYPTO_AES_ARM64_CE_BLK is not set +# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set +# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CFB is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_CHACHA20_NEON is not set +# CONFIG_CRYPTO_CHACHA_MIPS is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRC32_ARM_CE is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRCT10DIF_ARM_CE is not set +# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_NEON is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AUTHENC is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set +# CONFIG_CRYPTO_DEV_CCREE is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_HISI_SEC is not set +# CONFIG_CRYPTO_DEV_HISI_ZIP is not set +# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set +# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_MXC_SCC is not set +# CONFIG_CRYPTO_DEV_MXS_DCP is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_S5P is not set +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_SP_PSP is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DEV_VIRTIO is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_ESSIV is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_GHASH_ARM_CE is not set +# CONFIG_CRYPTO_GHASH_ARM64_CE is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_HASH is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_KHAZAD is not set +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=y +# CONFIG_CRYPTO_LIB_BLAKE2S is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +# CONFIG_CRYPTO_LIB_POLY1305 is not set +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_MORUS1280 is not set +# CONFIG_CRYPTO_MORUS1280_AVX2 is not set +# CONFIG_CRYPTO_MORUS1280_SSE2 is not set +# CONFIG_CRYPTO_MORUS640 is not set +# CONFIG_CRYPTO_MORUS640_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_NEON is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +CONFIG_CRYPTO_PCRYPT=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_ARM is not set +# CONFIG_CRYPTO_POLY1305_MIPS is not set +# CONFIG_CRYPTO_POLY1305_NEON is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SALSA20_586 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA1_ARM_CE is not set +# CONFIG_CRYPTO_SHA1_ARM_NEON is not set +# CONFIG_CRYPTO_SHA1_ARM64_CE is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA256_ARM is not set +# CONFIG_CRYPTO_SHA256_ARM64 is not set +# CONFIG_CRYPTO_SHA2_ARM_CE is not set +# CONFIG_CRYPTO_SHA2_ARM64_CE is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SHA3_ARM64 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_SHA512_ARM is not set +# CONFIG_CRYPTO_SHA512_ARM64 is not set +# CONFIG_CRYPTO_SHA512_ARM64_CE is not set +# CONFIG_CRYPTO_SIMD is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_SM3_ARM64_CE is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_SM4_ARM64_CE is not set +# CONFIG_CRYPTO_SPECK is not set +# CONFIG_CRYPTO_STATS is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_XXHASH is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_ZSTD is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXL_AFU_DRIVER_OPS is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXL_EEH is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CXL_LIB is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DAX is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DEBUG_ALIGN_RODATA is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_EFI is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_BTF is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +CONFIG_DEBUG_INFO_REDUCED=y +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MISC is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RSEQ is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_UART_8250_PALMCHIP is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_WX is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_DEADLINE=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +CONFIG_DEFAULT_IOSCHED="deadline" +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_DELL_LAPTOP is not set +# CONFIG_DELL_RBTN is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DEV_DAX is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DHT11 is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DL2K is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMARD06 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +CONFIG_DMA_DECLARE_COHERENT=y +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_FENCE_TRACE is not set +# CONFIG_DMA_JZ4780 is not set +# CONFIG_DMA_NOOP_OPS is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_VIRT_OPS is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_MQ_DEFAULT is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DPOT_DAC is not set +# CONFIG_DPS310 is not set +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_AMDGPU_CIK is not set +# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set +# CONFIG_DRM_AMDGPU_SI is not set +# CONFIG_DRM_AMDGPU_USERPTR is not set +# CONFIG_DRM_AMD_ACP is not set +# CONFIG_DRM_AMD_DC_DCN2_0 is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_ARMADA is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_DEBUG_MM is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DP_CEC is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set +# CONFIG_DRM_DW_HDMI_CEC is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_FSL_DCU is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_DRM_GMA500 is not set +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I915 is not set +# CONFIG_DRM_KOMEDA is not set +# CONFIG_DRM_LEGACY is not set +# CONFIG_DRM_LIB_RANDOM is not set +# CONFIG_DRM_LIMA is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_LVDS_ENCODER is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_MCDE is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_OMAP is not set +# CONFIG_DRM_PANEL_ARM_VERSATILE is not set +# CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D is not set +# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set +# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set +# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set +# CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set +# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set +# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set +# CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS is not set +# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set +# CONFIG_DRM_PANEL_ROCKTECH_JH057N00900 is not set +# CONFIG_DRM_PANEL_RONBO_RB070D30 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6D16D0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set +# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set +# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set +# CONFIG_DRM_PANEL_SIMPLE is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set +# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DRM_PANEL_TPO_TPG110 is not set +# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set +# CONFIG_DRM_PANFROST is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PL111 is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_RADEON_USERPTR is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_STI is not set +# CONFIG_DRM_STM is not set +# CONFIG_DRM_SUN4I is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_TINYDRM is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TOSHIBA_TC358764 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_VBOXVIDEO is not set +# CONFIG_DRM_VC4_HDMI_CEC is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VIRTIO_GPU is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_XEN is not set +# CONFIG_DS1682 is not set +# CONFIG_DS1803 is not set +# CONFIG_DS4424 is not set +# CONFIG_DST_CACHE is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DWC_XLGMAC is not set +# CONFIG_DWMAC_DWC_QOS_ETH is not set +# CONFIG_DWMAC_IPQ806X is not set +# CONFIG_DWMAC_LPC18XX is not set +# CONFIG_DWMAC_MESON is not set +# CONFIG_DWMAC_ROCKCHIP is not set +# CONFIG_DWMAC_SOCFPGA is not set +# CONFIG_DWMAC_STI is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_HWTS is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EBC_C384_WDT is not set +# CONFIG_ECHO is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_EE1004 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EFI is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFS_FS is not set +CONFIG_ELFCORE=y +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENA_ETHERNET is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_ENERGY_MODEL is not set +# CONFIG_ENIC is not set +# CONFIG_ENVELOPE_DETECTOR is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_EROFS_FS is not set +# CONFIG_ET131X is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_EVENTFD=y +# CONFIG_EVM is not set +# CONFIG_EXFAT_FS is not set +CONFIG_EXPERT=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +# CONFIG_EXT2_FS is not set +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_USE_FOR_EXT2=y +# CONFIG_EXTCON is not set +# CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set +# CONFIG_EXTCON_AXP288 is not set +# CONFIG_EXTCON_FSA9480 is not set +# CONFIG_EXTCON_GPIO is not set +# CONFIG_EXTCON_INTEL_INT3496 is not set +# CONFIG_EXTCON_MAX3355 is not set +# CONFIG_EXTCON_PTN5150 is not set +# CONFIG_EXTCON_QCOM_SPMI_MISC is not set +# CONFIG_EXTCON_RT8973A is not set +# CONFIG_EXTCON_SM5502 is not set +# CONFIG_EXTCON_USB_GPIO is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FS_POSIX_ACL is not set +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +# CONFIG_F2FS_IO_TRACE is not set +CONFIG_F2FS_STAT_FS=y +# CONFIG_FAILOVER is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_DEFAULT_UTF8 is not set +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BOTH_ENDIAN is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FLEX is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_MXS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_NOTIFY=y +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OMAP2 is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM712 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TFT is not set +# CONFIG_FB_TFT_AGM1264K_FL is not set +# CONFIG_FB_TFT_BD663474 is not set +# CONFIG_FB_TFT_FBTFT_DEVICE is not set +# CONFIG_FB_TFT_HX8340BN is not set +# CONFIG_FB_TFT_HX8347D is not set +# CONFIG_FB_TFT_HX8353D is not set +# CONFIG_FB_TFT_HX8357D is not set +# CONFIG_FB_TFT_ILI9163 is not set +# CONFIG_FB_TFT_ILI9320 is not set +# CONFIG_FB_TFT_ILI9325 is not set +# CONFIG_FB_TFT_ILI9340 is not set +# CONFIG_FB_TFT_ILI9341 is not set +# CONFIG_FB_TFT_ILI9481 is not set +# CONFIG_FB_TFT_ILI9486 is not set +# CONFIG_FB_TFT_PCD8544 is not set +# CONFIG_FB_TFT_RA8875 is not set +# CONFIG_FB_TFT_S6D02A1 is not set +# CONFIG_FB_TFT_S6D1121 is not set +# CONFIG_FB_TFT_SH1106 is not set +# CONFIG_FB_TFT_SSD1289 is not set +# CONFIG_FB_TFT_SSD1305 is not set +# CONFIG_FB_TFT_SSD1306 is not set +# CONFIG_FB_TFT_SSD1325 is not set +# CONFIG_FB_TFT_SSD1331 is not set +# CONFIG_FB_TFT_SSD1351 is not set +# CONFIG_FB_TFT_ST7735R is not set +# CONFIG_FB_TFT_ST7789V is not set +# CONFIG_FB_TFT_TINYLCD is not set +# CONFIG_FB_TFT_TLS8204 is not set +# CONFIG_FB_TFT_UC1611 is not set +# CONFIG_FB_TFT_UC1701 is not set +# CONFIG_FB_TFT_UPD161704 is not set +# CONFIG_FB_TFT_WATTEROTT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +# CONFIG_FIELDBUS_DEV is not set +CONFIG_FILE_LOCKING=y +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FONTS is not set +# CONFIG_FONT_TER16x32 is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORTIFY_SOURCE=y +# CONFIG_FPGA is not set +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSI is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_FSL_MC_BUS is not set +# CONFIG_FSL_PQ_MDIO is not set +# CONFIG_FSL_QDMA is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_DAX is not set +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FS_VERITY is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FTWDT010_WATCHDOG is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +# CONFIG_FW_CFG_SYSFS is not set +CONFIG_FW_LOADER=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FXAS21002C is not set +# CONFIG_FXOS8700_I2C is not set +# CONFIG_FXOS8700_SPI is not set +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GCC_PLUGINS is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GEMINI_ETHERNET is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_GENERIC_ADC_THERMAL is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HWEIGHT=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +# CONFIG_GENEVE is not set +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_DUMMYLL is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GNSS is not set +# CONFIG_GOLDFISH is not set +# CONFIG_GOOGLE_FIRMWARE is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_GPIOLIB is not set +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +# CONFIG_GPIO_104_DIO_48E is not set +# CONFIG_GPIO_104_IDIO_16 is not set +# CONFIG_GPIO_104_IDI_48 is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_AMD_FCH is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GPIO_MM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_LYNXPOINT is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_GPIO_MPC8XXX is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SAMA5D2_PIOBU is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +CONFIG_GPIO_SYSFS=y +# CONFIG_GPIO_TPIC2810 is not set +# CONFIG_GPIO_TS4900 is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_XRA1403 is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GPIO_ZX is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_GREYBUS is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_GTP is not set +# CONFIG_GUP_BENCHMARK is not set +# CONFIG_GVE is not set +# CONFIG_HABANA_AI is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_FALLBACK is not set +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +CONFIG_HARDEN_EL2_VECTORS=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_AOUT is not set +CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y +# CONFIG_HAVE_ARCH_HASH is not set +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +# CONFIG_HAVE_ARCH_VMAP_STACK is not set +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_HAVE_GCC_PLUGINS=y +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_CAT=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_STACKPROTECTOR=y +# CONFIG_HCALL_STATS is not set +# CONFIG_HDC100X is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDMI_LPE_AUDIO is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_HEADER_TEST is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFS_FS_POSIX_ACL is not set +# CONFIG_HI8435 is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_ASUS is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_BIGBEN_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GOOGLE_HAMMER is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTI is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_REDRAGON is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEAM is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_U2FZERO is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HINIC is not set +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC6352 is not set +# CONFIG_HNS is not set +# CONFIG_HNS3 is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HP03 is not set +# CONFIG_HP100 is not set +# CONFIG_HP206C is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSA_AMD is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTS221 is not set +# CONFIG_HTU21 is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWLAT_TRACER is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_CAVIUM is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_IPROC_RNG200 is not set +# CONFIG_HW_RANDOM_OMAP is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_TPM=y +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_HX711 is not set +# CONFIG_HYPERV is not set +# CONFIG_HYPERV_TSCPAGE is not set +# CONFIG_HYSDN is not set +# CONFIG_HZ is not set +# CONFIG_HZ_100 is not set +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_24 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_BCM_IPROC is not set +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_JZ4780 is not set +# CONFIG_I2C_MLXCPLD is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_S3C2410 is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SLAVE_EEPROM is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I3C is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IAQCORE is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICE is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IEEE802154_ADF7242 is not set +# CONFIG_IEEE802154_ATUSB is not set +# CONFIG_IEEE802154_CA8210 is not set +# CONFIG_IEEE802154_HWSIM is not set +# CONFIG_IEEE802154_MCR20A is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IGC is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_BUFFER_CB is not set +# CONFIG_IIO_BUFFER_HW_CONSUMER is not set +# CONFIG_IIO_CONFIGFS is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_MUX is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_RESCALE is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_LSM6DSX is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IIO_TRIGGER is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IKHEADERS is not set +# CONFIG_IMA is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMG_MDC_DMA is not set +# CONFIG_IMX7D_ADC is not set +# CONFIG_IMX_IPUV3_CORE is not set +# CONFIG_IMX_THERMAL is not set +# CONFIG_INA2XX_ADC is not set +# CONFIG_INDIRECT_PIO is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +# CONFIG_INGENIC_ADC is not set +# CONFIG_INGENIC_CGU_JZ4725B is not set +# CONFIG_INGENIC_CGU_JZ4740 is not set +# CONFIG_INGENIC_CGU_JZ4770 is not set +# CONFIG_INGENIC_CGU_JZ4780 is not set +# CONFIG_INGENIC_TCU_CLK is not set +# CONFIG_INGENIC_TCU_IRQ is not set +# CONFIG_INGENIC_TIMER is not set +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +CONFIG_INIT_STACK_NONE=y +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK_BH is not set +CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INPUT_AXP20X_PEK is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_GPIO_VIBRA is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_MATRIXKMAP is not set +# CONFIG_INPUT_MAX8997_HAPTIC is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_MSM_VIBRATOR is not set +# CONFIG_INPUT_PALMAS_PWRBUTTON is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_TPS65218_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_TWL6040_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEGRITY is not set +# CONFIG_INTEGRITY_AUDIT is not set +# CONFIG_INTEGRITY_SIGNATURE is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_CHT_INT33FE is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_INTEL_ISH_HID is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_TH is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IONIC is not set +# CONFIG_IOSCHED_BFQ is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IO_STRICT_DEVMEM=y +# CONFIG_IO_URING is not set +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_MASQUERADE is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMB_DEVICE_INTERFACE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_FOU is not set +# CONFIG_IPV6_FOU_TUNNEL is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_VS is not set +# CONFIG_IP_VS_MH is not set +CONFIG_IP_VS_MH_TAB_INDEX=10 +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_POLL is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISA_BUS is not set +# CONFIG_ISA_BUS_API is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISL29501 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KASAN is not set +CONFIG_KASAN_STACK=1 +# CONFIG_KCOV is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_CAT is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +# CONFIG_KEYBOARD_ADC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_APPLESPI is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_BCM is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_DLINK_DIR685 is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1050 is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_SNVS_PWRKEY is not set +# CONFIG_KEYBOARD_STMPE is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_TEGRA is not set +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +# CONFIG_KEYBOARD_TWL4030 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS is not set +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KS7010 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_GUEST is not set +# CONFIG_KVM_INTEL is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LAN743X is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_CLASS_DEVICE is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_OTM3225A is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LDISC_AUTOLOAD=y +# CONFIG_LDM_PARTITION is not set +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_NS2 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set +# CONFIG_LEDS_TLC591XX is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LED_TRIGGER_PHY is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LGUEST is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LIBNVDIMM is not set +# CONFIG_LIDAR_LITE_V2 is not set +# CONFIG_LIQUIDIO is not set +# CONFIG_LIQUIDIO_VF is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_LMP91000 is not set +# CONFIG_LNET is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_EVENT_COUNTS is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +# CONFIG_LSI_ET1011C_PHY is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +CONFIG_LSM_MMAP_MIN_ADDR=65536 +# CONFIG_LTC1660 is not set +# CONFIG_LTC2471 is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTC2497 is not set +# CONFIG_LTC2632 is not set +# CONFIG_LTE_GDM724X is not set +# CONFIG_LTPC is not set +# CONFIG_LTR501 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LV0104CS is not set +# CONFIG_LWTUNNEL is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4HC_COMPRESS is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M62332 is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_INGENIC is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON32 is not set +# CONFIG_MACH_LOONGSON64 is not set +# CONFIG_MACH_PIC32 is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACH_XILFPGA is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACSEC is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAGIC_SYSRQ_SERIAL is not set +# CONFIG_MAILBOX is not set +# CONFIG_MANAGER_SBS is not set +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX30102 is not set +# CONFIG_MAX31856 is not set +# CONFIG_MAX44000 is not set +# CONFIG_MAX44009 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5432 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MAX9611 is not set +# CONFIG_MAXIM_THERMOCOUPLE is not set +CONFIG_MAY_USE_DEVLINK=y +# CONFIG_MB1232 is not set +# CONFIG_MC3230 is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP3911 is not set +# CONFIG_MCP4018 is not set +# CONFIG_MCP41010 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_DEVICE is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_THUNDER is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_MEMBARRIER=y +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMORY_HOTPLUG is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MEN_A21_WDT is not set +# CONFIG_MESON_SM is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_AC100 is not set +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_EXYNOS_LPASS is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MAX77650 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_PM8XXX is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_KSZ is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK is not set +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_FP_SUPPORT is not set +# CONFIG_MIPS_GENERIC is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_MIPS_SEAD3 is not set +# CONFIG_MISC_ALCOR_PCI is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLX90632 is not set +# CONFIG_MLXFW is not set +# CONFIG_MLXSW_CORE is not set +# CONFIG_MLX_CPLD_PLATFORM is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC35240 is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CAVIUM_THUNDERX is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_CQHCI is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_JZ4740 is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_AM654 is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_CADENCE is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDHCI_IPROC is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_ASPEED is not set +# CONFIG_MMC_SDHCI_OF_AT91 is not set +# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_OMAP is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_S3C is not set +# CONFIG_MMC_SDHCI_XENON is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_STM32_SDMMC is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MODULES=y +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOST is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_FOCALTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MOXTET is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MPLS is not set +# CONFIG_MPU3050_I2C is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_MSCC_OCELOT_SWITCH is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_HYPERBUS is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MCHP23K256 is not set +# CONFIG_MTD_MT81xx_NOR is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_DENALI_DT is not set +# CONFIG_MTD_NAND_DENALI_PCI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_ECC_SW_BCH is not set +# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MTK is not set +# CONFIG_MTD_NAND_MTK_BMT is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_MXIC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +# CONFIG_MTD_PHYSMAP_GEMINI is not set +# CONFIG_MTD_PHYSMAP_GPIO_ADDR is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PHYSMAP_OF_GEMINI is not set +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set +# CONFIG_MTD_PHYSMAP_VERSATILE is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_RAW_NAND is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +# CONFIG_MTD_ROUTERBOOT_PARTS is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPINAND_MT29F is not set +# CONFIG_MTD_SPI_NAND is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=4096 +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_BCM_WFI_FW is not set +# CONFIG_MTD_SPLIT_BCM63XX_FW is not set +# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set +# CONFIG_MTD_SPLIT_ELF_FW is not set +# CONFIG_MTD_SPLIT_EVA_FW is not set +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_JIMAGE_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_MINOR_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SPLIT_WRGG_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +# CONFIG_MTD_VIRT_CONCAT is not set +# CONFIG_MTK_MMC is not set +CONFIG_MULTIUSER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVNETA_BM is not set +# CONFIG_MVSWITCH_PHY is not set +# CONFIG_MV_XOR_V2 is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVSIM is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_INGRESS is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLABEL is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_CT is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_MPLS is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SAMPLE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_LANTIQ_GSWIP is not set +# CONFIG_NET_DSA_LEGACY is not set +# CONFIG_NET_DSA_LOOP is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set +# CONFIG_NET_DSA_MT7530 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_QCA8K is not set +# CONFIG_NET_DSA_REALTEK_SMI is not set +# CONFIG_NET_DSA_SJA1105 is not set +# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set +# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set +# CONFIG_NET_DSA_TAG_8021Q is not set +# CONFIG_NET_DSA_TAG_BRCM is not set +# CONFIG_NET_DSA_TAG_BRCM_PREPEND is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_DSA_TAG_GSWIP is not set +# CONFIG_NET_DSA_TAG_KSZ is not set +# CONFIG_NET_DSA_TAG_LAN9303 is not set +# CONFIG_NET_DSA_TAG_MTK is not set +# CONFIG_NET_DSA_TAG_QCA is not set +# CONFIG_NET_DSA_TAG_RTL4_A is not set +# CONFIG_NET_DSA_TAG_SJA1105 is not set +# CONFIG_NET_DSA_TAG_TRAILER is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX_SPI is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CANID is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_IPT is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IFE is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_NCSI is not set +# CONFIG_NET_NSH is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_DEFAULT is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_ETF is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TC_SKB_EXT is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALACRITECH=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMAZON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_AQUANTIA=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_AURORA=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CADENCE=y +CONFIG_NET_VENDOR_CAVIUM=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_CORTINA=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_GOOGLE=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_HUAWEI=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MICROSEMI=y +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NETERION=y +CONFIG_NET_VENDOR_NETRONOME=y +CONFIG_NET_VENDOR_NI=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_PACKET_ENGINES=y +CONFIG_NET_VENDOR_PENSANDO=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_SOCIONEXT=y +CONFIG_NET_VENDOR_SOLARFLARE=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_SYNOPSYS=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_VRF is not set +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFP is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NFT_BRIDGE_META is not set +# CONFIG_NFT_BRIDGE_REJECT is not set +# CONFIG_NFT_CONNLIMIT is not set +# CONFIG_NFT_DUP_IPV4 is not set +# CONFIG_NFT_DUP_IPV6 is not set +# CONFIG_NFT_FIB_IPV4 is not set +# CONFIG_NFT_FIB_IPV6 is not set +# CONFIG_NFT_FIB_NETDEV is not set +# CONFIG_NFT_FLOW_OFFLOAD is not set +# CONFIG_NFT_OBJREF is not set +# CONFIG_NFT_OSF is not set +# CONFIG_NFT_RT is not set +# CONFIG_NFT_SET_BITMAP is not set +# CONFIG_NFT_SOCKET is not set +# CONFIG_NFT_SYNPROXY is not set +# CONFIG_NFT_TPROXY is not set +# CONFIG_NFT_TUNNEL is not set +# CONFIG_NFT_XFRM is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IPV4 is not set +# CONFIG_NF_CONNTRACK_IPV6 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SECMARK is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_NETLINK_HELPER is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_FLOW_TABLE is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_BRIDGE is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_LOG_NETDEV is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_MASQUERADE is not set +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_REJECT_IPV6 is not set +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TABLES is not set +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_IPV4=y +CONFIG_NF_TABLES_IPV6=y +CONFIG_NF_TABLES_NETDEV=y +# CONFIG_NF_TABLES_SET is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NI65 is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NIC7018_WDT is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +# CONFIG_NI_XGE_MANAGEMENT_ENET is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +CONFIG_NMI_LOG_BUF_SHIFT=13 +# CONFIG_NOA1305 is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NS83820 is not set +# CONFIG_NTB is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NULL_TTY is not set +# CONFIG_NUMA is not set +# CONFIG_NVM is not set +# CONFIG_NVMEM is not set +# CONFIG_NVMEM_BCM_OCOTP is not set +# CONFIG_NVMEM_IMX_OCOTP is not set +# CONFIG_NVMEM_REBOOT_MODE is not set +# CONFIG_NVMEM_SYSFS is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TARGET is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OCTEONTX2_AF is not set +# CONFIG_OF_OVERLAY is not set +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_UNITTEST is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_OPT3001 is not set +CONFIG_OPTIMIZE_INLINING=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_XINO_AUTO=y +# CONFIG_OWL_LOADER is not set +# CONFIG_P54_COMMON is not set +# CONFIG_PA12203001 is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PACKING is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PALMAS_GPADC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_PANEL is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IMX is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC104 is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_DMA is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_AL is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCIE_ARMADA_8K is not set +# CONFIG_PCIE_BW is not set +# CONFIG_PCIE_CADENCE_HOST is not set +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_DW_PLAT is not set +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIE_IPROC is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_ENDPOINT is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MESON is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PF_STUB is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_SW_SWITCHTEC is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCI_V3_SEMI is not set +# CONFIG_PCI_XGENE is not set +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_STATS is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_CADENCE_DP is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SIERRA is not set +# CONFIG_PHY_CPCAP_USB is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_OCELOT_SERDES is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PHY_QCOM_USB_HS is not set +# CONFIG_PHY_QCOM_USB_HSIC is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PHY_TUSB1210 is not set +# CONFIG_PHY_XGENE is not set +# CONFIG_PI433 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_AXP209 is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_INGENIC is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +# CONFIG_PINCTRL_OCELOT is not set +CONFIG_PINCTRL_SINGLE=y +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_SX150X is not set +CONFIG_PINMUX=y +# CONFIG_PKCS7_MESSAGE_PARSER is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +CONFIG_PLUGIN_HOSTCC="" +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMS7003 is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEBUG is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_POSIX_MQUEUE is not set +CONFIG_POSIX_TIMERS=y +# CONFIG_POWERCAP is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_BRCMKONA is not set +# CONFIG_POWER_RESET_BRCMSTB is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_PIIX4_POWEROFF is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_POWER_SUPPLY_HWMON is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_PREEMPTIRQ_EVENTS is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PRINTK=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_PRINTK_NMI=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +# CONFIG_PROC_STRIPPED is not set +CONFIG_PROC_SYSCTL=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_LIST is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set +# CONFIG_PSAMPLE is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSI is not set +CONFIG_PSTORE=y +# CONFIG_PSTORE_842_COMPRESS is not set +CONFIG_PSTORE_COMPRESS=y +CONFIG_PSTORE_COMPRESS_DEFAULT="deflate" +# CONFIG_PSTORE_CONSOLE is not set +CONFIG_PSTORE_DEFLATE_COMPRESS=y +CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT=y +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_PMSG is not set +CONFIG_PSTORE_RAM=y +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_KVM is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PUBLIC_KEY_ALGO_RSA is not set +# CONFIG_PVPANIC is not set +# CONFIG_PWM is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_PCA9685 is not set +CONFIG_PWRSEQ_EMMC=y +# CONFIG_PWRSEQ_SD8787 is not set +CONFIG_PWRSEQ_SIMPLE=y +# CONFIG_QCA7000 is not set +# CONFIG_QCA7000_SPI is not set +# CONFIG_QCA7000_UART is not set +# CONFIG_QCOM_EMAC is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_QCOM_HIDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_SPMI_ADC5 is not set +# CONFIG_QCOM_SPMI_IADC is not set +# CONFIG_QCOM_SPMI_TEMP_ALARM is not set +# CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QED is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QORIQ_CPUFREQ is not set +# CONFIG_QORIQ_THERMAL is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUEUED_LOCK_STAT is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID6_PQ_BENCHMARK is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RANDOMIZE_BASE is not set +# CONFIG_RANDOM_TRUST_BOOTLOADER is not set +# CONFIG_RANDOM_TRUST_CPU is not set +# CONFIG_RAPIDIO is not set +# CONFIG_RAS is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_RCU_BOOST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FANOUT=32 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FAST_NO_HZ is not set +CONFIG_RCU_KTHREAD_PRIO=0 +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_RCU_PERF_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 +# CONFIG_RCU_TRACE is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_READ_ONLY_THP_FOR_FS is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_REFCOUNT_FULL is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_88PG86X is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_LTC3676 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MCP16502 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PV88060 is not set +# CONFIG_REGULATOR_PV88080 is not set +# CONFIG_REGULATOR_PV88090 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_SLG51000 is not set +# CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_SY8824X is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VCTRL is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_REMOTEPROC is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_RESET_ATH79 is not set +# CONFIG_RESET_BERLIN is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RESET_IMX7 is not set +# CONFIG_RESET_LANTIQ is not set +# CONFIG_RESET_LPC18XX is not set +# CONFIG_RESET_MESON is not set +# CONFIG_RESET_PISTACHIO is not set +# CONFIG_RESET_SOCFPGA is not set +# CONFIG_RESET_STM32 is not set +# CONFIG_RESET_SUNXI is not set +# CONFIG_RESET_TEGRA_BPMP is not set +# CONFIG_RESET_TI_SYSCON is not set +# CONFIG_RESET_ZYNQ is not set +# CONFIG_RFD77402 is not set +# CONFIG_RFD_FTL is not set +CONFIG_RFKILL=y +# CONFIG_RFKILL_FULL is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_LEDS is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RMI4_CORE is not set +# CONFIG_RMNET is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# CONFIG_RPR0521 is not set +# CONFIG_RSEQ is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_CADENCE is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1307_HWMON is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_JZ4740 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R7301 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SD3078 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +# CONFIG_RTC_NVMEM is not set +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5208 is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RUNTIME_TESTING_MENU=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_RXKAD=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_INIC162X is not set +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +CONFIG_SBITMAP=y +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCACHE_DEBUGFS is not set +# CONFIG_SCC is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCR24X is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SD_ADC_MODULATOR is not set +# CONFIG_SECCOMP is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_APPARMOR is not set +CONFIG_SECURITY_DMESG_RESTRICT=y +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_SELINUX_AVC_STATS is not set +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0 +# CONFIG_SECURITY_SELINUX_DEVELOP is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_YAMA is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSIRION_SGP30 is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM1275 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IBM_CFFPS is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_INSPUR_IPSPS is not set +# CONFIG_SENSORS_IR35221 is not set +# CONFIG_SENSORS_IR38064 is not set +# CONFIG_SENSORS_IRPS5401 is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_ISL68137 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM25066 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2978 is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC3815 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LTQ_CPUTEMP is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16064 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX20751 is not set +# CONFIG_SENSORS_MAX31722 is not set +# CONFIG_SENSORS_MAX31785 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MAX34440 is not set +# CONFIG_SENSORS_MAX6621 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MAX8688 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_NSA320 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_OCC_P8_I2C is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_PMBUS is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_PWM_FAN is not set +# CONFIG_SENSORS_PXE1610 is not set +# CONFIG_SENSORS_RM3100_I2C is not set +# CONFIG_SENSORS_RM3100_SPI is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP108 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TPS40422 is not set +# CONFIG_SENSORS_TPS53679 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_UCD9000 is not set +# CONFIG_SENSORS_UCD9200 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83773G is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_XGENE is not set +# CONFIG_SENSORS_ZL6100 is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_ASPEED_VUART is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_INGENIC is not set +# CONFIG_SERIAL_8250_LPSS is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_8250_MOXA is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DEV_BUS is not set +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_STM32 is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_SUN4I_PS2 is not set +# CONFIG_SFC is not set +# CONFIG_SFC_FALCON is not set +# CONFIG_SFI is not set +# CONFIG_SFP is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SG_POOL is not set +# CONFIG_SG_SPLIT is not set +CONFIG_SHMEM=y +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI1133 is not set +# CONFIG_SI1145 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +CONFIG_SIGNALFD=y +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_SIOX is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SLAB_FREELIST_RANDOM is not set +CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIMBUS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SM_FTL is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AUDIO_GRAPH_CARD is not set +# CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EDMA_SOC is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_I2S_HI6210_I2S is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_JZ4740_SOC_I2S is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +CONFIG_SND_MAX_CARDS=16 +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +CONFIG_SND_PROC_FS=y +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIMPLE_SCU_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_AC97_CODEC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_ADAU1761_I2C is not set +# CONFIG_SND_SOC_ADAU1761_SPI is not set +# CONFIG_SND_SOC_ADAU7002 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4118 is not set +# CONFIG_SND_SOC_AK4458 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_AK5558 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AMD_ACP is not set +# CONFIG_SND_SOC_AMD_ACP3x is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_BD28623 is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +# CONFIG_SND_SOC_CS35L34 is not set +# CONFIG_SND_SOC_CS35L35 is not set +# CONFIG_SND_SOC_CS35L36 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L42 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_CS43130 is not set +# CONFIG_SND_SOC_CS4341 is not set +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_CX2072X is not set +# CONFIG_SND_SOC_DIO2125 is not set +# CONFIG_SND_SOC_DMIC is not set +# CONFIG_SND_SOC_ES7134 is not set +# CONFIG_SND_SOC_ES7241 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_ES8328_I2C is not set +# CONFIG_SND_SOC_ES8328_SPI is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_AUDMIX is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_MICFIL is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_ICS43432 is not set +# CONFIG_SND_SOC_IMG is not set +# CONFIG_SND_SOC_IMX_AUDMIX is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INNO_RK3036 is not set +# CONFIG_SND_SOC_INTEL_APL is not set +# CONFIG_SND_SOC_INTEL_BAYTRAIL is not set +# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_CFL is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set +# CONFIG_SND_SOC_INTEL_CML_H is not set +# CONFIG_SND_SOC_INTEL_CML_LP is not set +# CONFIG_SND_SOC_INTEL_CNL is not set +# CONFIG_SND_SOC_INTEL_GLK is not set +# CONFIG_SND_SOC_INTEL_HASWELL is not set +# CONFIG_SND_SOC_INTEL_KBL is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set +# CONFIG_SND_SOC_INTEL_SKYLAKE is not set +# CONFIG_SND_SOC_INTEL_SST is not set +CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y +# CONFIG_SND_SOC_JZ4725B_CODEC is not set +# CONFIG_SND_SOC_JZ4740_CODEC is not set +# CONFIG_SND_SOC_MA120X0P is not set +# CONFIG_SND_SOC_MAX9759 is not set +# CONFIG_SND_SOC_MAX98088 is not set +# CONFIG_SND_SOC_MAX98357A is not set +# CONFIG_SND_SOC_MAX98373 is not set +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MAX9867 is not set +# CONFIG_SND_SOC_MAX98927 is not set +# CONFIG_SND_SOC_MEDIATEK is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set +# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set +# CONFIG_SND_SOC_MT2701 is not set +# CONFIG_SND_SOC_MT6351 is not set +# CONFIG_SND_SOC_MT6358 is not set +# CONFIG_SND_SOC_MT8173 is not set +# CONFIG_SND_SOC_MTK_BTCVSD is not set +# CONFIG_SND_SOC_NAU8540 is not set +# CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_NAU8822 is not set +# CONFIG_SND_SOC_NAU8824 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1789_I2C is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM186X_I2C is not set +# CONFIG_SND_SOC_PCM186X_SPI is not set +# CONFIG_SND_SOC_PCM3060_I2C is not set +# CONFIG_SND_SOC_PCM3060_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_RK3328 is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SOF_TOPLEVEL is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2305 is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TAS6424 is not set +# CONFIG_SND_SOC_TDA7419 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set +# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_TSCS42XX is not set +# CONFIG_SND_SOC_TSCS454 is not set +# CONFIG_SND_SOC_UDA1334 is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8524 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8782 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8904 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set +# CONFIG_SND_SOC_XILINX_I2S is not set +# CONFIG_SND_SOC_XILINX_SPDIF is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SOC_ZX_AUD96P22 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI is not set +# CONFIG_SND_SUN4I_CODEC is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_X86=y +# CONFIG_SND_XEN_FRONTEND is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_SOCK_CGROUP_DATA is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_BRCMSTB is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFTLOCKUP_DETECTOR is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUNDWIRE is not set +# CONFIG_SOUND_OSS_CORE is not set +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BCM_QSPI is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MEM is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_MTK_QUADSPI is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_QCOM_QSPI is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_S3C64XX is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_SPMI is not set +# CONFIG_SPS30 is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +CONFIG_SQUASHFS_EMBEDDED=y +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_ZSTD is not set +# CONFIG_SRAM is not set +# CONFIG_SRF04 is not set +# CONFIG_SRF08 is not set +# CONFIG_SSB is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_HOST_SOC is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +# CONFIG_STACKPROTECTOR is not set +# CONFIG_STACKPROTECTOR_STRONG is not set +# CONFIG_STACKTRACE is not set +CONFIG_STACKTRACE_SUPPORT=y +# CONFIG_STACK_TRACER is not set +# CONFIG_STACK_VALIDATION is not set +CONFIG_STAGING=y +# CONFIG_STAGING_BOARD is not set +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STK3310 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set +# CONFIG_STM is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STM_DUMMY is not set +# CONFIG_STM_SOURCE_CONSOLE is not set +CONFIG_STP=y +# CONFIG_STREAM_PARSER is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_STRICT_MODULE_RWX=y +# CONFIG_STRING_SELFTEST is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STX104 is not set +# CONFIG_ST_UVIS25 is not set +# CONFIG_SUN4I_GPADC is not set +# CONFIG_SUN50I_DE2_BUS is not set +# CONFIG_SUN50I_ERRATUM_UNKNOWN1 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUNXI_SRAM is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SURFACE_3_BUTTON is not set +# CONFIG_SUSPEND is not set +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_B53 is not set +# CONFIG_SWCONFIG_B53_MDIO_DRIVER is not set +# CONFIG_SWCONFIG_B53_MMAP_DRIVER is not set +# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set +# CONFIG_SWCONFIG_B53_SRAB_DRIVER is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SW_SYNC is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +# CONFIG_SYNCLINK_CS is not set +# CONFIG_SYNC_FILE is not set +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set +CONFIG_SYN_COOKIES=y +# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# CONFIG_SYSTEM_DATA_VERIFICATION is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TASK_XACCT is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_ATMEL is not set +# CONFIG_TCG_CRB is not set +# CONFIG_TCG_FTPM_TEE is not set +# CONFIG_TCG_INFINEON is not set +# CONFIG_TCG_NSC is not set +# CONFIG_TCG_ST33_I2C is not set +# CONFIG_TCG_TIS is not set +# CONFIG_TCG_TIS_I2C_ATMEL is not set +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_TCG_TIS_I2C_NUVOTON is not set +# CONFIG_TCG_TIS_SPI is not set +# CONFIG_TCG_TIS_ST33ZP24_I2C is not set +# CONFIG_TCG_TIS_ST33ZP24_SPI is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCG_VTPM_PROXY is not set +# CONFIG_TCG_XEN is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BBR is not set +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CDG is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEE is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +# CONFIG_TEST_BITFIELD is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_SORT is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_XARRAY is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THERMAL_MMIO is not set +# CONFIG_THERMAL_STATISTICS is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +# CONFIG_THINKPAD_ACPI is not set +CONFIG_THIN_ARCHIVES=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUMB2_KERNEL is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_THUNDER_NIC_VF is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMER_STATS is not set +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_MI0283QT is not set +# CONFIG_TINYDRM_REPAPER is not set +# CONFIG_TINYDRM_ST7586 is not set +# CONFIG_TINYDRM_ST7735R is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC084S021 is not set +# CONFIG_TI_ADC108S102 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS124S08 is not set +# CONFIG_TI_ADS7950 is not set +# CONFIG_TI_ADS8344 is not set +# CONFIG_TI_ADS8688 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPSW_PHY_SEL is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC082S085 is not set +# CONFIG_TI_DAC5571 is not set +# CONFIG_TI_DAC7311 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAC7612 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TI_SYSCON_RESET is not set +# CONFIG_TI_TLC4541 is not set +# CONFIG_TLAN is not set +# CONFIG_TLS is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +# CONFIG_TMP007 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_88PM860X is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADC is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_BU21029 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set +# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_SPI is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP_SPI is not set +# CONFIG_TOUCHSCREEN_DA9034 is not set +# CONFIG_TOUCHSCREEN_DA9052 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set +# CONFIG_TOUCHSCREEN_EKTF2127 is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_EXC3000 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_HIDEEP is not set +# CONFIG_TOUCHSCREEN_HP600 is not set +# CONFIG_TOUCHSCREEN_HP7XX is not set +# CONFIG_TOUCHSCREEN_HTCPEN is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set +# CONFIG_TOUCHSCREEN_IPROC is not set +# CONFIG_TOUCHSCREEN_IQS5XX is not set +# CONFIG_TOUCHSCREEN_LPC32XX is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MC13783 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set +# CONFIG_TOUCHSCREEN_MIGOR is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MX25 is not set +# CONFIG_TOUCHSCREEN_MXS_LRADC is not set +# CONFIG_TOUCHSCREEN_PCAP is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_PROPERTIES is not set +# CONFIG_TOUCHSCREEN_RASPBERRYPI_FW is not set +# CONFIG_TOUCHSCREEN_RM_TS is not set +# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_S6SY761 is not set +# CONFIG_TOUCHSCREEN_SILEAD is not set +# CONFIG_TOUCHSCREEN_SIS_I2C is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_STMFTS is not set +# CONFIG_TOUCHSCREEN_STMPE is not set +# CONFIG_TOUCHSCREEN_SUN4I is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TS4800 is not set +# CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set +# CONFIG_TOUCHSCREEN_TSC200X_CORE is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_3M is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set +# CONFIG_TOUCHSCREEN_USB_E2I is not set +# CONFIG_TOUCHSCREEN_USB_EASYTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_EGALAX is not set +# CONFIG_TOUCHSCREEN_USB_ELO is not set +# CONFIG_TOUCHSCREEN_USB_ETT_TC45USB is not set +# CONFIG_TOUCHSCREEN_USB_ETURBO is not set +# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set +# CONFIG_TOUCHSCREEN_USB_GOTOP is not set +# CONFIG_TOUCHSCREEN_USB_GUNZE is not set +# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set +# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_ITM is not set +# CONFIG_TOUCHSCREEN_USB_JASTEC is not set +# CONFIG_TOUCHSCREEN_USB_NEXIO is not set +# CONFIG_TOUCHSCREEN_USB_PANJIT is not set +# CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set +# CONFIG_TOUCHSCREEN_WM831X is not set +# CONFIG_TOUCHSCREEN_WM9705 is not set +# CONFIG_TOUCHSCREEN_WM9712 is not set +# CONFIG_TOUCHSCREEN_WM9713 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set +# CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE is not set +# CONFIG_TOUCHSCREEN_ZET6223 is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TPL0102 is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +# CONFIG_TRACING_EVENTS_GPIO is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +# CONFIG_TRUSTED_FOUNDATIONS is not set +# CONFIG_TRUSTED_KEYS is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2772 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set +# CONFIG_TTPCI_EEPROM is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL4030_MADC is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPEC is not set +# CONFIG_TYPEC_TCPM is not set +# CONFIG_TYPEC_UCSI is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UBIFS_ATIME_SUPPORT is not set +# CONFIG_UBIFS_FS_AUTHENTICATION is not set +# CONFIG_UBIFS_FS_ENCRYPTION is not set +# CONFIG_UBIFS_FS_SECURITY is not set +# CONFIG_UBIFS_FS_ZLIB is not set +# CONFIG_UBIFS_FS_ZSTD is not set +CONFIG_UBIFS_FS_XATTR=y +# CONFIG_UBSAN is not set +CONFIG_UBSAN_ALIGNMENT=y +# CONFIG_UCB1400_CORE is not set +# CONFIG_UCSI is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDMABUF is not set +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UID16=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_UNICODE is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_UNISYS_VISORBUS is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +CONFIG_UNIX_SCM=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UNWINDER_FRAME_POINTER is not set +# CONFIG_UPROBES is not set +# CONFIG_UPROBE_EVENTS is not set +# CONFIG_US5182D is not set +# CONFIG_USB is not set +# CONFIG_USBIP_CORE is not set +CONFIG_USBIP_VHCI_HC_PORTS=8 +CONFIG_USBIP_VHCI_NR_HCS=1 +# CONFIG_USBIP_VUDC is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_CHAOSKEY is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CONN_GPIO is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_HAPS is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC3_OF_SIMPLE is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DWC3_ULPI is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_ATH79 is not set +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_OMAP is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IMX21_HCD is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MTU3 is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MXS_PHY is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PCI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SNP_UDC_PLAT is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_DBGCAP is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XHCI_MVEBU is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USERFAULTFD is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_U_SERIAL_CONSOLE is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VALIDATE_FS_PARSER is not set +# CONFIG_VBOXGUEST is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VCNL4035 is not set +CONFIG_VDSO=y +# CONFIG_VEML6070 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VF610_DAC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VFIO is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_VSOCK is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_ASPEED is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_CADENCE is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CS3308 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_I2C is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9M111 is not set +# CONFIG_VIDEO_MT9T112 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V111 is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OV2640 is not set +# CONFIG_VIDEO_OV2659 is not set +# CONFIG_VIDEO_OV5695 is not set +# CONFIG_VIDEO_OV6650 is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_OV772X is not set +# CONFIG_VIDEO_OV7740 is not set +# CONFIG_VIDEO_OV9640 is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_RJ54N1 is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_TW9910 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_BLK_SCSI is not set +# CONFIG_VIRTIO_FS is not set +# CONFIG_VIRTIO_INPUT is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +# CONFIG_VL53L0X_I2C is not set +# CONFIG_VL6180 is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VOP_BUS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VSOCKETS_DIAG is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_VZ89X is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_MASTER_SGI is not set +# CONFIG_W1_SLAVE_DS2405 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2438 is not set +# CONFIG_W1_SLAVE_DS250X is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS2805 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_DS28E17 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set +# CONFIG_WATCHDOG_SYSFS is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_WDTPCI is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIREGUARD is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +# CONFIG_WIRELESS_WDS is not set +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +CONFIG_WLAN=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLCORE is not set +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_X25 is not set +# CONFIG_X509_CERTIFICATE_PARSER is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XDP_SOCKETS is not set +# CONFIG_XEN is not set +# CONFIG_XEN_GRANT_DMA_ALLOC is not set +# CONFIG_XEN_PVCALLS_FRONTEND is not set +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y +CONFIG_XFRM=y +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_ONLINE_SCRUB is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_XILINX_VCU is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILINX_XADC is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAM is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +CONFIG_ZONE_DMA=y +# CONFIG_ZOPT2201 is not set +# CONFIG_ZPA2326 is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZRAM is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_ZX_TDM is not set diff --git a/ipq806x/files-5.4/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml b/ipq806x/files-5.4/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml new file mode 100644 index 0000000..d052ab1 --- /dev/null +++ b/ipq806x/files-5.4/Documentation/devicetree/bindings/mtd/partitions/openwrt,uimage.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/openwrt,uimage.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OpenWrt variations of U-Boot Image partitions + +maintainers: + - Bjørn Mork + +description: | + The image format defined by the boot loader "Das U-Boot" is often + modified or extended by device vendors. This defines a few optional + properties which can be used to describe such modifications. + +# partition.txt defines common properties, but has not yet been +# converted to YAML +#allOf: +# - $ref: ../partition.yaml# + +properties: + compatible: + items: + - enum: + - openwrt,uimage + - const: denx,uimage + + openwrt,padding: + description: Number of padding bytes between header and data + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + + openwrt,ih-magic: + description: U-Boot Image Header magic number. + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0x27051956 # IH_MAGIC + + openwrt,ih-type: + description: U-Boot Image type + $ref: /schemas/types.yaml#/definitions/uint32 + default: 2 # IH_TYPE_KERNEL + + openwrt,offset: + description: + Offset between partition start and U-Boot Image in bytes + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + + openwrt,partition-magic: + description: + Magic number found at the start of the partition. Will only be + validated if both this property and openwrt,offset is non-zero + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + +required: + - compatible + - reg + +#unevaluatedProperties: false +additionalProperties: false + +examples: + - | + // device with non-default magic + partition@300000 { + compatible = "openwrt,uimage", "denx,uimage"; + reg = <0x00300000 0xe80000>; + label = "firmware"; + openwrt,ih-magic = <0x4e474520>; + }; + - | + // device with U-Boot Image at an offset, with a partition magic value + partition@70000 { + compatible = "openwrt,uimage", "denx,uimage"; + reg = <0x00070000 0x00790000>; + label = "firmware"; + openwrt,offset = <20>; + openwrt,partition-magic = <0x43535953>; + }; + - | + // device using a non-default image type + #include "dt-bindings/mtd/partitions/uimage.h" + partition@6c0000 { + compatible = "openwrt,uimage", "denx,uimage"; + reg = <0x6c0000 0x1900000>; + label = "firmware"; + openwrt,ih-magic = <0x33373033>; + openwrt,ih-type = ; + }; diff --git a/ipq806x/files-5.4/Documentation/networking/adm6996.txt b/ipq806x/files-5.4/Documentation/networking/adm6996.txt new file mode 100644 index 0000000..ab59f1d --- /dev/null +++ b/ipq806x/files-5.4/Documentation/networking/adm6996.txt @@ -0,0 +1,110 @@ +------- + +ADM6996FC / ADM6996M switch chip driver + + +1. General information + + This driver supports the FC and M models only. The ADM6996F and L are + completely different chips. + + Support for the FC model is extremely limited at the moment. There is no VLAN + support as of yet. The driver will not offer an swconfig interface for the FC + chip. + +1.1 VLAN IDs + + It is possible to define 16 different VLANs. Every VLAN has an identifier, its + VLAN ID. It is easiest if you use at most VLAN IDs 0-15. In that case, the + swconfig based configuration is very straightforward. To define two VLANs with + IDs 4 and 5, you can invoke, for example: + + # swconfig dev ethX vlan 4 set ports '0 1t 2 5t' + # swconfig dev ethX vlan 5 set ports '0t 1t 5t' + + The swconfig framework will automatically invoke 'port Y set pvid Z' for every + port that is an untagged member of VLAN Y, setting its Primary VLAN ID. In + this example, ports 0 and 2 would get "pvid 4". The Primary VLAN ID of a port + is the VLAN ID associated with untagged packets coming in on that port. + + But if you wish to use VLAN IDs outside the range 0-15, this automatic + behaviour of the swconfig framework becomes a problem. The 16 VLANs that + swconfig can configure on the ADM6996 also have a "vid" setting. By default, + this is the same as the number of the VLAN entry, to make the simple behaviour + above possible. To still support a VLAN with a VLAN ID higher than 15 + (presumably because you are in a network where such VLAN IDs are already in + use), you can change the "vid" setting of the VLAN to anything in the range + 0-1023. But suppose you did the following: + + # swconfig dev ethX vlan 0 set vid 998 + # swconfig dev ethX vlan 0 set ports '0 2 5t' + + Now the swconfig framework will issue 'port 0 set pvid 0' and 'port 2 set pvid + 0'. But the "pvid" should be set to 998, so you are responsible for manually + fixing this! + +1.2 VLAN filtering + + The switch is configured to apply source port filtering. This means that + packets are only accepted when the port the packets came in on is a member of + the VLAN the packet should go to. + + Only membership of a VLAN is tested, it does not matter whether it is a tagged + or untagged membership. + + For untagged packets, the destination VLAN is the Primary VLAN ID of the + incoming port. So if the PVID of a port is 0, but that port is not a member of + the VLAN with ID 0, this means that untagged packets on that port are dropped. + This can be used as a roundabout way of dropping untagged packets from a port, + a mode often referred to as "Admit only tagged packets". + +1.3 Reset + + The two supported chip models do not have a sofware-initiated reset. When the + driver is initialised, as well as when the 'reset' swconfig option is invoked, + the driver will set those registers it knows about and supports to the correct + default value. But there are a lot of registers in the chip that the driver + does not support. If something changed those registers, invoking 'reset' or + performing a warm reboot might still leave the chip in a "broken" state. Only + a hardware reset will bring it back in the default state. + +2. Technical details on PHYs and the ADM6996 + + From the viewpoint of the Linux kernel, it is common that an Ethernet adapter + can be seen as a separate MAC entity and a separate PHY entity. The PHY entity + can be queried and set through registers accessible via an MDIO bus. A PHY + normally has a single address on that bus, in the range 0 through 31. + + The ADM6996 has special-purpose registers in the range of PHYs 0 through 10. + Even though all these registers control a single ADM6996 chip, the Linux + kernel treats this as 11 separate PHYs. The driver will bind to these + addresses to prevent a different PHY driver from binding and corrupting these + registers. + + What Linux sees as the PHY on address 0 is meant for the Ethernet MAC + connected to the CPU port of the ADM6996 switch chip (port 5). This is the + Ethernet MAC you will use to send and receive data through the switch. + + The PHYs at addresses 16 through 20 map to the PHYs on ports 0 through 4 of + the switch chip. These can be accessed with the Generic PHY driver, as the + registers have the common layout. + + If a second Ethernet MAC on your board is wired to the port 4 PHY, that MAC + needs to bind to PHY address 20 for the port to work correctly. + + The ADM6996 switch driver will reset the ports 0 through 3 on startup and when + 'reset' is invoked. This could clash with a different PHY driver if the kernel + binds a PHY driver to address 16 through 19. + + If Linux binds a PHY on addresses 1 through 10 to an Ethernet MAC, the ADM6996 + driver will simply always report a connected 100 Mbit/s full-duplex link for + that PHY, and provide no other functionality. This is most likely not what you + want. So if you see a message in your log + + ethX: PHY overlaps ADM6996, providing fixed PHY yy. + + This is most likely an indication that ethX will not work properly, and your + kernel needs to be configured to attach a different PHY to that Ethernet MAC. + + Controlling the mapping between MACs and PHYs is usually done in platform- or + board-specific fixup code. The ADM6996 driver has no influence over this. diff --git a/ipq806x/files-5.4/arch/mips/fw/myloader/Makefile b/ipq806x/files-5.4/arch/mips/fw/myloader/Makefile new file mode 100644 index 0000000..34acfd0 --- /dev/null +++ b/ipq806x/files-5.4/arch/mips/fw/myloader/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Compex's MyLoader support on MIPS architecture +# + +lib-y += myloader.o diff --git a/ipq806x/files-5.4/arch/mips/fw/myloader/myloader.c b/ipq806x/files-5.4/arch/mips/fw/myloader/myloader.c new file mode 100644 index 0000000..a26f9ad --- /dev/null +++ b/ipq806x/files-5.4/arch/mips/fw/myloader/myloader.c @@ -0,0 +1,63 @@ +/* + * Compex's MyLoader specific prom routines + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include + +#include +#include + +#define SYS_PARAMS_ADDR KSEG1ADDR(0x80000800) +#define BOARD_PARAMS_ADDR KSEG1ADDR(0x80000A00) +#define PART_TABLE_ADDR KSEG1ADDR(0x80000C00) +#define BOOT_PARAMS_ADDR KSEG1ADDR(0x80000E00) + +static struct myloader_info myloader_info __initdata; +static int myloader_found __initdata; + +struct myloader_info * __init myloader_get_info(void) +{ + struct mylo_system_params *sysp; + struct mylo_board_params *boardp; + struct mylo_partition_table *parts; + + if (myloader_found) + return &myloader_info; + + sysp = (struct mylo_system_params *)(SYS_PARAMS_ADDR); + boardp = (struct mylo_board_params *)(BOARD_PARAMS_ADDR); + parts = (struct mylo_partition_table *)(PART_TABLE_ADDR); + + printk(KERN_DEBUG "MyLoader: sysp=%08x, boardp=%08x, parts=%08x\n", + sysp->magic, boardp->magic, parts->magic); + + /* Check for some magic numbers */ + if (sysp->magic != MYLO_MAGIC_SYS_PARAMS || + boardp->magic != MYLO_MAGIC_BOARD_PARAMS || + le32_to_cpu(parts->magic) != MYLO_MAGIC_PARTITIONS) + return NULL; + + printk(KERN_DEBUG "MyLoader: id=%04x:%04x, sub_id=%04x:%04x\n", + sysp->vid, sysp->did, sysp->svid, sysp->sdid); + + myloader_info.vid = sysp->vid; + myloader_info.did = sysp->did; + myloader_info.svid = sysp->svid; + myloader_info.sdid = sysp->sdid; + + memcpy(myloader_info.macs, boardp->addr, sizeof(myloader_info.macs)); + + myloader_found = 1; + + return &myloader_info; +} diff --git a/ipq806x/files-5.4/block/partitions/fit.c b/ipq806x/files-5.4/block/partitions/fit.c new file mode 100644 index 0000000..c0d9642 --- /dev/null +++ b/ipq806x/files-5.4/block/partitions/fit.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * fs/partitions/fit.c + * Copyright (C) 2021 Daniel Golle + * + * headers extracted from U-Boot mkimage sources + * (C) Copyright 2008 Semihalf + * (C) Copyright 2000-2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * based on existing partition parsers + * Copyright (C) 1991-1998 Linus Torvalds + * Re-organised Feb 1998 Russell King + */ + +#define pr_fmt(fmt) fmt + +#include +#include +#include +#include +#include + +#include "check.h" + +#define FIT_IMAGES_PATH "/images" +#define FIT_CONFS_PATH "/configurations" + +/* hash/signature/key node */ +#define FIT_HASH_NODENAME "hash" +#define FIT_ALGO_PROP "algo" +#define FIT_VALUE_PROP "value" +#define FIT_IGNORE_PROP "uboot-ignore" +#define FIT_SIG_NODENAME "signature" +#define FIT_KEY_REQUIRED "required" +#define FIT_KEY_HINT "key-name-hint" + +/* cipher node */ +#define FIT_CIPHER_NODENAME "cipher" +#define FIT_ALGO_PROP "algo" + +/* image node */ +#define FIT_DATA_PROP "data" +#define FIT_DATA_POSITION_PROP "data-position" +#define FIT_DATA_OFFSET_PROP "data-offset" +#define FIT_DATA_SIZE_PROP "data-size" +#define FIT_TIMESTAMP_PROP "timestamp" +#define FIT_DESC_PROP "description" +#define FIT_ARCH_PROP "arch" +#define FIT_TYPE_PROP "type" +#define FIT_OS_PROP "os" +#define FIT_COMP_PROP "compression" +#define FIT_ENTRY_PROP "entry" +#define FIT_LOAD_PROP "load" + +/* configuration node */ +#define FIT_KERNEL_PROP "kernel" +#define FIT_FILESYSTEM_PROP "filesystem" +#define FIT_RAMDISK_PROP "ramdisk" +#define FIT_FDT_PROP "fdt" +#define FIT_LOADABLE_PROP "loadables" +#define FIT_DEFAULT_PROP "default" +#define FIT_SETUP_PROP "setup" +#define FIT_FPGA_PROP "fpga" +#define FIT_FIRMWARE_PROP "firmware" +#define FIT_STANDALONE_PROP "standalone" + +#define FIT_MAX_HASH_LEN HASH_MAX_DIGEST_SIZE + +#define MIN_FREE_SECT 16 +#define REMAIN_VOLNAME "rootfs_data" + +int parse_fit_partitions(struct parsed_partitions *state, u64 fit_start_sector, u64 sectors, int *slot, int add_remain) +{ + struct address_space *mapping = state->bdev->bd_inode->i_mapping; + struct page *page; + void *fit, *init_fit; + struct partition_meta_info *info; + char tmp[sizeof(info->volname)]; + u64 dsize, dsectors, imgmaxsect = 0; + u32 size, image_pos, image_len; + const u32 *image_offset_be, *image_len_be, *image_pos_be; + int ret = 1, node, images, config; + const char *image_name, *image_type, *image_description, *config_default, + *config_description, *config_loadables; + int image_name_len, image_type_len, image_description_len, config_default_len, + config_description_len, config_loadables_len; + sector_t start_sect, nr_sects; + size_t label_min; + + if (fit_start_sector % (1<<(PAGE_SHIFT - SECTOR_SHIFT))) + return -ERANGE; + + page = read_mapping_page(mapping, fit_start_sector >> (PAGE_SHIFT - SECTOR_SHIFT), NULL); + if (!page) + return -ENOMEM; + + init_fit = page_address(page); + + if (!init_fit) { + put_page(page); + return -EFAULT; + } + + if (fdt_check_header(init_fit)) { + put_page(page); + return 0; + } + + dsectors = get_capacity(state->bdev->bd_disk); + if (sectors) + dsectors = (dsectors>sectors)?sectors:dsectors; + + dsize = dsectors << SECTOR_SHIFT; + printk(KERN_DEBUG "FIT: volume size: %llu sectors (%llu bytes)\n", dsectors, dsize); + + size = fdt_totalsize(init_fit); + printk(KERN_DEBUG "FIT: FDT structure size: %u bytes\n", size); + if (size > PAGE_SIZE) { + printk(KERN_ERR "FIT: FDT structure beyond page boundaries, use 'mkimage -E ...'!\n"); + put_page(page); + return -ENOTSUPP; + } + + if (size >= dsize) { + put_page(page); + state->access_beyond_eod = (size >= dsize); + return 0; + } + + fit = kmemdup(init_fit, size, GFP_KERNEL); + put_page(page); + if (!fit) + return -ENOMEM; + + config = fdt_path_offset(fit, FIT_CONFS_PATH); + if (config < 0) { + printk(KERN_ERR "FIT: Cannot find %s node: %d\n", FIT_CONFS_PATH, images); + ret = -ENOENT; + goto ret_out; + } + + config_default = fdt_getprop(fit, config, FIT_DEFAULT_PROP, &config_default_len); + + if (!config_default) { + printk(KERN_ERR "FIT: Cannot find default configuration\n"); + ret = -ENOENT; + goto ret_out; + } + + node = fdt_subnode_offset(fit, config, config_default); + if (node < 0) { + printk(KERN_ERR "FIT: Cannot find %s node: %d\n", config_default, node); + ret = -ENOENT; + goto ret_out; + } + + config_description = fdt_getprop(fit, node, FIT_DESC_PROP, &config_description_len); + config_loadables = fdt_getprop(fit, node, FIT_LOADABLE_PROP, &config_loadables_len); + + printk(KERN_DEBUG "FIT: Default configuration: %s%s%s%s\n", config_default, + config_description?" (":"", config_description?:"", config_description?")":""); + + images = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images < 0) { + printk(KERN_ERR "FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH, images); + ret = -EINVAL; + goto ret_out; + } + + fdt_for_each_subnode(node, fit, images) { + image_name = fdt_get_name(fit, node, &image_name_len); + image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len); + image_offset_be = fdt_getprop(fit, node, FIT_DATA_OFFSET_PROP, NULL); + image_pos_be = fdt_getprop(fit, node, FIT_DATA_POSITION_PROP, NULL); + image_len_be = fdt_getprop(fit, node, FIT_DATA_SIZE_PROP, NULL); + if (!image_name || !image_type || !image_len_be) + continue; + + image_len = be32_to_cpu(*image_len_be); + if (!image_len) + continue; + + if (image_offset_be) + image_pos = be32_to_cpu(*image_offset_be) + size; + else if (image_pos_be) + image_pos = be32_to_cpu(*image_pos_be); + else + continue; + + image_description = fdt_getprop(fit, node, FIT_DESC_PROP, &image_description_len); + + printk(KERN_DEBUG "FIT: %16s sub-image 0x%08x - 0x%08x '%s' %s%s%s\n", + image_type, image_pos, image_pos + image_len, image_name, + image_description?"(":"", image_description?:"", image_description?") ":""); + + if (strcmp(image_type, FIT_FILESYSTEM_PROP)) + continue; + + if (image_pos & ((1 << PAGE_SHIFT)-1)) { + printk(KERN_ERR "FIT: image %s start not aligned to page boundaries, skipping\n", image_name); + continue; + } + + if (image_len & ((1 << PAGE_SHIFT)-1)) { + printk(KERN_ERR "FIT: sub-image %s end not aligned to page boundaries, skipping\n", image_name); + continue; + } + + start_sect = image_pos >> SECTOR_SHIFT; + nr_sects = image_len >> SECTOR_SHIFT; + imgmaxsect = (imgmaxsect < (start_sect + nr_sects))?(start_sect + nr_sects):imgmaxsect; + + if (start_sect + nr_sects > dsectors) { + state->access_beyond_eod = 1; + continue; + } + + put_partition(state, ++(*slot), fit_start_sector + start_sect, nr_sects); + state->parts[*slot].flags = 0; + info = &state->parts[*slot].info; + + label_min = min_t(int, sizeof(info->volname) - 1, image_name_len); + strncpy(info->volname, image_name, label_min); + info->volname[label_min] = '\0'; + + snprintf(tmp, sizeof(tmp), "(%s)", info->volname); + strlcat(state->pp_buf, tmp, PAGE_SIZE); + + state->parts[*slot].has_info = true; + + if (config_loadables && !strcmp(image_name, config_loadables)) { + printk(KERN_DEBUG "FIT: selecting configured loadable %s to be root filesystem\n", image_name); + state->parts[*slot].flags |= ADDPART_FLAG_ROOTDEV; + } + } + + if (add_remain && (imgmaxsect + MIN_FREE_SECT) < dsectors) { + put_partition(state, ++(*slot), fit_start_sector + imgmaxsect, dsectors - imgmaxsect); + state->parts[*slot].flags = 0; + info = &state->parts[*slot].info; + strcpy(info->volname, REMAIN_VOLNAME); + snprintf(tmp, sizeof(tmp), "(%s)", REMAIN_VOLNAME); + strlcat(state->pp_buf, tmp, PAGE_SIZE); + } +ret_out: + kfree(fit); + return ret; +} + +int fit_partition(struct parsed_partitions *state) { + int slot = 0; + return parse_fit_partitions(state, 0, 0, &slot, 0); +} diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/Kconfig b/ipq806x/files-5.4/drivers/mtd/mtdsplit/Kconfig new file mode 100644 index 0000000..794a39f --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/Kconfig @@ -0,0 +1,103 @@ +config MTD_SPLIT + def_bool n + help + Generic MTD split support. + +config MTD_SPLIT_SUPPORT + def_bool MTD = y + +comment "Rootfs partition parsers" + +config MTD_SPLIT_SQUASHFS_ROOT + bool "Squashfs based root partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + default n + help + This provides a parsing function which allows to detect the + offset and size of the unused portion of a rootfs partition + containing a squashfs. + +comment "Firmware partition parsers" + +config MTD_SPLIT_BCM63XX_FW + bool "BCM63xx firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_BCM_WFI_FW + bool "Broadcom Whole Flash Image parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_CFE_BOOTFS + bool "Parser finding rootfs appended to the CFE bootfs" + depends on MTD_SPLIT_SUPPORT && ARCH_BCM4908 + select MTD_SPLIT + help + cferom on BCM4908 (and bcm63xx) uses JFFS2 bootfs partition + for storing kernel, cferam and some device specific files. + There isn't any straight way of storing rootfs so it gets + appended to the JFFS2 bootfs partition. Kernel needs to find + it and run init from it. This parser is responsible for + finding appended rootfs. + +config MTD_SPLIT_SEAMA_FW + bool "Seama firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_WRGG_FW + bool "WRGG firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_UIMAGE_FW + bool "uImage based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_FIT_FW + bool "FIT based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_LZMA_FW + bool "LZMA compressed kernel based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_TPLINK_FW + bool "TP-Link firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_TRX_FW + bool "TRX image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_BRNIMAGE_FW + bool "brnImage (brnboot image) firmware parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_EVA_FW + bool "EVA image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_MINOR_FW + bool "Mikrotik NOR image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_JIMAGE_FW + bool "JBOOT Image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT + +config MTD_SPLIT_ELF_FW + bool "ELF loader firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/Makefile b/ipq806x/files-5.4/drivers/mtd/mtdsplit/Makefile new file mode 100644 index 0000000..1461099 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/Makefile @@ -0,0 +1,17 @@ +obj-$(CONFIG_MTD_SPLIT) += mtdsplit.o +obj-$(CONFIG_MTD_SPLIT_BCM63XX_FW) += mtdsplit_bcm63xx.o +obj-$(CONFIG_MTD_SPLIT_BCM_WFI_FW) += mtdsplit_bcm_wfi.o +obj-$(CONFIG_MTD_SPLIT_CFE_BOOTFS) += mtdsplit_cfe_bootfs.o +obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o +obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o +obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o +obj-$(CONFIG_MTD_SPLIT_FIT_FW) += mtdsplit_fit.o +obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o +obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o +obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o +obj-$(CONFIG_MTD_SPLIT_BRNIMAGE_FW) += mtdsplit_brnimage.o +obj-$(CONFIG_MTD_SPLIT_EVA_FW) += mtdsplit_eva.o +obj-$(CONFIG_MTD_SPLIT_WRGG_FW) += mtdsplit_wrgg.o +obj-$(CONFIG_MTD_SPLIT_MINOR_FW) += mtdsplit_minor.o +obj-$(CONFIG_MTD_SPLIT_JIMAGE_FW) += mtdsplit_jimage.o +obj-$(CONFIG_MTD_SPLIT_ELF_FW) += mtdsplit_elf.o diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.c new file mode 100644 index 0000000..b2e51dc --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * 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) "mtdsplit: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define UBI_EC_MAGIC 0x55424923 /* UBI# */ + +struct squashfs_super_block { + __le32 s_magic; + __le32 pad0[9]; + __le64 bytes_used; +}; + +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + struct squashfs_super_block sb; + size_t retlen; + int err; + + err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb); + if (err || (retlen != sizeof(sb))) { + pr_alert("error occured while reading from \"%s\"\n", + master->name); + return -EIO; + } + + if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) { + pr_alert("no squashfs found in \"%s\"\n", master->name); + return -EINVAL; + } + + retlen = le64_to_cpu(sb.bytes_used); + if (retlen <= 0) { + pr_alert("squashfs is empty in \"%s\"\n", master->name); + return -ENODEV; + } + + if (offset + retlen > master->size) { + pr_alert("squashfs has invalid size in \"%s\"\n", + master->name); + return -EINVAL; + } + + *squashfs_len = retlen; + return 0; +} +EXPORT_SYMBOL_GPL(mtd_get_squashfs_len); + +static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset) +{ + return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize; +} + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, + enum mtdsplit_part_type *type) +{ + u32 magic; + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, sizeof(magic), &retlen, + (unsigned char *) &magic); + if (ret) + return ret; + + if (retlen != sizeof(magic)) + return -EIO; + + if (le32_to_cpu(magic) == SQUASHFS_MAGIC) { + if (type) + *type = MTDSPLIT_PART_TYPE_SQUASHFS; + return 0; + } else if (magic == 0x19852003) { + if (type) + *type = MTDSPLIT_PART_TYPE_JFFS2; + return 0; + } else if (be32_to_cpu(magic) == UBI_EC_MAGIC) { + if (type) + *type = MTDSPLIT_PART_TYPE_UBI; + return 0; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset, + enum mtdsplit_part_type *type) +{ + size_t offset; + int err; + + for (offset = from; offset < limit; + offset = mtd_next_eb(mtd, offset)) { + err = mtd_check_rootfs_magic(mtd, offset, type); + if (err) + continue; + + *ret_offset = offset; + return 0; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(mtd_find_rootfs_from); + diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.h b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.h new file mode 100644 index 0000000..71d62a8 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * 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. + * + */ + +#ifndef _MTDSPLIT_H +#define _MTDSPLIT_H + +#define KERNEL_PART_NAME "kernel" +#define ROOTFS_PART_NAME "rootfs" +#define UBI_PART_NAME "ubi" + +#define ROOTFS_SPLIT_NAME "rootfs_data" + +enum mtdsplit_part_type { + MTDSPLIT_PART_TYPE_UNK = 0, + MTDSPLIT_PART_TYPE_SQUASHFS, + MTDSPLIT_PART_TYPE_JFFS2, + MTDSPLIT_PART_TYPE_UBI, +}; + +#ifdef CONFIG_MTD_SPLIT +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len); + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, + enum mtdsplit_part_type *type); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset, + enum mtdsplit_part_type *type); + +#else +static inline int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + return -ENODEV; +} + +static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset, + enum mtdsplit_part_type *type) +{ + return -EINVAL; +} + +static inline int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset, + enum mtdsplit_part_type *type) +{ + return -ENODEV; +} +#endif /* CONFIG_MTD_SPLIT */ + +#endif /* _MTDSPLIT_H */ diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c new file mode 100644 index 0000000..3a4b8a7 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm63xx.c @@ -0,0 +1,186 @@ +/* + * Firmware MTD split for BCM63XX, based on bcm63xxpart.c + * + * Copyright (C) 2006-2008 Florian Fainelli + * Copyright (C) 2006-2008 Mike Albon + * Copyright (C) 2009-2010 Daniel Dickinson + * Copyright (C) 2011-2013 Jonas Gorski + * Copyright (C) 2015 Simon Arlott + * Copyright (C) 2017 Álvaro Fernández Rojas + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +/* Ensure strings read from flash structs are null terminated */ +#define STR_NULL_TERMINATE(x) \ + do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0) + +#define BCM63XX_NR_PARTS 2 + +static int bcm63xx_read_image_tag(struct mtd_info *master, loff_t offset, + struct bcm_tag *hdr) +{ + int ret; + size_t retlen; + u32 computed_crc; + + ret = mtd_read(master, offset, sizeof(*hdr), &retlen, (void *) hdr); + if (ret) + return ret; + + if (retlen != sizeof(*hdr)) + return -EIO; + + computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)hdr, + offsetof(struct bcm_tag, header_crc)); + if (computed_crc == hdr->header_crc) { + STR_NULL_TERMINATE(hdr->board_id); + STR_NULL_TERMINATE(hdr->tag_version); + + pr_info("CFE image tag found at 0x%llx with version %s, " + "board type %s\n", offset, hdr->tag_version, + hdr->board_id); + + return 0; + } else { + pr_err("CFE image tag at 0x%llx CRC invalid " + "(expected %08x, actual %08x)\n", + offset, hdr->header_crc, computed_crc); + + return 1; + } +} + +static int bcm63xx_parse_partitions(struct mtd_info *master, + const struct mtd_partition **pparts, + struct bcm_tag *hdr) +{ + struct mtd_partition *parts; + unsigned int flash_image_start; + unsigned int kernel_address; + unsigned int kernel_length; + size_t kernel_offset = 0, kernel_size = 0; + size_t rootfs_offset = 0, rootfs_size = 0; + int kernel_part, rootfs_part; + + STR_NULL_TERMINATE(hdr->flash_image_start); + if (kstrtouint(hdr->flash_image_start, 10, &flash_image_start) || + flash_image_start < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid rootfs address: %*ph\n", + (int) sizeof(hdr->flash_image_start), + hdr->flash_image_start); + return -EINVAL; + } + + STR_NULL_TERMINATE(hdr->kernel_address); + if (kstrtouint(hdr->kernel_address, 10, &kernel_address) || + kernel_address < BCM963XX_EXTENDED_SIZE) { + pr_err("invalid kernel address: %*ph\n", + (int) sizeof(hdr->kernel_address), hdr->kernel_address); + return -EINVAL; + } + + STR_NULL_TERMINATE(hdr->kernel_length); + if (kstrtouint(hdr->kernel_length, 10, &kernel_length) || + !kernel_length) { + pr_err("invalid kernel length: %*ph\n", + (int) sizeof(hdr->kernel_length), hdr->kernel_length); + return -EINVAL; + } + + kernel_offset = kernel_address - BCM963XX_EXTENDED_SIZE - + mtdpart_get_offset(master); + kernel_size = kernel_length; + + if (flash_image_start < kernel_address) { + /* rootfs first */ + rootfs_part = 0; + kernel_part = 1; + rootfs_offset = flash_image_start - BCM963XX_EXTENDED_SIZE - + mtdpart_get_offset(master); + rootfs_size = kernel_offset - rootfs_offset; + } else { + /* kernel first */ + kernel_part = 0; + rootfs_part = 1; + rootfs_offset = kernel_offset + kernel_size; + rootfs_size = master->size - rootfs_offset; + } + + if (mtd_check_rootfs_magic(master, rootfs_offset, NULL)) + pr_warn("rootfs magic not found\n"); + + parts = kzalloc(BCM63XX_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[kernel_part].name = KERNEL_PART_NAME; + parts[kernel_part].offset = kernel_offset; + parts[kernel_part].size = kernel_size; + + parts[rootfs_part].name = ROOTFS_PART_NAME; + parts[rootfs_part].offset = rootfs_offset; + parts[rootfs_part].size = rootfs_size; + + *pparts = parts; + return BCM63XX_NR_PARTS; +} + +static int mtdsplit_parse_bcm63xx(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct bcm_tag hdr; + loff_t offset; + + if (mtd_type_is_nand(master)) + return -EINVAL; + + /* find bcm63xx_cfe image on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + if (!bcm63xx_read_image_tag(master, offset, (void *) &hdr)) + return bcm63xx_parse_partitions(master, pparts, + (void *) &hdr); + } + + return -EINVAL; +} + +static const struct of_device_id mtdsplit_fit_of_match_table[] = { + { .compatible = "brcm,bcm963xx-imagetag" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_bcm63xx_parser = { + .owner = THIS_MODULE, + .name = "bcm63xx-fw", + .of_match_table = mtdsplit_fit_of_match_table, + .parse_fn = mtdsplit_parse_bcm63xx, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_bcm63xx_init(void) +{ + register_mtd_parser(&mtdsplit_bcm63xx_parser); + + return 0; +} + +module_init(mtdsplit_bcm63xx_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c new file mode 100644 index 0000000..1ddcf67 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_bcm_wfi.c @@ -0,0 +1,523 @@ +/* + * MTD split for Broadcom Whole Flash Image + * + * Copyright (C) 2020 Álvaro Fernández Rojas + * + * 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 je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define char_to_num(c) ((c >= '0' && c <= '9') ? (c - '0') : (0)) + +#define BCM_WFI_PARTS 3 +#define BCM_WFI_SPLIT_PARTS 2 + +#define CFERAM_NAME "cferam" +#define CFERAM_NAME_LEN (sizeof(CFERAM_NAME) - 1) +#define KERNEL_NAME "vmlinux.lz" +#define KERNEL_NAME_LEN (sizeof(KERNEL_NAME) - 1) +#define OPENWRT_NAME "1-openwrt" +#define OPENWRT_NAME_LEN (sizeof(OPENWRT_NAME) - 1) + +#define UBI_MAGIC 0x55424923 + +#define CFE_MAGIC_PFX "cferam." +#define CFE_MAGIC_PFX_LEN (sizeof(CFE_MAGIC_PFX) - 1) +#define CFE_MAGIC "cferam.000" +#define CFE_MAGIC_LEN (sizeof(CFE_MAGIC) - 1) +#define SERCOMM_MAGIC_PFX "eRcOmM." +#define SERCOMM_MAGIC_PFX_LEN (sizeof(SERCOMM_MAGIC_PFX) - 1) +#define SERCOMM_MAGIC "eRcOmM.000" +#define SERCOMM_MAGIC_LEN (sizeof(SERCOMM_MAGIC) - 1) + +#define PART_CFERAM "cferam" +#define PART_FIRMWARE "firmware" +#define PART_IMAGE_1 "img1" +#define PART_IMAGE_2 "img2" + +static u32 jffs2_dirent_crc(struct jffs2_raw_dirent *node) +{ + return crc32(0, node, sizeof(struct jffs2_raw_dirent) - 8); +} + +static bool jffs2_dirent_valid(struct jffs2_raw_dirent *node) +{ + return ((je16_to_cpu(node->magic) == JFFS2_MAGIC_BITMASK) && + (je16_to_cpu(node->nodetype) == JFFS2_NODETYPE_DIRENT) && + je32_to_cpu(node->ino) && + je32_to_cpu(node->node_crc) == jffs2_dirent_crc(node)); +} + +static int jffs2_find_file(struct mtd_info *mtd, uint8_t *buf, + const char *name, size_t name_len, + loff_t *offs, loff_t size, + char **out_name, size_t *out_name_len) +{ + const loff_t end = *offs + size; + struct jffs2_raw_dirent *node; + bool valid = false; + size_t retlen; + uint16_t magic; + int rc; + + for (; *offs < end; *offs += mtd->erasesize) { + unsigned int block_offs = 0; + + /* Skip CFE erased blocks */ + rc = mtd_read(mtd, *offs, sizeof(magic), &retlen, + (void *) &magic); + if (rc || retlen != sizeof(magic)) { + continue; + } + + /* Skip blocks not starting with JFFS2 magic */ + if (magic != JFFS2_MAGIC_BITMASK) + continue; + + /* Read full block */ + rc = mtd_read(mtd, *offs, mtd->erasesize, &retlen, + (void *) buf); + if (rc) + return rc; + if (retlen != mtd->erasesize) + return -EINVAL; + + while (block_offs < mtd->erasesize) { + node = (struct jffs2_raw_dirent *) &buf[block_offs]; + + if (!jffs2_dirent_valid(node)) { + block_offs += 4; + continue; + } + + if (!memcmp(node->name, OPENWRT_NAME, + OPENWRT_NAME_LEN)) { + valid = true; + } else if (!memcmp(node->name, name, name_len)) { + if (!valid) + return -EINVAL; + + if (out_name) + *out_name = kstrndup(node->name, + node->nsize, + GFP_KERNEL); + + if (out_name_len) + *out_name_len = node->nsize; + + return 0; + } + + block_offs += je32_to_cpu(node->totlen); + block_offs = (block_offs + 0x3) & ~0x3; + } + } + + return -ENOENT; +} + +static int ubifs_find(struct mtd_info *mtd, loff_t *offs, loff_t size) +{ + const loff_t end = *offs + size; + uint32_t magic; + size_t retlen; + int rc; + + for (; *offs < end; *offs += mtd->erasesize) { + rc = mtd_read(mtd, *offs, sizeof(magic), &retlen, + (unsigned char *) &magic); + if (rc || retlen != sizeof(magic)) + continue; + + if (be32_to_cpu(magic) == UBI_MAGIC) + return 0; + } + + return -ENOENT; +} + +static int parse_bcm_wfi(struct mtd_info *master, + const struct mtd_partition **pparts, + uint8_t *buf, loff_t off, loff_t size, bool cfe_part) +{ + struct mtd_partition *parts; + loff_t cfe_off, kernel_off, rootfs_off; + unsigned int num_parts = BCM_WFI_PARTS, cur_part = 0; + int ret; + + if (cfe_part) { + num_parts++; + cfe_off = off; + + ret = jffs2_find_file(master, buf, CFERAM_NAME, + CFERAM_NAME_LEN, &cfe_off, + size - (cfe_off - off), NULL, NULL); + if (ret) + return ret; + + kernel_off = cfe_off + master->erasesize; + } else { + kernel_off = off; + } + + ret = jffs2_find_file(master, buf, KERNEL_NAME, KERNEL_NAME_LEN, + &kernel_off, size - (kernel_off - off), + NULL, NULL); + if (ret) + return ret; + + rootfs_off = kernel_off + master->erasesize; + ret = ubifs_find(master, &rootfs_off, size - (rootfs_off - off)); + if (ret) + return ret; + + parts = kzalloc(num_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + if (cfe_part) { + parts[cur_part].name = PART_CFERAM; + parts[cur_part].mask_flags = MTD_WRITEABLE; + parts[cur_part].offset = cfe_off; + parts[cur_part].size = kernel_off - cfe_off; + cur_part++; + } + + parts[cur_part].name = PART_FIRMWARE; + parts[cur_part].offset = kernel_off; + parts[cur_part].size = size - (kernel_off - off); + cur_part++; + + parts[cur_part].name = KERNEL_PART_NAME; + parts[cur_part].offset = kernel_off; + parts[cur_part].size = rootfs_off - kernel_off; + cur_part++; + + parts[cur_part].name = UBI_PART_NAME; + parts[cur_part].offset = rootfs_off; + parts[cur_part].size = size - (rootfs_off - off); + cur_part++; + + *pparts = parts; + + return num_parts; +} + +static int mtdsplit_parse_bcm_wfi(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *mtd_node; + bool cfe_part = true; + uint8_t *buf; + int ret; + + mtd_node = mtd_get_of_node(master); + if (!mtd_node) + return -EINVAL; + + buf = kzalloc(master->erasesize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (of_property_read_bool(mtd_node, "brcm,no-cferam")) + cfe_part = false; + + ret = parse_bcm_wfi(master, pparts, buf, 0, master->size, cfe_part); + + kfree(buf); + + return ret; +} + +static const struct of_device_id mtdsplit_bcm_wfi_of_match[] = { + { .compatible = "brcm,wfi" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_bcm_wfi_parser = { + .owner = THIS_MODULE, + .name = "bcm-wfi-fw", + .of_match_table = mtdsplit_bcm_wfi_of_match, + .parse_fn = mtdsplit_parse_bcm_wfi, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int cferam_bootflag_value(const char *name, size_t name_len) +{ + int rc = -ENOENT; + + if (name && + (name_len >= CFE_MAGIC_LEN) && + !memcmp(name, CFE_MAGIC_PFX, CFE_MAGIC_PFX_LEN)) { + rc = char_to_num(name[CFE_MAGIC_PFX_LEN + 0]) * 100; + rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 1]) * 10; + rc += char_to_num(name[CFE_MAGIC_PFX_LEN + 2]) * 1; + } + + return rc; +} + +static int mtdsplit_parse_bcm_wfi_split(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + loff_t cfe_off; + loff_t img1_off = 0; + loff_t img2_off = master->size / 2; + loff_t img1_size = (img2_off - img1_off); + loff_t img2_size = (master->size - img2_off); + loff_t active_off, inactive_off; + loff_t active_size, inactive_size; + const char *inactive_name; + uint8_t *buf; + char *cfe1_name = NULL, *cfe2_name = NULL; + size_t cfe1_size = 0, cfe2_size = 0; + int ret; + int bf1, bf2; + + buf = kzalloc(master->erasesize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + cfe_off = img1_off; + ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN, + &cfe_off, img1_size, &cfe1_name, &cfe1_size); + + cfe_off = img2_off; + ret = jffs2_find_file(master, buf, CFERAM_NAME, CFERAM_NAME_LEN, + &cfe_off, img2_size, &cfe2_name, &cfe2_size); + + bf1 = cferam_bootflag_value(cfe1_name, cfe1_size); + if (bf1 >= 0) + printk("cferam: bootflag1=%d\n", bf1); + + bf2 = cferam_bootflag_value(cfe2_name, cfe2_size); + if (bf2 >= 0) + printk("cferam: bootflag2=%d\n", bf2); + + kfree(cfe1_name); + kfree(cfe2_name); + + if (bf1 >= bf2) { + active_off = img1_off; + active_size = img1_size; + inactive_off = img2_off; + inactive_size = img2_size; + inactive_name = PART_IMAGE_2; + } else { + active_off = img2_off; + active_size = img2_size; + inactive_off = img1_off; + inactive_size = img1_size; + inactive_name = PART_IMAGE_1; + } + + ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, true); + + kfree(buf); + + if (ret > 0) { + parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + memcpy(parts, *pparts, ret * sizeof(*parts)); + kfree(*pparts); + + parts[ret].name = inactive_name; + parts[ret].offset = inactive_off; + parts[ret].size = inactive_size; + ret++; + + *pparts = parts; + } else { + parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL); + + parts[0].name = PART_IMAGE_1; + parts[0].offset = img1_off; + parts[0].size = img1_size; + + parts[1].name = PART_IMAGE_2; + parts[1].offset = img2_off; + parts[1].size = img2_size; + + *pparts = parts; + } + + return ret; +} + +static const struct of_device_id mtdsplit_bcm_wfi_split_of_match[] = { + { .compatible = "brcm,wfi-split" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_bcm_wfi_split_parser = { + .owner = THIS_MODULE, + .name = "bcm-wfi-split-fw", + .of_match_table = mtdsplit_bcm_wfi_split_of_match, + .parse_fn = mtdsplit_parse_bcm_wfi_split, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int sercomm_bootflag_value(struct mtd_info *mtd, uint8_t *buf) +{ + size_t retlen; + loff_t offs; + int rc; + + for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { + rc = mtd_read(mtd, offs, SERCOMM_MAGIC_LEN, &retlen, buf); + if (rc || retlen != SERCOMM_MAGIC_LEN) + continue; + + if (memcmp(buf, SERCOMM_MAGIC_PFX, SERCOMM_MAGIC_PFX_LEN)) + continue; + + rc = char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 0]) * 100; + rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 1]) * 10; + rc += char_to_num(buf[SERCOMM_MAGIC_PFX_LEN + 2]) * 1; + + return rc; + } + + return -ENOENT; +} + +static int mtdsplit_parse_ser_wfi(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct mtd_info *mtd_bf1, *mtd_bf2; + loff_t img1_off = 0; + loff_t img2_off = master->size / 2; + loff_t img1_size = (img2_off - img1_off); + loff_t img2_size = (master->size - img2_off); + loff_t active_off, inactive_off; + loff_t active_size, inactive_size; + const char *inactive_name; + uint8_t *buf; + int bf1, bf2; + int ret; + + mtd_bf1 = get_mtd_device_nm("bootflag1"); + if (IS_ERR(mtd_bf1)) + return -ENOENT; + + mtd_bf2 = get_mtd_device_nm("bootflag2"); + if (IS_ERR(mtd_bf2)) + return -ENOENT; + + buf = kzalloc(master->erasesize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + bf1 = sercomm_bootflag_value(mtd_bf1, buf); + if (bf1 >= 0) + printk("sercomm: bootflag1=%d\n", bf1); + + bf2 = sercomm_bootflag_value(mtd_bf2, buf); + if (bf2 >= 0) + printk("sercomm: bootflag2=%d\n", bf2); + + if (bf1 == bf2 && bf2 >= 0) { + struct erase_info bf_erase; + + bf2 = -ENOENT; + bf_erase.addr = 0; + bf_erase.len = mtd_bf2->size; + mtd_erase(mtd_bf2, &bf_erase); + } + + if (bf1 >= bf2) { + active_off = img1_off; + active_size = img1_size; + inactive_off = img2_off; + inactive_size = img2_size; + inactive_name = PART_IMAGE_2; + } else { + active_off = img2_off; + active_size = img2_size; + inactive_off = img1_off; + inactive_size = img1_size; + inactive_name = PART_IMAGE_1; + } + + ret = parse_bcm_wfi(master, pparts, buf, active_off, active_size, false); + + kfree(buf); + + if (ret > 0) { + parts = kzalloc((ret + 1) * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + memcpy(parts, *pparts, ret * sizeof(*parts)); + kfree(*pparts); + + parts[ret].name = inactive_name; + parts[ret].offset = inactive_off; + parts[ret].size = inactive_size; + ret++; + + *pparts = parts; + } else { + parts = kzalloc(BCM_WFI_SPLIT_PARTS * sizeof(*parts), GFP_KERNEL); + + parts[0].name = PART_IMAGE_1; + parts[0].offset = img1_off; + parts[0].size = img1_size; + + parts[1].name = PART_IMAGE_2; + parts[1].offset = img2_off; + parts[1].size = img2_size; + + *pparts = parts; + } + + return ret; +} + +static const struct of_device_id mtdsplit_ser_wfi_of_match[] = { + { .compatible = "sercomm,wfi" }, + { }, +}; + +static struct mtd_part_parser mtdsplit_ser_wfi_parser = { + .owner = THIS_MODULE, + .name = "ser-wfi-fw", + .of_match_table = mtdsplit_ser_wfi_of_match, + .parse_fn = mtdsplit_parse_ser_wfi, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_bcm_wfi_init(void) +{ + register_mtd_parser(&mtdsplit_bcm_wfi_parser); + register_mtd_parser(&mtdsplit_bcm_wfi_split_parser); + register_mtd_parser(&mtdsplit_ser_wfi_parser); + + return 0; +} + +module_init(mtdsplit_bcm_wfi_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_brnimage.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_brnimage.c new file mode 100644 index 0000000..3f2d796 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_brnimage.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 John Crispin + * Copyright (C) 2015 Martin Blumenstingl + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define BRNIMAGE_NR_PARTS 2 + +#define BRNIMAGE_ALIGN_BYTES 0x400 +#define BRNIMAGE_FOOTER_SIZE 12 + +#define BRNIMAGE_MIN_OVERHEAD (BRNIMAGE_FOOTER_SIZE) +#define BRNIMAGE_MAX_OVERHEAD (BRNIMAGE_ALIGN_BYTES + BRNIMAGE_FOOTER_SIZE) + +static int mtdsplit_parse_brnimage(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + uint32_t buf; + unsigned long rootfs_offset, rootfs_size, kernel_size; + size_t len; + int ret = 0; + + for (rootfs_offset = 0; rootfs_offset < master->size; + rootfs_offset += BRNIMAGE_ALIGN_BYTES) { + ret = mtd_check_rootfs_magic(master, rootfs_offset, NULL); + if (!ret) + break; + } + + if (ret) + return ret; + + if (rootfs_offset >= master->size) + return -EINVAL; + + ret = mtd_read(master, rootfs_offset - BRNIMAGE_FOOTER_SIZE, 4, &len, + (void *)&buf); + if (ret) + return ret; + + if (len != 4) + return -EIO; + + kernel_size = le32_to_cpu(buf); + + if (kernel_size > (rootfs_offset - BRNIMAGE_MIN_OVERHEAD)) + return -EINVAL; + + if (kernel_size < (rootfs_offset - BRNIMAGE_MAX_OVERHEAD)) + return -EINVAL; + + /* + * The footer must be untouched as it contains the checksum of the + * original brnImage (kernel + squashfs)! + */ + rootfs_size = master->size - rootfs_offset - BRNIMAGE_FOOTER_SIZE; + + parts = kzalloc(BRNIMAGE_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = kernel_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return BRNIMAGE_NR_PARTS; +} + +static struct mtd_part_parser mtdsplit_brnimage_parser = { + .owner = THIS_MODULE, + .name = "brnimage-fw", + .parse_fn = mtdsplit_parse_brnimage, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_brnimage_init(void) +{ + register_mtd_parser(&mtdsplit_brnimage_parser); + + return 0; +} + +subsys_initcall(mtdsplit_brnimage_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c new file mode 100644 index 0000000..a3474c9 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_cfe_bootfs.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Rafał Miłecki + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define je16_to_cpu(x) ((x).v16) +#define je32_to_cpu(x) ((x).v32) + +#define NR_PARTS 2 + +static int mtdsplit_cfe_bootfs_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct jffs2_raw_dirent node; + enum mtdsplit_part_type type; + struct mtd_partition *parts; + size_t rootfs_offset; + size_t retlen; + size_t offset; + int err; + + /* Don't parse backup partitions */ + if (strcmp(mtd->name, "firmware")) + return -EINVAL; + + /* Find the end of JFFS2 bootfs partition */ + offset = 0; + do { + err = mtd_read(mtd, offset, sizeof(node), &retlen, (void *)&node); + if (err || retlen != sizeof(node)) + break; + + if (je16_to_cpu(node.magic) != JFFS2_MAGIC_BITMASK) + break; + + offset += je32_to_cpu(node.totlen); + offset = (offset + 0x3) & ~0x3; + } while (offset < mtd->size); + + /* Find rootfs partition that follows the bootfs */ + err = mtd_find_rootfs_from(mtd, mtd->erasesize, mtd->size, &rootfs_offset, &type); + if (err) + return err; + + parts = kzalloc(NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = "bootfs"; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = mtd->size - rootfs_offset; + + *pparts = parts; + + return NR_PARTS; +} + +static const struct of_device_id mtdsplit_cfe_bootfs_of_match_table[] = { + { .compatible = "brcm,bcm4908-firmware" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_cfe_bootfs_of_match_table); + +static struct mtd_part_parser mtdsplit_cfe_bootfs_parser = { + .owner = THIS_MODULE, + .name = "cfe-bootfs", + .of_match_table = mtdsplit_cfe_bootfs_of_match_table, + .parse_fn = mtdsplit_cfe_bootfs_parse, +}; + +module_mtd_part_parser(mtdsplit_cfe_bootfs_parser); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_elf.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_elf.c new file mode 100644 index 0000000..4781841 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_elf.c @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * MTD splitter for ELF loader firmware partitions + * + * Copyright (C) 2020 Sander Vanheule + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2. + * + * To parse the ELF kernel loader, a small ELF parser is used that can + * handle both ELF32 or ELF64 class loaders. The splitter assumes that the + * kernel is always located before the rootfs, whether it is embedded in the + * loader or not. + * + * The kernel image is preferably embedded inside the ELF loader, so the end + * of the loader equals the end of the kernel partition. This is due to the + * way mtd_find_rootfs_from searches for the the rootfs: + * - if the kernel image is embedded in the loader, the appended rootfs may + * follow the loader immediately, within the same erase block. + * - if the kernel image is not embedded in the loader, but placed at some + * offset behind the loader (OKLI-style loader), the rootfs must be + * aligned to an erase-block after the loader and kernel image. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define ELF_NR_PARTS 2 + +#define ELF_MAGIC 0x7f454c46 /* 0x7f E L F */ +#define ELF_CLASS_32 1 +#define ELF_CLASS_64 2 + +struct elf_header_ident { + uint32_t magic; + uint8_t class; + uint8_t data; + uint8_t version; + uint8_t osabi; + uint8_t abiversion; + uint8_t pad[7]; +}; + +struct elf_header_32 { + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t phoff; + uint32_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +struct elf_header_64 { + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry; + uint64_t phoff; + uint64_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +struct elf_header { + struct elf_header_ident ident; + union { + struct elf_header_32 elf32; + struct elf_header_64 elf64; + }; +}; + +struct elf_program_header_32 { + uint32_t type; + uint32_t offset; + uint32_t vaddr; + uint32_t paddr; + uint32_t filesize; + uint32_t memsize; + uint32_t flags; +}; + +struct elf_program_header_64 { + uint32_t type; + uint32_t flags; + uint64_t offset; + uint64_t vaddr; + uint64_t paddr; + uint64_t filesize; + uint64_t memsize; +}; + + +static int mtdsplit_elf_read_mtd(struct mtd_info *mtd, size_t offset, + uint8_t *dst, size_t len) +{ + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, len, &retlen, dst); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static int elf32_determine_size(struct mtd_info *mtd, struct elf_header *hdr, + size_t *size) +{ + struct elf_header_32 *hdr32 = &(hdr->elf32); + int err; + size_t section_end, ph_table_end, ph_entry; + struct elf_program_header_32 ph; + + *size = 0; + + if (hdr32->shoff > 0) { + *size = hdr32->shoff + hdr32->shentsize * hdr32->shnum; + return 0; + } + + ph_entry = hdr32->phoff; + ph_table_end = hdr32->phoff + hdr32->phentsize * hdr32->phnum; + + while (ph_entry < ph_table_end) { + err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph), + sizeof(ph)); + if (err) + return err; + + section_end = ph.offset + ph.filesize; + if (section_end > *size) + *size = section_end; + + ph_entry += hdr32->phentsize; + } + + return 0; +} + +static int elf64_determine_size(struct mtd_info *mtd, struct elf_header *hdr, + size_t *size) +{ + struct elf_header_64 *hdr64 = &(hdr->elf64); + int err; + size_t section_end, ph_table_end, ph_entry; + struct elf_program_header_64 ph; + + *size = 0; + + if (hdr64->shoff > 0) { + *size = hdr64->shoff + hdr64->shentsize * hdr64->shnum; + return 0; + } + + ph_entry = hdr64->phoff; + ph_table_end = hdr64->phoff + hdr64->phentsize * hdr64->phnum; + + while (ph_entry < ph_table_end) { + err = mtdsplit_elf_read_mtd(mtd, ph_entry, (uint8_t *)(&ph), + sizeof(ph)); + if (err) + return err; + + section_end = ph.offset + ph.filesize; + if (section_end > *size) + *size = section_end; + + ph_entry += hdr64->phentsize; + } + + return 0; +} + +static int mtdsplit_parse_elf(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct elf_header hdr; + size_t loader_size, rootfs_offset; + enum mtdsplit_part_type type; + struct mtd_partition *parts; + int err; + + err = mtdsplit_elf_read_mtd(mtd, 0, (uint8_t *)&hdr, sizeof(hdr)); + if (err) + return err; + + if (be32_to_cpu(hdr.ident.magic) != ELF_MAGIC) { + pr_debug("invalid ELF magic %08x\n", + be32_to_cpu(hdr.ident.magic)); + return -EINVAL; + } + + switch (hdr.ident.class) { + case ELF_CLASS_32: + err = elf32_determine_size(mtd, &hdr, &loader_size); + break; + case ELF_CLASS_64: + err = elf64_determine_size(mtd, &hdr, &loader_size); + break; + default: + pr_debug("invalid ELF class %i\n", hdr.ident.class); + err = -EINVAL; + } + + if (err) + return err; + + err = mtd_find_rootfs_from(mtd, loader_size, mtd->size, + &rootfs_offset, &type); + if (err) + return err; + + if (rootfs_offset == mtd->size) { + pr_debug("no rootfs found in \"%s\"\n", mtd->name); + return -ENODEV; + } + + parts = kzalloc(ELF_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = mtd->size - rootfs_offset; + + *pparts = parts; + return ELF_NR_PARTS; +} + +static const struct of_device_id mtdsplit_elf_of_match_table[] = { + { .compatible = "openwrt,elf" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_elf_of_match_table); + +static struct mtd_part_parser mtdsplit_elf_parser = { + .owner = THIS_MODULE, + .name = "elf-loader-fw", + .of_match_table = mtdsplit_elf_of_match_table, + .parse_fn = mtdsplit_parse_elf, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_elf_init(void) +{ + register_mtd_parser(&mtdsplit_elf_parser); + + return 0; +} + +subsys_initcall(mtdsplit_elf_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_eva.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_eva.c new file mode 100644 index 0000000..55004a6 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_eva.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012 John Crispin + * Copyright (C) 2015 Martin Blumenstingl + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define EVA_NR_PARTS 2 +#define EVA_MAGIC 0xfeed1281 +#define EVA_FOOTER_SIZE 0x18 +#define EVA_DUMMY_SQUASHFS_SIZE 0x100 + +struct eva_image_header { + uint32_t magic; + uint32_t size; +}; + +static int mtdsplit_parse_eva(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct eva_image_header hdr; + size_t retlen; + unsigned long kernel_size, rootfs_offset; + int err; + + err = mtd_read(master, 0, sizeof(hdr), &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != sizeof(hdr)) + return -EIO; + + if (le32_to_cpu(hdr.magic) != EVA_MAGIC) + return -EINVAL; + + kernel_size = le32_to_cpu(hdr.size) + EVA_FOOTER_SIZE; + + /* rootfs starts at the next 0x10000 boundary: */ + rootfs_offset = round_up(kernel_size, 0x10000); + + /* skip the dummy EVA squashfs partition (with wrong endianness): */ + rootfs_offset += EVA_DUMMY_SQUASHFS_SIZE; + + if (rootfs_offset >= master->size) + return -EINVAL; + + err = mtd_check_rootfs_magic(master, rootfs_offset, NULL); + if (err) + return err; + + parts = kzalloc(EVA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = kernel_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return EVA_NR_PARTS; +} + +static const struct of_device_id mtdsplit_eva_of_match_table[] = { + { .compatible = "avm,eva-firmware" }, + {}, +}; + +static struct mtd_part_parser mtdsplit_eva_parser = { + .owner = THIS_MODULE, + .name = "eva-fw", + .of_match_table = mtdsplit_eva_of_match_table, + .parse_fn = mtdsplit_parse_eva, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_eva_init(void) +{ + register_mtd_parser(&mtdsplit_eva_parser); + + return 0; +} + +subsys_initcall(mtdsplit_eva_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_fit.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_fit.c new file mode 100644 index 0000000..f043428 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_fit.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015 The Linux Foundation + * Copyright (C) 2014 Gabor Juhos + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +struct fdt_header { + uint32_t magic; /* magic word FDT_MAGIC */ + uint32_t totalsize; /* total size of DT block */ + uint32_t off_dt_struct; /* offset to structure */ + uint32_t off_dt_strings; /* offset to strings */ + uint32_t off_mem_rsvmap; /* offset to memory reserve map */ + uint32_t version; /* format version */ + uint32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + uint32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + uint32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + uint32_t size_dt_struct; /* size of the structure block */ +}; + +static int +mtdsplit_fit_parse(struct mtd_info *mtd, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *np = mtd_get_of_node(mtd); + const char *cmdline_match = NULL; + struct fdt_header hdr; + size_t hdr_len, retlen; + size_t offset; + size_t fit_offset, fit_size; + size_t rootfs_offset, rootfs_size; + struct mtd_partition *parts; + enum mtdsplit_part_type type; + int ret; + + of_property_read_string(np, "openwrt,cmdline-match", &cmdline_match); + if (cmdline_match && !strstr(saved_command_line, cmdline_match)) + return -ENODEV; + + hdr_len = sizeof(struct fdt_header); + + /* Parse the MTD device & search for the FIT image location */ + for(offset = 0; offset + hdr_len <= mtd->size; offset += mtd->erasesize) { + ret = mtd_read(mtd, offset, hdr_len, &retlen, (void*) &hdr); + if (ret) { + pr_err("read error in \"%s\" at offset 0x%llx\n", + mtd->name, (unsigned long long) offset); + return ret; + } + + if (retlen != hdr_len) { + pr_err("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + /* Check the magic - see if this is a FIT image */ + if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) { + pr_debug("no valid FIT image found in \"%s\" at offset %llx\n", + mtd->name, (unsigned long long) offset); + continue; + } + + /* We found a FIT image. Let's keep going */ + break; + } + + fit_offset = offset; + fit_size = be32_to_cpu(hdr.totalsize); + + if (fit_size == 0) { + pr_err("FIT image in \"%s\" at offset %llx has null size\n", + mtd->name, (unsigned long long) fit_offset); + return -ENODEV; + } + + /* Search for the rootfs partition after the FIT image */ + ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, mtd->size, + &rootfs_offset, &type); + if (ret) { + pr_info("no rootfs found after FIT image in \"%s\"\n", + mtd->name); + return ret; + } + + rootfs_size = mtd->size - rootfs_offset; + + parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = fit_offset; + parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return 2; +} + +static const struct of_device_id mtdsplit_fit_of_match_table[] = { + { .compatible = "denx,fit" }, + {}, +}; + +static struct mtd_part_parser uimage_parser = { + .owner = THIS_MODULE, + .name = "fit-fw", + .of_match_table = mtdsplit_fit_of_match_table, + .parse_fn = mtdsplit_fit_parse, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_fit_init(void) +{ + register_mtd_parser(&uimage_parser); + + return 0; +} + +module_init(mtdsplit_fit_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_jimage.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_jimage.c new file mode 100644 index 0000000..1770dd4 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_jimage.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2018 Paweł Dembicki + * + * Based on: mtdsplit_uimage.c + * Copyright (C) 2013 Gabor Juhos + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define MAX_HEADER_LEN ( STAG_SIZE + SCH2_SIZE ) + +#define STAG_SIZE 16 +#define STAG_ID 0x04 +#define STAG_MAGIC 0x2B24 + +#define SCH2_SIZE 40 +#define SCH2_MAGIC 0x2124 +#define SCH2_VER 0x02 + +/* + * Jboot image header, + * all data in little endian. + */ + +struct jimage_header //stag + sch2 jboot joined headers +{ + uint8_t stag_cmark; // in factory 0xFF , in sysupgrade must be the same as stag_id + uint8_t stag_id; // 0x04 + uint16_t stag_magic; //magic 0x2B24 + uint32_t stag_time_stamp; // timestamp calculated in jboot way + uint32_t stag_image_length; // lentgh of kernel + sch2 header + uint16_t stag_image_checksum; // negated jboot_checksum of sch2 + kernel + uint16_t stag_tag_checksum; // negated jboot_checksum of stag header data + uint16_t sch2_magic; // magic 0x2124 + uint8_t sch2_cp_type; // 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma + uint8_t sch2_version; // 0x02 for sch2 + uint32_t sch2_ram_addr; // ram entry address + uint32_t sch2_image_len; // kernel image length + uint32_t sch2_image_crc32; // kernel image crc + uint32_t sch2_start_addr; // ram start address + uint32_t sch2_rootfs_addr; // rootfs flash address + uint32_t sch2_rootfs_len; // rootfls length + uint32_t sch2_rootfs_crc32; // rootfs crc32 + uint32_t sch2_header_crc32; // sch2 header crc32, durring calculation this area is replaced by zero + uint16_t sch2_header_length; // sch2 header length: 0x28 + uint16_t sch2_cmd_line_length; // cmd line length, known zeros +}; + +static int +read_jimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, + size_t header_len) +{ + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, header_len, &retlen, buf); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +/** + * __mtdsplit_parse_jimage - scan partition and create kernel + rootfs parts + * + * @find_header: function to call for a block of data that will return offset + * of a valid jImage header if found + */ +static int __mtdsplit_parse_jimage(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data, + ssize_t (*find_header)(u_char *buf, size_t len)) +{ + struct mtd_partition *parts; + u_char *buf; + int nr_parts; + size_t offset; + size_t jimage_offset; + size_t jimage_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int jimage_part, rf_part; + int ret; + enum mtdsplit_part_type type; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + buf = vmalloc(MAX_HEADER_LEN); + if (!buf) { + ret = -ENOMEM; + goto err_free_parts; + } + + /* find jImage on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + struct jimage_header *header; + + jimage_size = 0; + + ret = read_jimage_header(master, offset, buf, MAX_HEADER_LEN); + if (ret) + continue; + + ret = find_header(buf, MAX_HEADER_LEN); + if (ret < 0) { + pr_debug("no valid jImage found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + header = (struct jimage_header *)(buf + ret); + + jimage_size = sizeof(*header) + header->sch2_image_len + ret; + if ((offset + jimage_size) > master->size) { + pr_debug("jImage exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (jimage_size == 0) { + pr_debug("no jImage found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + jimage_offset = offset; + + if (jimage_offset == 0) { + jimage_part = 0; + rf_part = 1; + + /* find the roots after the jImage */ + ret = mtd_find_rootfs_from(master, jimage_offset + jimage_size, + master->size, &rootfs_offset, &type); + if (ret) { + pr_debug("no rootfs after jImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_size = master->size - rootfs_offset; + jimage_size = rootfs_offset - jimage_offset; + } else { + rf_part = 0; + jimage_part = 1; + + /* check rootfs presence at offset 0 */ + ret = mtd_check_rootfs_magic(master, 0, &type); + if (ret) { + pr_debug("no rootfs before jImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_offset = 0; + rootfs_size = jimage_offset; + } + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + parts[jimage_part].name = KERNEL_PART_NAME; + parts[jimage_part].offset = jimage_offset; + parts[jimage_part].size = jimage_size; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[rf_part].name = UBI_PART_NAME; + else + parts[rf_part].name = ROOTFS_PART_NAME; + parts[rf_part].offset = rootfs_offset; + parts[rf_part].size = rootfs_size; + + vfree(buf); + + *pparts = parts; + return nr_parts; + +err_free_buf: + vfree(buf); + +err_free_parts: + kfree(parts); + return ret; +} + +static ssize_t jimage_verify_default(u_char *buf, size_t len) +{ + struct jimage_header *header = (struct jimage_header *)buf; + + /* default sanity checks */ + if (header->stag_magic != STAG_MAGIC) { + pr_debug("invalid jImage stag header magic: %04x\n", + header->stag_magic); + return -EINVAL; + } + if (header->sch2_magic != SCH2_MAGIC) { + pr_debug("invalid jImage sch2 header magic: %04x\n", + header->stag_magic); + return -EINVAL; + } + if (header->stag_cmark != header->stag_id) { + pr_debug("invalid jImage stag header cmark: %02x\n", + header->stag_magic); + return -EINVAL; + } + if (header->stag_id != STAG_ID) { + pr_debug("invalid jImage stag header id: %02x\n", + header->stag_magic); + return -EINVAL; + } + if (header->sch2_version != SCH2_VER) { + pr_debug("invalid jImage sch2 header version: %02x\n", + header->stag_magic); + return -EINVAL; + } + + return 0; +} + +static int +mtdsplit_jimage_parse_generic(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_jimage(master, pparts, data, + jimage_verify_default); +} + +static const struct of_device_id mtdsplit_jimage_of_match_table[] = { + { .compatible = "amit,jimage" }, + {}, +}; + +static struct mtd_part_parser jimage_generic_parser = { + .owner = THIS_MODULE, + .name = "jimage-fw", + .of_match_table = mtdsplit_jimage_of_match_table, + .parse_fn = mtdsplit_jimage_parse_generic, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_jimage_init(void) +{ + register_mtd_parser(&jimage_generic_parser); + + return 0; +} + +module_init(mtdsplit_jimage_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_lzma.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_lzma.c new file mode 100644 index 0000000..c58f7ae --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_lzma.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mtdsplit.h" + +#define LZMA_NR_PARTS 2 +#define LZMA_PROPERTIES_SIZE 5 + +struct lzma_header { + u8 props[LZMA_PROPERTIES_SIZE]; + u8 size_low[4]; + u8 size_high[4]; +}; + +static int mtdsplit_parse_lzma(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct lzma_header hdr; + size_t hdr_len, retlen; + size_t rootfs_offset; + u32 t; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* verify LZMA properties */ + if (hdr.props[0] >= (9 * 5 * 5)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.props[1]); + if (!is_power_of_2(t)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.size_high); + if (t) + return -EINVAL; + + err = mtd_find_rootfs_from(master, master->erasesize, master->size, + &rootfs_offset, NULL); + if (err) + return err; + + parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return LZMA_NR_PARTS; +} + +static const struct of_device_id mtdsplit_lzma_of_match_table[] = { + { .compatible = "lzma" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_lzma_of_match_table); + +static struct mtd_part_parser mtdsplit_lzma_parser = { + .owner = THIS_MODULE, + .name = "lzma-fw", + .of_match_table = mtdsplit_lzma_of_match_table, + .parse_fn = mtdsplit_parse_lzma, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_lzma_init(void) +{ + register_mtd_parser(&mtdsplit_lzma_parser); + + return 0; +} + +subsys_initcall(mtdsplit_lzma_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_minor.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_minor.c new file mode 100644 index 0000000..af6822e --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_minor.c @@ -0,0 +1,125 @@ +/* + * MTD splitter for MikroTik NOR devices + * + * Copyright (C) 2017 Thibaut VARENE + * + * 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. + * + * The rootfs is expected at erase-block boundary due to the use of + * mtd_find_rootfs_from(). We use a trimmed down version of the yaffs header + * for two main reasons: + * - the original header uses weakly defined types (int, enum...) which can + * vary in length depending on build host (and the struct is not packed), + * and the name field can have a different total length depending on + * whether or not the yaffs code was _built_ with unicode support. + * - the only field that could be of real use here (file_size_low) contains + * invalid data in the header generated by kernel2minor, so we cannot use + * it to infer the exact position of the rootfs and do away with + * mtd_find_rootfs_from() (and thus have non-EB-aligned rootfs). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define YAFFS_OBJECT_TYPE_FILE 0x1 +#define YAFFS_OBJECTID_ROOT 0x1 +#define YAFFS_SUM_UNUSED 0xFFFF +#define YAFFS_NAME "kernel" + +#define MINOR_NR_PARTS 2 + +/* + * This structure is based on yaffs_obj_hdr from yaffs_guts.h + * The weak types match upstream. The fields have cpu-endianness + */ +struct minor_header { + int yaffs_type; + int yaffs_obj_id; + u16 yaffs_sum_unused; + char yaffs_name[sizeof(YAFFS_NAME)]; +}; + +static int mtdsplit_parse_minor(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct minor_header hdr; + size_t hdr_len, retlen; + size_t rootfs_offset; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* match header */ + if (hdr.yaffs_type != YAFFS_OBJECT_TYPE_FILE) + return -EINVAL; + + if (hdr.yaffs_obj_id != YAFFS_OBJECTID_ROOT) + return -EINVAL; + + if (hdr.yaffs_sum_unused != YAFFS_SUM_UNUSED) + return -EINVAL; + + if (memcmp(hdr.yaffs_name, YAFFS_NAME, sizeof(YAFFS_NAME))) + return -EINVAL; + + err = mtd_find_rootfs_from(master, master->erasesize, master->size, + &rootfs_offset, NULL); + if (err) + return err; + + parts = kzalloc(MINOR_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return MINOR_NR_PARTS; +} + +static const struct of_device_id mtdsplit_minor_of_match_table[] = { + { .compatible = "mikrotik,minor" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_minor_of_match_table); + +static struct mtd_part_parser mtdsplit_minor_parser = { + .owner = THIS_MODULE, + .name = "minor-fw", + .of_match_table = mtdsplit_minor_of_match_table, + .parse_fn = mtdsplit_parse_minor, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_minor_init(void) +{ + register_mtd_parser(&mtdsplit_minor_parser); + + return 0; +} + +subsys_initcall(mtdsplit_minor_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_seama.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_seama.c new file mode 100644 index 0000000..5d49171 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_seama.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define SEAMA_MAGIC 0x5EA3A417 +#define SEAMA_NR_PARTS 2 +#define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ + +struct seama_header { + __be32 magic; /* should always be SEAMA_MAGIC. */ + __be16 reserved; /* reserved for */ + __be16 metasize; /* size of the META data */ + __be32 size; /* size of the image */ + u8 md5[16]; /* digest */ +}; + +static int mtdsplit_parse_seama(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct seama_header hdr; + size_t hdr_len, retlen, kernel_ent_size; + size_t rootfs_offset; + struct mtd_partition *parts; + enum mtdsplit_part_type type; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* sanity checks */ + if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) + return -EINVAL; + + kernel_ent_size = hdr_len + be32_to_cpu(hdr.size) + + be16_to_cpu(hdr.metasize); + if (kernel_ent_size > master->size) + return -EINVAL; + + /* Check for the rootfs right after Seama entity with a kernel. */ + err = mtd_check_rootfs_magic(master, kernel_ent_size, &type); + if (!err) { + rootfs_offset = kernel_ent_size; + } else { + /* + * On some devices firmware entity might contain both: kernel + * and rootfs. We can't determine kernel size so we just have to + * look for rootfs magic. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset, &type); + if (err) + return err; + } + + parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = sizeof hdr + be16_to_cpu(hdr.metasize); + parts[0].size = rootfs_offset - parts[0].offset; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[1].name = UBI_PART_NAME; + else + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return SEAMA_NR_PARTS; +} + +static const struct of_device_id mtdsplit_seama_of_match_table[] = { + { .compatible = "seama" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_seama_of_match_table); + +static struct mtd_part_parser mtdsplit_seama_parser = { + .owner = THIS_MODULE, + .name = "seama-fw", + .of_match_table = mtdsplit_seama_of_match_table, + .parse_fn = mtdsplit_parse_seama, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_seama_init(void) +{ + register_mtd_parser(&mtdsplit_seama_parser); + + return 0; +} + +subsys_initcall(mtdsplit_seama_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_squashfs.c new file mode 100644 index 0000000..f6353da --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_squashfs.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 Gabor Juhos + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +static int +mtdsplit_parse_squashfs(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *part; + struct mtd_info *parent_mtd; + size_t part_offset; + size_t squashfs_len; + int err; + + err = mtd_get_squashfs_len(master, 0, &squashfs_len); + if (err) + return err; + + parent_mtd = mtd_get_master(master); + part_offset = mtdpart_get_offset(master); + + part = kzalloc(sizeof(*part), GFP_KERNEL); + if (!part) { + pr_alert("unable to allocate memory for \"%s\" partition\n", + ROOTFS_SPLIT_NAME); + return -ENOMEM; + } + + part->name = ROOTFS_SPLIT_NAME; + part->offset = mtd_roundup_to_eb(part_offset + squashfs_len, + parent_mtd) - part_offset; + part->size = mtd_rounddown_to_eb(master->size - part->offset, master); + + *pparts = part; + return 1; +} + +static struct mtd_part_parser mtdsplit_squashfs_parser = { + .owner = THIS_MODULE, + .name = "squashfs-split", + .parse_fn = mtdsplit_parse_squashfs, + .type = MTD_PARSER_TYPE_ROOTFS, +}; + +static int __init mtdsplit_squashfs_init(void) +{ + register_mtd_parser(&mtdsplit_squashfs_parser); + + return 0; +} + +subsys_initcall(mtdsplit_squashfs_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_tplink.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_tplink.c new file mode 100644 index 0000000..8909c10 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_tplink.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define TPLINK_NR_PARTS 2 +#define TPLINK_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ + +#define MD5SUM_LEN 16 + +struct fw_v1 { + char vendor_name[24]; + char fw_version[36]; + uint32_t hw_id; /* hardware id */ + uint32_t hw_rev; /* hardware revision */ + uint32_t unk1; + uint8_t md5sum1[MD5SUM_LEN]; + uint32_t unk2; + uint8_t md5sum2[MD5SUM_LEN]; + uint32_t unk3; + uint32_t kernel_la; /* kernel load address */ + uint32_t kernel_ep; /* kernel entry point */ + uint32_t fw_length; /* total length of the firmware */ + uint32_t kernel_ofs; /* kernel data offset */ + uint32_t kernel_len; /* kernel data length */ + uint32_t rootfs_ofs; /* rootfs data offset */ + uint32_t rootfs_len; /* rootfs data length */ + uint32_t boot_ofs; /* bootloader data offset */ + uint32_t boot_len; /* bootloader data length */ + uint8_t pad[360]; +} __attribute__ ((packed)); + +struct fw_v2 { + char fw_version[48]; /* 0x04: fw version string */ + uint32_t hw_id; /* 0x34: hardware id */ + uint32_t hw_rev; /* 0x38: FIXME: hardware revision? */ + uint32_t unk1; /* 0x3c: 0x00000000 */ + uint8_t md5sum1[MD5SUM_LEN]; /* 0x40 */ + uint32_t unk2; /* 0x50: 0x00000000 */ + uint8_t md5sum2[MD5SUM_LEN]; /* 0x54 */ + uint32_t unk3; /* 0x64: 0xffffffff */ + + uint32_t kernel_la; /* 0x68: kernel load address */ + uint32_t kernel_ep; /* 0x6c: kernel entry point */ + uint32_t fw_length; /* 0x70: total length of the image */ + uint32_t kernel_ofs; /* 0x74: kernel data offset */ + uint32_t kernel_len; /* 0x78: kernel data length */ + uint32_t rootfs_ofs; /* 0x7c: rootfs data offset */ + uint32_t rootfs_len; /* 0x80: rootfs data length */ + uint32_t boot_ofs; /* 0x84: FIXME: seems to be unused */ + uint32_t boot_len; /* 0x88: FIXME: seems to be unused */ + uint16_t unk4; /* 0x8c: 0x55aa */ + uint8_t sver_hi; /* 0x8e */ + uint8_t sver_lo; /* 0x8f */ + uint8_t unk5; /* 0x90: magic: 0xa5 */ + uint8_t ver_hi; /* 0x91 */ + uint8_t ver_mid; /* 0x92 */ + uint8_t ver_lo; /* 0x93 */ + uint8_t pad[364]; +} __attribute__ ((packed)); + +struct tplink_fw_header { + uint32_t version; + union { + struct fw_v1 v1; + struct fw_v2 v2; + }; +}; + +static int mtdsplit_parse_tplink(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct tplink_fw_header hdr; + size_t hdr_len, retlen, kernel_size; + size_t rootfs_offset; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + switch (le32_to_cpu(hdr.version)) { + case 1: + if (be32_to_cpu(hdr.v1.kernel_ofs) != sizeof(hdr)) + return -EINVAL; + + kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v1.kernel_len); + rootfs_offset = be32_to_cpu(hdr.v1.rootfs_ofs); + break; + case 2: + case 3: + if (be32_to_cpu(hdr.v2.kernel_ofs) != sizeof(hdr)) + return -EINVAL; + + kernel_size = sizeof(hdr) + be32_to_cpu(hdr.v2.kernel_len); + rootfs_offset = be32_to_cpu(hdr.v2.rootfs_ofs); + break; + default: + return -EINVAL; + } + + if (kernel_size > master->size) + return -EINVAL; + + /* Find the rootfs */ + err = mtd_check_rootfs_magic(master, rootfs_offset, NULL); + if (err) { + /* + * The size in the header might cover the rootfs as well. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, TPLINK_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset, NULL); + if (err) + return err; + } + + parts = kzalloc(TPLINK_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = kernel_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return TPLINK_NR_PARTS; +} + +static const struct of_device_id mtdsplit_tplink_of_match_table[] = { + { .compatible = "tplink,firmware" }, + {}, +}; + +static struct mtd_part_parser mtdsplit_tplink_parser = { + .owner = THIS_MODULE, + .name = "tplink-fw", + .of_match_table = mtdsplit_tplink_of_match_table, + .parse_fn = mtdsplit_parse_tplink, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_tplink_init(void) +{ + register_mtd_parser(&mtdsplit_tplink_parser); + + return 0; +} + +subsys_initcall(mtdsplit_tplink_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_trx.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_trx.c new file mode 100644 index 0000000..b853ec9 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_trx.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ + +struct trx_header { + __le32 magic; + __le32 len; + __le32 crc32; + __le32 flag_version; + __le32 offset[4]; +}; + +static int +read_trx_header(struct mtd_info *mtd, size_t offset, + struct trx_header *header) +{ + size_t header_len; + size_t retlen; + int ret; + + header_len = sizeof(*header); + ret = mtd_read(mtd, offset, header_len, &retlen, + (unsigned char *) header); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static int +mtdsplit_parse_trx(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct trx_header hdr; + int nr_parts; + size_t offset; + size_t trx_offset; + size_t trx_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int ret; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + /* find trx image on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + trx_size = 0; + + ret = read_trx_header(master, offset, &hdr); + if (ret) + continue; + + if (hdr.magic != cpu_to_le32(TRX_MAGIC)) { + pr_debug("no valid trx header found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + + trx_size = le32_to_cpu(hdr.len); + if ((offset + trx_size) > master->size) { + pr_debug("trx image exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (trx_size == 0) { + pr_debug("no trx header found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + trx_offset = offset + hdr.offset[0]; + rootfs_offset = offset + hdr.offset[1]; + rootfs_size = master->size - rootfs_offset; + trx_size = rootfs_offset - trx_offset; + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = trx_offset; + parts[0].size = trx_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return nr_parts; + +err: + kfree(parts); + return ret; +} + +static const struct of_device_id trx_parser_of_match_table[] = { + { .compatible = "openwrt,trx" }, + {}, +}; +MODULE_DEVICE_TABLE(of, trx_parser_of_match_table); + +static struct mtd_part_parser trx_parser = { + .owner = THIS_MODULE, + .name = "trx-fw", + .of_match_table = trx_parser_of_match_table, + .parse_fn = mtdsplit_parse_trx, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_trx_init(void) +{ + register_mtd_parser(&trx_parser); + + return 0; +} + +module_init(mtdsplit_trx_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_uimage.c new file mode 100644 index 0000000..a3e55fb --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_uimage.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +/* + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). + */ +struct uimage_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +}; + +static int +read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, + size_t header_len) +{ + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, header_len, &retlen, buf); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static void uimage_parse_dt(struct mtd_info *master, int *extralen, + u32 *ih_magic, u32 *ih_type, + u32 *header_offset, u32 *part_magic) +{ + struct device_node *np = mtd_get_of_node(master); + + if (!np || !of_device_is_compatible(np, "openwrt,uimage")) + return; + + if (!of_property_read_u32(np, "openwrt,padding", extralen)) + pr_debug("got openwrt,padding=%d from device-tree\n", *extralen); + if (!of_property_read_u32(np, "openwrt,ih-magic", ih_magic)) + pr_debug("got openwrt,ih-magic=%08x from device-tree\n", *ih_magic); + if (!of_property_read_u32(np, "openwrt,ih-type", ih_type)) + pr_debug("got openwrt,ih-type=%08x from device-tree\n", *ih_type); + if (!of_property_read_u32(np, "openwrt,offset", header_offset)) + pr_debug("got ih-start=%u from device-tree\n", *header_offset); + if (!of_property_read_u32(np, "openwrt,partition-magic", part_magic)) + pr_debug("got openwrt,partition-magic=%08x from device-tree\n", *part_magic); +} + +static ssize_t uimage_verify_default(u_char *buf, u32 ih_magic, u32 ih_type) +{ + struct uimage_header *header = (struct uimage_header *)buf; + + /* default sanity checks */ + if (be32_to_cpu(header->ih_magic) != ih_magic) { + pr_debug("invalid uImage magic: %08x != %08x\n", + be32_to_cpu(header->ih_magic), ih_magic); + return -EINVAL; + } + + if (header->ih_os != IH_OS_LINUX) { + pr_debug("invalid uImage OS: %08x != %08x\n", + be32_to_cpu(header->ih_os), IH_OS_LINUX); + return -EINVAL; + } + + if (header->ih_type != ih_type) { + pr_debug("invalid uImage type: %08x != %08x\n", + be32_to_cpu(header->ih_type), ih_type); + return -EINVAL; + } + + return 0; +} + +/** + * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts + * + * @find_header: function to call for a block of data that will return offset + * and tail padding length of a valid uImage header if found + */ +static int __mtdsplit_parse_uimage(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + u_char *buf; + int nr_parts; + size_t offset; + size_t uimage_offset; + size_t uimage_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + size_t buflen; + int uimage_part, rf_part; + int ret; + int extralen = 0; + u32 ih_magic = IH_MAGIC; + u32 ih_type = IH_TYPE_KERNEL; + u32 header_offset = 0; + u32 part_magic = 0; + enum mtdsplit_part_type type; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + uimage_parse_dt(master, &extralen, &ih_magic, &ih_type, &header_offset, &part_magic); + buflen = sizeof(struct uimage_header) + header_offset; + buf = vmalloc(buflen); + if (!buf) { + ret = -ENOMEM; + goto err_free_parts; + } + + /* find uImage on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + struct uimage_header *header; + + uimage_size = 0; + + ret = read_uimage_header(master, offset, buf, buflen); + if (ret) + continue; + + /* verify optional partition magic before uimage header */ + if (header_offset && part_magic && (be32_to_cpu(*(u32 *)buf) != part_magic)) + continue; + + ret = uimage_verify_default(buf + header_offset, ih_magic, ih_type); + if (ret < 0) { + pr_debug("no valid uImage found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + + header = (struct uimage_header *)(buf + header_offset); + + uimage_size = sizeof(*header) + + be32_to_cpu(header->ih_size) + header_offset + extralen; + + if ((offset + uimage_size) > master->size) { + pr_debug("uImage exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (uimage_size == 0) { + pr_debug("no uImage found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + uimage_offset = offset; + + if (uimage_offset == 0) { + uimage_part = 0; + rf_part = 1; + + /* find the roots after the uImage */ + ret = mtd_find_rootfs_from(master, uimage_offset + uimage_size, + master->size, &rootfs_offset, &type); + if (ret) { + pr_debug("no rootfs after uImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_size = master->size - rootfs_offset; + uimage_size = rootfs_offset - uimage_offset; + } else { + rf_part = 0; + uimage_part = 1; + + /* check rootfs presence at offset 0 */ + ret = mtd_check_rootfs_magic(master, 0, &type); + if (ret) { + pr_debug("no rootfs before uImage in \"%s\"\n", + master->name); + goto err_free_buf; + } + + rootfs_offset = 0; + rootfs_size = uimage_offset; + } + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_buf; + } + + parts[uimage_part].name = KERNEL_PART_NAME; + parts[uimage_part].offset = uimage_offset; + parts[uimage_part].size = uimage_size; + + if (type == MTDSPLIT_PART_TYPE_UBI) + parts[rf_part].name = UBI_PART_NAME; + else + parts[rf_part].name = ROOTFS_PART_NAME; + parts[rf_part].offset = rootfs_offset; + parts[rf_part].size = rootfs_size; + + vfree(buf); + + *pparts = parts; + return nr_parts; + +err_free_buf: + vfree(buf); + +err_free_parts: + kfree(parts); + return ret; +} + +static const struct of_device_id mtdsplit_uimage_of_match_table[] = { + { .compatible = "denx,uimage" }, + { .compatible = "openwrt,uimage" }, + {}, +}; + +static struct mtd_part_parser uimage_generic_parser = { + .owner = THIS_MODULE, + .name = "uimage-fw", + .of_match_table = mtdsplit_uimage_of_match_table, + .parse_fn = __mtdsplit_parse_uimage, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +/************************************************** + * Init + **************************************************/ + +static int __init mtdsplit_uimage_init(void) +{ + register_mtd_parser(&uimage_generic_parser); + + return 0; +} + +module_init(mtdsplit_uimage_init); diff --git a/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_wrgg.c b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_wrgg.c new file mode 100644 index 0000000..dfd6058 --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/mtdsplit/mtdsplit_wrgg.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * Copyright (C) 2016 Stijn Tintel + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define WRGG_NR_PARTS 2 +#define WRGG_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ +#define WRGG03_MAGIC 0x20080321 +#define WRG_MAGIC 0x20040220 + +struct wrgg03_header { + char signature[32]; + uint32_t magic1; + uint32_t magic2; + char version[16]; + char model[16]; + uint32_t flag[2]; + uint32_t reserve[2]; + char buildno[16]; + uint32_t size; + uint32_t offset; + char devname[32]; + char digest[16]; +} __attribute__ ((packed)); + +struct wrg_header { + char signature[32]; + uint32_t magic1; + uint32_t magic2; + uint32_t size; + uint32_t offset; + char devname[32]; + char digest[16]; +} __attribute__ ((packed)); + + +static int mtdsplit_parse_wrgg(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct wrgg03_header hdr; + size_t hdr_len, retlen, kernel_ent_size; + size_t rootfs_offset; + struct mtd_partition *parts; + enum mtdsplit_part_type type; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* sanity checks */ + if (le32_to_cpu(hdr.magic1) == WRGG03_MAGIC) { + kernel_ent_size = hdr_len + be32_to_cpu(hdr.size); + /* + * If this becomes silly big it's probably because the + * WRGG image is little-endian. + */ + if (kernel_ent_size > master->size) + kernel_ent_size = hdr_len + le32_to_cpu(hdr.size); + + /* Now what ?! It's neither */ + if (kernel_ent_size > master->size) + return -EINVAL; + } else if (le32_to_cpu(hdr.magic1) == WRG_MAGIC) { + kernel_ent_size = sizeof(struct wrg_header) + le32_to_cpu( + ((struct wrg_header*)&hdr)->size); + } else { + return -EINVAL; + } + + if (kernel_ent_size > master->size) + return -EINVAL; + + /* + * The size in the header covers the rootfs as well. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, WRGG_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset, &type); + if (err) + return err; + + parts = kzalloc(WRGG_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return WRGG_NR_PARTS; +} + +static const struct of_device_id mtdsplit_wrgg_of_match_table[] = { + { .compatible = "wrg" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtdsplit_wrgg_of_match_table); + +static struct mtd_part_parser mtdsplit_wrgg_parser = { + .owner = THIS_MODULE, + .name = "wrgg-fw", + .of_match_table = mtdsplit_wrgg_of_match_table, + .parse_fn = mtdsplit_parse_wrgg, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_wrgg_init(void) +{ + register_mtd_parser(&mtdsplit_wrgg_parser); + + return 0; +} + +subsys_initcall(mtdsplit_wrgg_init); diff --git a/ipq806x/files-5.4/drivers/mtd/parsers/routerbootpart.c b/ipq806x/files-5.4/drivers/mtd/parsers/routerbootpart.c new file mode 100644 index 0000000..f9bba0f --- /dev/null +++ b/ipq806x/files-5.4/drivers/mtd/parsers/routerbootpart.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Parser for MikroTik RouterBoot partitions. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This parser builds from the "fixed-partitions" one (see ofpart.c), but it can + * handle dynamic partitions as found on routerboot devices. + * + * DTS nodes are defined as follows: + * For fixed partitions: + * node-name@unit-address { + * reg = ; + * label = ; + * read-only; + * lock; + * }; + * + * reg property is mandatory; other properties are optional. + * reg format is
. length can be 0 if the next partition is + * another fixed partition or a "well-known" partition as defined below: in that + * case the partition will extend up to the next one. + * + * For dynamic partitions: + * node-name { + * size = ; + * label = ; + * read-only; + * lock; + * }; + * + * size property is normally mandatory. It can only be omitted (or set to 0) if: + * - the partition is a "well-known" one (as defined below), in which case + * the partition size will be automatically adjusted; or + * - the next partition is a fixed one or a "well-known" one, in which case + * the current partition will extend up to the next one. + * Other properties are optional. + * size format is . + * By default dynamic partitions are appended after the preceding one, except + * for "well-known" ones which are automatically located on flash. + * + * Well-known partitions (matched via label or node-name): + * - "hard_config" + * - "soft_config" + * - "dtb_config" + * + * Note: this parser will happily register 0-sized partitions if misused. + * + * This parser requires the DTS to list partitions in ascending order as + * expected on the MTD device. + * + * Since only the "hard_config" and "soft_config" partitions are used in OpenWRT, + * a minimal working DTS could define only these two partitions dynamically (in + * the right order, usually hard_config then soft_config). + * + * Note: some mips RB devices encode the hard_config offset and length in two + * consecutive u32 located at offset 0x14 (for ramips) or 0x24 (for ath79) on + * the SPI NOR flash. Unfortunately this seems inconsistent across machines and + * does not apply to e.g. ipq-based ones, so we ignore that information. + * + * Note: To find well-known partitions, this parser will go through the entire + * top mtd partition parsed, _before_ the DTS nodes are processed. This works + * well in the current state of affairs, and is a simpler implementation than + * searching for known partitions in the "holes" left between fixed-partition, + * _after_ processing DTS nodes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define RB_MAGIC_HARD (('H') | ('a' << 8) | ('r' << 16) | ('d' << 24)) +#define RB_MAGIC_SOFT (('S') | ('o' << 8) | ('f' << 16) | ('t' << 24)) +#define RB_BLOCK_SIZE 0x1000 + +struct routerboot_dynpart { + const char * const name; + const u32 magic; + int (* const size_fixup)(struct mtd_info *, struct routerboot_dynpart *); + size_t offset; + size_t size; + bool found; +}; + +static int routerboot_dtbsfixup(struct mtd_info *, struct routerboot_dynpart *); + +static struct routerboot_dynpart rb_dynparts[] = { + { + .name = "hard_config", + .magic = RB_MAGIC_HARD, // stored in CPU-endianness on flash + .size_fixup = NULL, + .offset = 0x0, + .size = RB_BLOCK_SIZE, + .found = false, + }, { + .name = "soft_config", + .magic = RB_MAGIC_SOFT, // stored in CPU-endianness on flash + .size_fixup = NULL, + .offset = 0x0, + .size = RB_BLOCK_SIZE, + .found = false, + }, { + .name = "dtb_config", + .magic = fdt32_to_cpu(OF_DT_HEADER), // stored BE on flash + .size_fixup = routerboot_dtbsfixup, + .offset = 0x0, + .size = 0x0, + .found = false, + } +}; + +static int routerboot_dtbsfixup(struct mtd_info *master, struct routerboot_dynpart *rbdpart) +{ + int err; + size_t bytes_read, psize; + struct { + fdt32_t magic; + fdt32_t totalsize; + fdt32_t off_dt_struct; + fdt32_t off_dt_strings; + fdt32_t off_mem_rsvmap; + fdt32_t version; + fdt32_t last_comp_version; + fdt32_t boot_cpuid_phys; + fdt32_t size_dt_strings; + fdt32_t size_dt_struct; + } fdt_header; + + err = mtd_read(master, rbdpart->offset, sizeof(fdt_header), + &bytes_read, (u8 *)&fdt_header); + if (err) + return err; + + if (bytes_read != sizeof(fdt_header)) + return -EIO; + + psize = fdt32_to_cpu(fdt_header.totalsize); + if (!psize) + return -EINVAL; + + rbdpart->size = psize; + return 0; +} + +static void routerboot_find_dynparts(struct mtd_info *master) +{ + size_t bytes_read, offset; + bool allfound; + int err, i; + u32 buf; + + /* + * Dynamic RouterBoot partitions offsets are aligned to RB_BLOCK_SIZE: + * read the whole partition at RB_BLOCK_SIZE intervals to find sigs. + * Skip partition content when possible. + */ + offset = 0; + while (offset < master->size) { + err = mtd_read(master, offset, sizeof(buf), &bytes_read, (u8 *)&buf); + if (err) { + pr_err("%s: mtd_read error while parsing (offset: 0x%X): %d\n", + master->name, offset, err); + continue; + } + + allfound = true; + + for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) { + if (rb_dynparts[i].found) + continue; + + allfound = false; + + if (rb_dynparts[i].magic == buf) { + rb_dynparts[i].offset = offset; + + if (rb_dynparts[i].size_fixup) { + err = rb_dynparts[i].size_fixup(master, &rb_dynparts[i]); + if (err) { + pr_err("%s: size fixup error while parsing \"%s\": %d\n", + master->name, rb_dynparts[i].name, err); + continue; + } + } + + rb_dynparts[i].found = true; + + /* + * move offset to skip the whole partition on + * next iteration if size > RB_BLOCK_SIZE. + */ + if (rb_dynparts[i].size > RB_BLOCK_SIZE) + offset += ALIGN_DOWN((rb_dynparts[i].size - RB_BLOCK_SIZE), RB_BLOCK_SIZE); + + break; + } + } + + offset += RB_BLOCK_SIZE; + + if (allfound) + break; + } +} + +static int routerboot_partitions_parse(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *rbpart_node, *pp; + struct mtd_partition *parts; + const char *partname; + size_t master_ofs; + int np; + + /* Pull of_node from the master device node */ + rbpart_node = mtd_get_of_node(master); + if (!rbpart_node) + return 0; + + /* First count the subnodes */ + np = 0; + for_each_child_of_node(rbpart_node, pp) + np++; + + if (!np) + return 0; + + parts = kcalloc(np, sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + /* Preemptively look for known parts in flash */ + routerboot_find_dynparts(master); + + np = 0; + master_ofs = 0; + for_each_child_of_node(rbpart_node, pp) { + const __be32 *reg, *sz; + size_t offset, size; + int i, len, a_cells, s_cells; + + partname = of_get_property(pp, "label", &len); + /* Allow deprecated use of "name" instead of "label" */ + if (!partname) + partname = of_get_property(pp, "name", &len); + /* Fallback to node name per spec if all else fails: partname is always set */ + if (!partname) + partname = pp->name; + parts[np].name = partname; + + reg = of_get_property(pp, "reg", &len); + if (reg) { + /* Fixed partition */ + a_cells = of_n_addr_cells(pp); + s_cells = of_n_size_cells(pp); + + if ((len / 4) != (a_cells + s_cells)) { + pr_debug("%s: routerboot partition %pOF (%pOF) error parsing reg property.\n", + master->name, pp, rbpart_node); + goto rbpart_fail; + } + + offset = of_read_number(reg, a_cells); + size = of_read_number(reg + a_cells, s_cells); + } else { + /* Dynamic partition */ + /* Default: part starts at current offset, 0 size */ + offset = master_ofs; + size = 0; + + /* Check if well-known partition */ + for (i = 0; i < ARRAY_SIZE(rb_dynparts); i++) { + if (!strcmp(partname, rb_dynparts[i].name) && rb_dynparts[i].found) { + offset = rb_dynparts[i].offset; + size = rb_dynparts[i].size; + break; + } + } + + /* Standalone 'size' property? Override size */ + sz = of_get_property(pp, "size", &len); + if (sz) { + s_cells = of_n_size_cells(pp); + if ((len / 4) != s_cells) { + pr_debug("%s: routerboot partition %pOF (%pOF) error parsing size property.\n", + master->name, pp, rbpart_node); + goto rbpart_fail; + } + + size = of_read_number(sz, s_cells); + } + } + + if (np > 0) { + /* Minor sanity check for overlaps */ + if (offset < (parts[np-1].offset + parts[np-1].size)) { + pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" overlaps with previous partition \"%s\".\n", + master->name, pp, rbpart_node, + partname, parts[np-1].name); + goto rbpart_fail; + } + + /* Fixup end of previous partition if necessary */ + if (!parts[np-1].size) + parts[np-1].size = (offset - parts[np-1].offset); + } + + if ((offset + size) > master->size) { + pr_err("%s: routerboot partition %pOF (%pOF) \"%s\" extends past end of segment.\n", + master->name, pp, rbpart_node, partname); + goto rbpart_fail; + } + + parts[np].offset = offset; + parts[np].size = size; + parts[np].of_node = pp; + + if (of_get_property(pp, "read-only", &len)) + parts[np].mask_flags |= MTD_WRITEABLE; + + if (of_get_property(pp, "lock", &len)) + parts[np].mask_flags |= MTD_POWERUP_LOCK; + + /* Keep master offset aligned to RB_BLOCK_SIZE */ + master_ofs = ALIGN(offset + size, RB_BLOCK_SIZE); + np++; + } + + *pparts = parts; + return np; + +rbpart_fail: + pr_err("%s: error parsing routerboot partition %pOF (%pOF)\n", + master->name, pp, rbpart_node); + of_node_put(pp); + kfree(parts); + return -EINVAL; +} + +static const struct of_device_id parse_routerbootpart_match_table[] = { + { .compatible = "mikrotik,routerboot-partitions" }, + {}, +}; +MODULE_DEVICE_TABLE(of, parse_routerbootpart_match_table); + +static struct mtd_part_parser routerbootpart_parser = { + .parse_fn = routerboot_partitions_parse, + .name = "routerbootpart", + .of_match_table = parse_routerbootpart_match_table, +}; +module_mtd_part_parser(routerbootpart_parser); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MTD partitioning for RouterBoot"); +MODULE_AUTHOR("Thibaut VARENE"); diff --git a/ipq806x/files-5.4/drivers/net/phy/adm6996.c b/ipq806x/files-5.4/drivers/net/phy/adm6996.c new file mode 100644 index 0000000..66013f2 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/adm6996.c @@ -0,0 +1,1243 @@ +/* + * ADM6996 switch driver + * + * swconfig interface based on ar8216.c + * + * Copyright (c) 2008 Felix Fietkau + * VLAN support Copyright (c) 2010, 2011 Peter Lebbing + * Copyright (c) 2013 Hauke Mehrtens + * Copyright (c) 2014 Matti Laakso + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/*#define DEBUG 1*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "adm6996.h" + +MODULE_DESCRIPTION("Infineon ADM6996 Switch"); +MODULE_AUTHOR("Felix Fietkau, Peter Lebbing "); +MODULE_LICENSE("GPL"); + +static const char * const adm6996_model_name[] = +{ + NULL, + "ADM6996FC", + "ADM6996M", + "ADM6996L" +}; + +struct adm6996_mib_desc { + unsigned int offset; + const char *name; +}; + +struct adm6996_priv { + struct switch_dev dev; + void *priv; + + u8 eecs; + u8 eesk; + u8 eedi; + + enum adm6996_model model; + + bool enable_vlan; + bool vlan_enabled; /* Current hardware state */ + +#ifdef DEBUG + u16 addr; /* Debugging: register address to operate on */ +#endif + + u16 pvid[ADM_NUM_PORTS]; /* Primary VLAN ID */ + u8 tagged_ports; + + u16 vlan_id[ADM_NUM_VLANS]; + u8 vlan_table[ADM_NUM_VLANS]; /* bitmap, 1 = port is member */ + u8 vlan_tagged[ADM_NUM_VLANS]; /* bitmap, 1 = tagged member */ + + struct mutex mib_lock; + char buf[2048]; + + struct mutex reg_mutex; + + /* use abstraction for regops, we want to add gpio support in the future */ + u16 (*read)(struct adm6996_priv *priv, enum admreg reg); + void (*write)(struct adm6996_priv *priv, enum admreg reg, u16 val); +}; + +#define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev) +#define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) + +#define MIB_DESC(_o, _n) \ + { \ + .offset = (_o), \ + .name = (_n), \ + } + +static const struct adm6996_mib_desc adm6996_mibs[] = { + MIB_DESC(ADM_CL0, "RxPacket"), + MIB_DESC(ADM_CL6, "RxByte"), + MIB_DESC(ADM_CL12, "TxPacket"), + MIB_DESC(ADM_CL18, "TxByte"), + MIB_DESC(ADM_CL24, "Collision"), + MIB_DESC(ADM_CL30, "Error"), +}; + +#define ADM6996_MIB_RXB_ID 1 +#define ADM6996_MIB_TXB_ID 3 + +static inline u16 +r16(struct adm6996_priv *priv, enum admreg reg) +{ + return priv->read(priv, reg); +} + +static inline void +w16(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + priv->write(priv, reg, val); +} + +/* Minimum timing constants */ +#define EECK_EDGE_TIME 3 /* 3us - max(adm 2.5us, 93c 1us) */ +#define EEDI_SETUP_TIME 1 /* 1us - max(adm 10ns, 93c 400ns) */ +#define EECS_SETUP_TIME 1 /* 1us - max(adm no, 93c 200ns) */ + +static void adm6996_gpio_write(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) +{ + int i, len = (bits + 7) / 8; + u8 mask; + + gpio_set_value(priv->eecs, cs); + udelay(EECK_EDGE_TIME); + + /* Byte assemble from MSB to LSB */ + for (i = 0; i < len; i++) { + /* Bit bang from MSB to LSB */ + for (mask = 0x80; mask && bits > 0; mask >>= 1, bits --) { + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + /* Output on rising edge */ + gpio_set_value(priv->eedi, (mask & buf[i])); + udelay(EEDI_SETUP_TIME); + + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + } + } + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + if (cs) + gpio_set_value(priv->eecs, 0); +} + +static void adm6996_gpio_read(struct adm6996_priv *priv, int cs, char *buf, unsigned int bits) +{ + int i, len = (bits + 7) / 8; + u8 mask; + + gpio_set_value(priv->eecs, cs); + udelay(EECK_EDGE_TIME); + + /* Byte assemble from MSB to LSB */ + for (i = 0; i < len; i++) { + u8 byte; + + /* Bit bang from MSB to LSB */ + for (mask = 0x80, byte = 0; mask && bits > 0; mask >>= 1, bits --) { + u8 gp; + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + /* Input on rising edge */ + gp = gpio_get_value(priv->eedi); + if (gp) + byte |= mask; + + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + } + + *buf++ = byte; + } + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + + if (cs) + gpio_set_value(priv->eecs, 0); +} + +/* Advance clock(s) */ +static void adm6996_gpio_adclk(struct adm6996_priv *priv, int clocks) +{ + int i; + for (i = 0; i < clocks; i++) { + /* Clock high */ + gpio_set_value(priv->eesk, 1); + udelay(EECK_EDGE_TIME); + + /* Clock low */ + gpio_set_value(priv->eesk, 0); + udelay(EECK_EDGE_TIME); + } +} + +static u16 +adm6996_read_gpio_reg(struct adm6996_priv *priv, enum admreg reg) +{ + /* cmd: 01 10 T DD R RRRRRR */ + u8 bits[6] = { + 0xFF, 0xFF, 0xFF, 0xFF, + (0x06 << 4) | ((0 & 0x01) << 3 | (reg&64)>>6), + ((reg&63)<<2) + }; + + u8 rbits[4]; + + /* Enable GPIO outputs with all pins to 0 */ + gpio_direction_output(priv->eecs, 0); + gpio_direction_output(priv->eesk, 0); + gpio_direction_output(priv->eedi, 0); + + adm6996_gpio_write(priv, 0, bits, 46); + gpio_direction_input(priv->eedi); + adm6996_gpio_adclk(priv, 2); + adm6996_gpio_read(priv, 0, rbits, 32); + + /* Extra clock(s) required per datasheet */ + adm6996_gpio_adclk(priv, 2); + + /* Disable GPIO outputs */ + gpio_direction_input(priv->eecs); + gpio_direction_input(priv->eesk); + + /* EEPROM has 16-bit registers, but pumps out two registers in one request */ + return (reg & 0x01 ? (rbits[0]<<8) | rbits[1] : (rbits[2]<<8) | (rbits[3])); +} + +/* Write chip configuration register */ +/* Follow 93c66 timing and chip's min EEPROM timing requirement */ +static void +adm6996_write_gpio_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + /* cmd(27bits): sb(1) + opc(01) + addr(bbbbbbbb) + data(bbbbbbbbbbbbbbbb) */ + u8 bits[4] = { + (0x05 << 5) | (reg >> 3), + (reg << 5) | (u8)(val >> 11), + (u8)(val >> 3), + (u8)(val << 5) + }; + + /* Enable GPIO outputs with all pins to 0 */ + gpio_direction_output(priv->eecs, 0); + gpio_direction_output(priv->eesk, 0); + gpio_direction_output(priv->eedi, 0); + + /* Write cmd. Total 27 bits */ + adm6996_gpio_write(priv, 1, bits, 27); + + /* Extra clock(s) required per datasheet */ + adm6996_gpio_adclk(priv, 2); + + /* Disable GPIO outputs */ + gpio_direction_input(priv->eecs); + gpio_direction_input(priv->eesk); + gpio_direction_input(priv->eedi); +} + +static u16 +adm6996_read_mii_reg(struct adm6996_priv *priv, enum admreg reg) +{ + struct phy_device *phydev = priv->priv; + struct mii_bus *bus = phydev->mdio.bus; + + return bus->read(bus, PHYADDR(reg)); +} + +static void +adm6996_write_mii_reg(struct adm6996_priv *priv, enum admreg reg, u16 val) +{ + struct phy_device *phydev = priv->priv; + struct mii_bus *bus = phydev->mdio.bus; + + bus->write(bus, PHYADDR(reg), val); +} + +static int +adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 1) + return -EINVAL; + + priv->enable_vlan = val->value.i; + + return 0; +}; + +static int +adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = priv->enable_vlan; + + return 0; +}; + +#ifdef DEBUG + +static int +adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 1023) + return -EINVAL; + + priv->addr = val->value.i; + + return 0; +}; + +static int +adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = priv->addr; + + return 0; +}; + +static int +adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + if (val->value.i > 65535) + return -EINVAL; + + w16(priv, priv->addr, val->value.i); + + return 0; +}; + +static int +adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + val->value.i = r16(priv, priv->addr); + + return 0; +}; + +#endif /* def DEBUG */ + +static int +adm6996_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("set_pvid port %d vlan %d\n", port, vlan); + + if (vlan > ADM_VLAN_MAX_ID) + return -EINVAL; + + priv->pvid[port] = vlan; + + return 0; +} + +static int +adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("get_pvid port %d\n", port); + *vlan = priv->pvid[port]; + + return 0; +} + +static int +adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("set_vid port %d vid %d\n", val->port_vlan, val->value.i); + + if (val->value.i > ADM_VLAN_MAX_ID) + return -EINVAL; + + priv->vlan_id[val->port_vlan] = val->value.i; + + return 0; +}; + +static int +adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("get_vid port %d\n", val->port_vlan); + + val->value.i = priv->vlan_id[val->port_vlan]; + + return 0; +}; + +static int +adm6996_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + u8 tagged = priv->vlan_tagged[val->port_vlan]; + int i; + + pr_devel("get_ports port_vlan %d\n", val->port_vlan); + + val->len = 0; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + + return 0; +}; + +static int +adm6996_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + u8 *ports = &priv->vlan_table[val->port_vlan]; + u8 *tagged = &priv->vlan_tagged[val->port_vlan]; + int i; + + pr_devel("set_ports port_vlan %d ports", val->port_vlan); + + *ports = 0; + *tagged = 0; + + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + +#ifdef DEBUG + pr_cont(" %d%s", p->id, + ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" : + "")); +#endif + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + *tagged |= (1 << p->id); + priv->tagged_ports |= (1 << p->id); + } + + *ports |= (1 << p->id); + } + +#ifdef DEBUG + pr_cont("\n"); +#endif + + return 0; +}; + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_enable_vlan(struct adm6996_priv *priv) +{ + u16 reg; + + reg = r16(priv, ADM_OTBE_P2_PVID); + reg &= ~(ADM_OTBE_MASK); + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = r16(priv, ADM_IFNTE); + reg &= ~(ADM_IFNTE_MASK); + w16(priv, ADM_IFNTE, reg); + reg = r16(priv, ADM_VID_CHECK); + reg |= ADM_VID_CHECK_MASK; + w16(priv, ADM_VID_CHECK, reg); + reg = r16(priv, ADM_SYSC0); + reg |= ADM_NTTE; + reg &= ~(ADM_RVID1); + w16(priv, ADM_SYSC0, reg); + reg = r16(priv, ADM_SYSC3); + reg |= ADM_TBV; + w16(priv, ADM_SYSC3, reg); +} + +static void +adm6996_enable_vlan_6996l(struct adm6996_priv *priv) +{ + u16 reg; + + reg = r16(priv, ADM_SYSC3); + reg |= ADM_TBV; + reg |= ADM_MAC_CLONE; + w16(priv, ADM_SYSC3, reg); +} + +/* + * Disable VLANs + * + * Sets VLAN mapping for port-based VLAN with all ports connected to + * eachother (this is also the power-on default). + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_disable_vlan(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + reg = ADM_VLAN_FILT_MEMBER_MASK; + w16(priv, ADM_VLAN_FILT_L(i), reg); + reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1); + w16(priv, ADM_VLAN_FILT_H(i), reg); + } + + reg = r16(priv, ADM_OTBE_P2_PVID); + reg |= ADM_OTBE_MASK; + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = r16(priv, ADM_IFNTE); + reg |= ADM_IFNTE_MASK; + w16(priv, ADM_IFNTE, reg); + reg = r16(priv, ADM_VID_CHECK); + reg &= ~(ADM_VID_CHECK_MASK); + w16(priv, ADM_VID_CHECK, reg); + reg = r16(priv, ADM_SYSC0); + reg &= ~(ADM_NTTE); + reg |= ADM_RVID1; + w16(priv, ADM_SYSC0, reg); + reg = r16(priv, ADM_SYSC3); + reg &= ~(ADM_TBV); + w16(priv, ADM_SYSC3, reg); +} + +/* + * Disable VLANs + * + * Sets VLAN mapping for port-based VLAN with all ports connected to + * eachother (this is also the power-on default). + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_disable_vlan_6996l(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + w16(priv, ADM_VLAN_MAP(i), 0); + } + + reg = r16(priv, ADM_SYSC3); + reg &= ~(ADM_TBV); + reg &= ~(ADM_MAC_CLONE); + w16(priv, ADM_SYSC3, reg); +} + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_apply_port_pvids(struct adm6996_priv *priv) +{ + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + reg = r16(priv, adm_portcfg[i]); + reg &= ~(ADM_PORTCFG_PVID_MASK); + reg |= ADM_PORTCFG_PVID(priv->pvid[i]); + if (priv->model == ADM6996L) { + if (priv->tagged_ports & (1 << i)) + reg |= (1 << 4); + else + reg &= ~(1 << 4); + } + w16(priv, adm_portcfg[i], reg); + } + + w16(priv, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0])); + w16(priv, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1])); + reg = r16(priv, ADM_OTBE_P2_PVID); + reg &= ~(ADM_P2_PVID_MASK); + reg |= ADM_P2_PVID_VAL(priv->pvid[2]); + w16(priv, ADM_OTBE_P2_PVID, reg); + reg = ADM_P3_PVID_VAL(priv->pvid[3]); + reg |= ADM_P4_PVID_VAL(priv->pvid[4]); + w16(priv, ADM_P3_P4_PVID, reg); + reg = r16(priv, ADM_P5_PVID); + reg &= ~(ADM_P2_PVID_MASK); + reg |= ADM_P5_PVID_VAL(priv->pvid[5]); + w16(priv, ADM_P5_PVID, reg); +} + +/* + * Precondition: reg_mutex must be held + */ +static void +adm6996_apply_vlan_filters(struct adm6996_priv *priv) +{ + u8 ports, tagged; + u16 vid, reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + vid = priv->vlan_id[i]; + ports = priv->vlan_table[i]; + tagged = priv->vlan_tagged[i]; + + if (ports == 0) { + /* Disable VLAN entry */ + w16(priv, ADM_VLAN_FILT_H(i), 0); + w16(priv, ADM_VLAN_FILT_L(i), 0); + continue; + } + + reg = ADM_VLAN_FILT_MEMBER(ports); + reg |= ADM_VLAN_FILT_TAGGED(tagged); + w16(priv, ADM_VLAN_FILT_L(i), reg); + reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid); + w16(priv, ADM_VLAN_FILT_H(i), reg); + } +} + +static void +adm6996_apply_vlan_filters_6996l(struct adm6996_priv *priv) +{ + u8 ports; + u16 reg; + int i; + + for (i = 0; i < ADM_NUM_VLANS; i++) { + ports = priv->vlan_table[i]; + + if (ports == 0) { + /* Disable VLAN entry */ + w16(priv, ADM_VLAN_MAP(i), 0); + continue; + } else { + reg = ADM_VLAN_FILT(ports); + w16(priv, ADM_VLAN_MAP(i), reg); + } + } +} + +static int +adm6996_hw_apply(struct switch_dev *dev) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("hw_apply\n"); + + mutex_lock(&priv->reg_mutex); + + if (!priv->enable_vlan) { + if (priv->vlan_enabled) { + if (priv->model == ADM6996L) + adm6996_disable_vlan_6996l(priv); + else + adm6996_disable_vlan(priv); + priv->vlan_enabled = 0; + } + goto out; + } + + if (!priv->vlan_enabled) { + if (priv->model == ADM6996L) + adm6996_enable_vlan_6996l(priv); + else + adm6996_enable_vlan(priv); + priv->vlan_enabled = 1; + } + + adm6996_apply_port_pvids(priv); + if (priv->model == ADM6996L) + adm6996_apply_vlan_filters_6996l(priv); + else + adm6996_apply_vlan_filters(priv); + +out: + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +/* + * Reset the switch + * + * The ADM6996 can't do a software-initiated reset, so we just initialise the + * registers we support in this driver. + * + * Precondition: reg_mutex must be held + */ +static void +adm6996_perform_reset (struct adm6996_priv *priv) +{ + int i; + + /* initialize port and vlan settings */ + for (i = 0; i < ADM_NUM_PORTS - 1; i++) { + w16(priv, adm_portcfg[i], ADM_PORTCFG_INIT | + ADM_PORTCFG_PVID(0)); + } + w16(priv, adm_portcfg[5], ADM_PORTCFG_CPU); + + if (priv->model == ADM6996M || priv->model == ADM6996FC) { + /* reset all PHY ports */ + for (i = 0; i < ADM_PHY_PORTS; i++) { + w16(priv, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); + } + } + + priv->enable_vlan = 0; + priv->vlan_enabled = 0; + + for (i = 0; i < ADM_NUM_PORTS; i++) { + priv->pvid[i] = 0; + } + + for (i = 0; i < ADM_NUM_VLANS; i++) { + priv->vlan_id[i] = i; + priv->vlan_table[i] = 0; + priv->vlan_tagged[i] = 0; + } + + if (priv->model == ADM6996M) { + /* Clear VLAN priority map so prio's are unused */ + w16 (priv, ADM_VLAN_PRIOMAP, 0); + + adm6996_disable_vlan(priv); + adm6996_apply_port_pvids(priv); + } else if (priv->model == ADM6996L) { + /* Clear VLAN priority map so prio's are unused */ + w16 (priv, ADM_VLAN_PRIOMAP, 0); + + adm6996_disable_vlan_6996l(priv); + adm6996_apply_port_pvids(priv); + } +} + +static int +adm6996_reset_switch(struct switch_dev *dev) +{ + struct adm6996_priv *priv = to_adm(dev); + + pr_devel("reset\n"); + + mutex_lock(&priv->reg_mutex); + adm6996_perform_reset (priv); + mutex_unlock(&priv->reg_mutex); + return 0; +} + +static int +adm6996_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct adm6996_priv *priv = to_adm(dev); + + u16 reg = 0; + + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + switch (port) { + case 0: + reg = r16(priv, ADM_PS0); + break; + case 1: + reg = r16(priv, ADM_PS0); + reg = reg >> 8; + break; + case 2: + reg = r16(priv, ADM_PS1); + break; + case 3: + reg = r16(priv, ADM_PS1); + reg = reg >> 8; + break; + case 4: + reg = r16(priv, ADM_PS1); + reg = reg >> 12; + break; + case 5: + reg = r16(priv, ADM_PS2); + /* Bits 0, 1, 3 and 4. */ + reg = (reg & 3) | ((reg & 24) >> 1); + break; + default: + return -EINVAL; + } + + link->link = reg & ADM_PS_LS; + if (!link->link) + return 0; + link->aneg = true; + link->duplex = reg & ADM_PS_DS; + link->tx_flow = reg & ADM_PS_FCS; + link->rx_flow = reg & ADM_PS_FCS; + if (reg & ADM_PS_SS) + link->speed = SWITCH_PORT_SPEED_100; + else + link->speed = SWITCH_PORT_SPEED_10; + + return 0; +} + +static int +adm6996_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct adm6996_priv *priv = to_adm(dev); + int port; + char *buf = priv->buf; + int i, len = 0; + u32 reg = 0; + + port = val->port_vlan; + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + len += snprintf(buf + len, sizeof(priv->buf) - len, + "Port %d MIB counters\n", + port); + + for (i = 0; i < ARRAY_SIZE(adm6996_mibs); i++) { + reg = r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port)); + reg += r16(priv, adm6996_mibs[i].offset + ADM_OFFSET_PORT(port) + 1) << 16; + len += snprintf(buf + len, sizeof(priv->buf) - len, + "%-12s: %u\n", + adm6996_mibs[i].name, + reg); + } + + mutex_unlock(&priv->mib_lock); + + val->value.s = buf; + val->len = len; + + return 0; +} + +static int +adm6996_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + struct adm6996_priv *priv = to_adm(dev); + int id; + u32 reg = 0; + + if (port >= ADM_NUM_PORTS) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + id = ADM6996_MIB_TXB_ID; + reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port)); + reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16; + stats->tx_bytes = reg; + + id = ADM6996_MIB_RXB_ID; + reg = r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port)); + reg += r16(priv, adm6996_mibs[id].offset + ADM_OFFSET_PORT(port) + 1) << 16; + stats->rx_bytes = reg; + + mutex_unlock(&priv->mib_lock); + + return 0; +} + +static struct switch_attr adm6996_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLANs", + .set = adm6996_set_enable_vlan, + .get = adm6996_get_enable_vlan, + }, +#ifdef DEBUG + { + .type = SWITCH_TYPE_INT, + .name = "addr", + .description = + "Direct register access: set register address (0 - 1023)", + .set = adm6996_set_addr, + .get = adm6996_get_addr, + }, + { + .type = SWITCH_TYPE_INT, + .name = "data", + .description = + "Direct register access: read/write to register (0 - 65535)", + .set = adm6996_set_data, + .get = adm6996_get_data, + }, +#endif /* def DEBUG */ +}; + +static struct switch_attr adm6996_port[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = adm6996_sw_get_port_mib, + }, +}; + +static struct switch_attr adm6996_vlan[] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID", + .set = adm6996_set_vid, + .get = adm6996_get_vid, + }, +}; + +static struct switch_dev_ops adm6996_ops = { + .attr_global = { + .attr = adm6996_globals, + .n_attr = ARRAY_SIZE(adm6996_globals), + }, + .attr_port = { + .attr = adm6996_port, + .n_attr = ARRAY_SIZE(adm6996_port), + }, + .attr_vlan = { + .attr = adm6996_vlan, + .n_attr = ARRAY_SIZE(adm6996_vlan), + }, + .get_port_pvid = adm6996_get_pvid, + .set_port_pvid = adm6996_set_pvid, + .get_vlan_ports = adm6996_get_ports, + .set_vlan_ports = adm6996_set_ports, + .apply_config = adm6996_hw_apply, + .reset_switch = adm6996_reset_switch, + .get_port_link = adm6996_get_port_link, + .get_port_stats = adm6996_get_port_stats, +}; + +static int adm6996_switch_init(struct adm6996_priv *priv, const char *alias, struct net_device *netdev) +{ + struct switch_dev *swdev; + u16 test, old; + + if (!priv->model) { + /* Detect type of chip */ + old = r16(priv, ADM_VID_CHECK); + test = old ^ (1 << 12); + w16(priv, ADM_VID_CHECK, test); + test ^= r16(priv, ADM_VID_CHECK); + if (test & (1 << 12)) { + /* + * Bit 12 of this register is read-only. + * This is the FC model. + */ + priv->model = ADM6996FC; + } else { + /* Bit 12 is read-write. This is the M model. */ + priv->model = ADM6996M; + w16(priv, ADM_VID_CHECK, old); + } + } + + swdev = &priv->dev; + swdev->name = (adm6996_model_name[priv->model]); + swdev->cpu_port = ADM_CPU_PORT; + swdev->ports = ADM_NUM_PORTS; + swdev->vlans = ADM_NUM_VLANS; + swdev->ops = &adm6996_ops; + swdev->alias = alias; + + /* The ADM6996L connected through GPIOs does not support any switch + status calls */ + if (priv->model == ADM6996L) { + adm6996_ops.attr_port.n_attr = 0; + adm6996_ops.get_port_link = NULL; + } + + pr_info ("%s: %s model PHY found.\n", alias, swdev->name); + + mutex_lock(&priv->reg_mutex); + adm6996_perform_reset (priv); + mutex_unlock(&priv->reg_mutex); + + if (priv->model == ADM6996M || priv->model == ADM6996L) { + return register_switch(swdev, netdev); + } + + return -ENODEV; +} + +static int adm6996_config_init(struct phy_device *pdev) +{ + struct adm6996_priv *priv; + int ret; + + linkmode_zero(pdev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); + linkmode_copy(pdev->advertising, pdev->supported); + + if (pdev->mdio.addr != 0) { + pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n" + , pdev->attached_dev->name, pdev->mdio.addr); + return 0; + } + + priv = devm_kzalloc(&pdev->mdio.dev, sizeof(struct adm6996_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + priv->priv = pdev; + priv->read = adm6996_read_mii_reg; + priv->write = adm6996_write_mii_reg; + + ret = adm6996_switch_init(priv, pdev->attached_dev->name, pdev->attached_dev); + if (ret < 0) + return ret; + + pdev->priv = priv; + + return 0; +} + +/* + * Warning: phydev->priv is NULL if phydev->mdio.addr != 0 + */ +static int adm6996_read_status(struct phy_device *phydev) +{ + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +/* + * Warning: phydev->priv is NULL if phydev->mdio.addr != 0 + */ +static int adm6996_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int adm6996_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u16 reg; + + /* Our custom registers are at PHY addresses 0-10. Claim those. */ + if (dev->mdio.addr > 10) + return 0; + + /* look for the switch on the bus */ + reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; + if (reg != ADM_SIG0_VAL) + return 0; + + reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; + if (reg != ADM_SIG1_VAL) + return 0; + + dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL; + + return 0; +} + +static int adm6996_probe(struct phy_device *pdev) +{ + return 0; +} + +static void adm6996_remove(struct phy_device *pdev) +{ + struct adm6996_priv *priv = phy_to_adm(pdev); + + if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) + unregister_switch(&priv->dev); +} + +static int adm6996_soft_reset(struct phy_device *phydev) +{ + /* we don't need an extra reset */ + return 0; +} + +static struct phy_driver adm6996_phy_driver = { + .name = "Infineon ADM6996", + .phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = adm6996_probe, + .remove = adm6996_remove, + .config_init = &adm6996_config_init, + .config_aneg = &adm6996_config_aneg, + .read_status = &adm6996_read_status, + .soft_reset = adm6996_soft_reset, +}; + +static int adm6996_gpio_probe(struct platform_device *pdev) +{ + struct adm6996_gpio_platform_data *pdata = pdev->dev.platform_data; + struct adm6996_priv *priv; + int ret; + + if (!pdata) + return -EINVAL; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct adm6996_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + + priv->eecs = pdata->eecs; + priv->eedi = pdata->eedi; + priv->eesk = pdata->eesk; + + priv->model = pdata->model; + priv->read = adm6996_read_gpio_reg; + priv->write = adm6996_write_gpio_reg; + + ret = devm_gpio_request(&pdev->dev, priv->eecs, "adm_eecs"); + if (ret) + return ret; + ret = devm_gpio_request(&pdev->dev, priv->eedi, "adm_eedi"); + if (ret) + return ret; + ret = devm_gpio_request(&pdev->dev, priv->eesk, "adm_eesk"); + if (ret) + return ret; + + ret = adm6996_switch_init(priv, dev_name(&pdev->dev), NULL); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int adm6996_gpio_remove(struct platform_device *pdev) +{ + struct adm6996_priv *priv = platform_get_drvdata(pdev); + + if (priv && (priv->model == ADM6996M || priv->model == ADM6996L)) + unregister_switch(&priv->dev); + + return 0; +} + +static struct platform_driver adm6996_gpio_driver = { + .probe = adm6996_gpio_probe, + .remove = adm6996_gpio_remove, + .driver = { + .name = "adm6996_gpio", + }, +}; + +static int __init adm6996_init(void) +{ + int err; + + phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup); + err = phy_driver_register(&adm6996_phy_driver, THIS_MODULE); + if (err) + return err; + + err = platform_driver_register(&adm6996_gpio_driver); + if (err) + phy_driver_unregister(&adm6996_phy_driver); + + return err; +} + +static void __exit adm6996_exit(void) +{ + platform_driver_unregister(&adm6996_gpio_driver); + phy_driver_unregister(&adm6996_phy_driver); +} + +module_init(adm6996_init); +module_exit(adm6996_exit); diff --git a/ipq806x/files-5.4/drivers/net/phy/adm6996.h b/ipq806x/files-5.4/drivers/net/phy/adm6996.h new file mode 100644 index 0000000..6fd460a --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/adm6996.h @@ -0,0 +1,186 @@ +/* + * ADM6996 switch driver + * + * Copyright (c) 2008 Felix Fietkau + * Copyright (c) 2010,2011 Peter Lebbing + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#ifndef __ADM6996_H +#define __ADM6996_H + +/* + * ADM_PHY_PORTS: Number of ports with a PHY. + * We only control ports 0 to 3, because if 4 is connected, it is most likely + * not connected to the switch but to a separate MII and MAC for the WAN port. + */ +#define ADM_PHY_PORTS 4 +#define ADM_NUM_PORTS 6 +#define ADM_CPU_PORT 5 + +#define ADM_NUM_VLANS 16 +#define ADM_VLAN_MAX_ID 4094 + +enum admreg { + ADM_EEPROM_BASE = 0x0, + ADM_P0_CFG = ADM_EEPROM_BASE + 1, + ADM_P1_CFG = ADM_EEPROM_BASE + 3, + ADM_P2_CFG = ADM_EEPROM_BASE + 5, + ADM_P3_CFG = ADM_EEPROM_BASE + 7, + ADM_P4_CFG = ADM_EEPROM_BASE + 8, + ADM_P5_CFG = ADM_EEPROM_BASE + 9, + ADM_SYSC0 = ADM_EEPROM_BASE + 0xa, + ADM_VLAN_PRIOMAP = ADM_EEPROM_BASE + 0xe, + ADM_SYSC3 = ADM_EEPROM_BASE + 0x11, + /* Input Force No Tag Enable */ + ADM_IFNTE = ADM_EEPROM_BASE + 0x20, + ADM_VID_CHECK = ADM_EEPROM_BASE + 0x26, + ADM_P0_PVID = ADM_EEPROM_BASE + 0x28, + ADM_P1_PVID = ADM_EEPROM_BASE + 0x29, + /* Output Tag Bypass Enable and P2 PVID */ + ADM_OTBE_P2_PVID = ADM_EEPROM_BASE + 0x2a, + ADM_P3_P4_PVID = ADM_EEPROM_BASE + 0x2b, + ADM_P5_PVID = ADM_EEPROM_BASE + 0x2c, + ADM_EEPROM_EXT_BASE = 0x40, +#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n)) +#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n)) +#define ADM_VLAN_MAP(n) (ADM_EEPROM_BASE + 0x13 + n) + ADM_COUNTER_BASE = 0xa0, + ADM_SIG0 = ADM_COUNTER_BASE + 0, + ADM_SIG1 = ADM_COUNTER_BASE + 1, + ADM_PS0 = ADM_COUNTER_BASE + 2, + ADM_PS1 = ADM_COUNTER_BASE + 3, + ADM_PS2 = ADM_COUNTER_BASE + 4, + ADM_CL0 = ADM_COUNTER_BASE + 8, /* RxPacket */ + ADM_CL6 = ADM_COUNTER_BASE + 0x1a, /* RxByte */ + ADM_CL12 = ADM_COUNTER_BASE + 0x2c, /* TxPacket */ + ADM_CL18 = ADM_COUNTER_BASE + 0x3e, /* TxByte */ + ADM_CL24 = ADM_COUNTER_BASE + 0x50, /* Coll */ + ADM_CL30 = ADM_COUNTER_BASE + 0x62, /* Err */ +#define ADM_OFFSET_PORT(n) ((n * 4) - (n / 4) * 2 - (n / 5) * 2) + ADM_PHY_BASE = 0x200, +#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n)) +}; + +/* Chip identification patterns */ +#define ADM_SIG0_MASK 0xffff +#define ADM_SIG0_VAL 0x1023 +#define ADM_SIG1_MASK 0xffff +#define ADM_SIG1_VAL 0x0007 + +enum { + ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */ + ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */ + ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */ + ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */ + ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */ + ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */ + ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */ + ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */ + ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */ + ADM_PHYCFG_INIT = ( + ADM_PHYCFG_RST | + ADM_PHYCFG_SPEED_100 | + ADM_PHYCFG_ANEN | + ADM_PHYCFG_ANEN_RST + ) +}; + +enum { + ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */ + ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */ + ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */ + ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */ + ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */ + ADM_PORTCFG_PD = (1 << 5), /* Port disable */ + ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority + * 1 = TOS based priority */ + ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */ + ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */ + ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */ + ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */ + ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */ + + ADM_PORTCFG_INIT = ( + ADM_PORTCFG_FC | + ADM_PORTCFG_AN | + ADM_PORTCFG_SPEED_100 | + ADM_PORTCFG_DPLX | + ADM_PORTCFG_CAM + ), + ADM_PORTCFG_CPU = ( + ADM_PORTCFG_FC | + ADM_PORTCFG_SPEED_100 | + ADM_PORTCFG_OT | + ADM_PORTCFG_DPLX + ), +}; + +#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8) +#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10) +#define ADM_PORTCFG_PVID_MASK (0xf << 10) + +#define ADM_IFNTE_MASK (0x3f << 9) +#define ADM_VID_CHECK_MASK (0x3f << 6) + +#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8) +#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) +#define ADM_P2_PVID_MASK 0xff + +#define ADM_OTBE(n) (((n) & 0x3f) << 8) +#define ADM_OTBE_MASK (0x3f << 8) + +/* ADM_SYSC0 */ +enum { + ADM_NTTE = (1 << 2), /* New Tag Transmit Enable */ + ADM_RVID1 = (1 << 8) /* Replace VLAN ID 1 */ +}; + +/* Tag Based VLAN in ADM_SYSC3 */ +#define ADM_MAC_CLONE BIT(4) +#define ADM_TBV BIT(5) + +static const u8 adm_portcfg[] = { + [0] = ADM_P0_CFG, + [1] = ADM_P1_CFG, + [2] = ADM_P2_CFG, + [3] = ADM_P3_CFG, + [4] = ADM_P4_CFG, + [5] = ADM_P5_CFG, +}; + +/* Fields in ADM_VLAN_FILT_L(x) */ +#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12) +#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6) +#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0) +#define ADM_VLAN_FILT_MEMBER_MASK 0x3f +/* Fields in ADM_VLAN_FILT_H(x) */ +#define ADM_VLAN_FILT_VALID (1 << 15) +#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0) + +/* Convert ports to a form for ADM6996L VLAN map */ +#define ADM_VLAN_FILT(ports) ((ports & 0x01) | ((ports & 0x02) << 1) | \ + ((ports & 0x04) << 2) | ((ports & 0x08) << 3) | \ + ((ports & 0x10) << 3) | ((ports & 0x20) << 3)) + +/* Port status register */ +enum { + ADM_PS_LS = (1 << 0), /* Link status */ + ADM_PS_SS = (1 << 1), /* Speed status */ + ADM_PS_DS = (1 << 2), /* Duplex status */ + ADM_PS_FCS = (1 << 3) /* Flow control status */ +}; + +/* + * Split the register address in phy id and register + * it will get combined again by the mdio bus op + */ +#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) + +#endif diff --git a/ipq806x/files-5.4/drivers/net/phy/ar8216.c b/ipq806x/files-5.4/drivers/net/phy/ar8216.c new file mode 100644 index 0000000..dbcb1c4 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/ar8216.c @@ -0,0 +1,2925 @@ +/* + * ar8216.c: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * Copyright (C) 2011-2012 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar8216.h" + +extern const struct ar8xxx_chip ar8327_chip; +extern const struct ar8xxx_chip ar8337_chip; + +#define MIB_DESC_BASIC(_s , _o, _n) \ + { \ + .size = (_s), \ + .offset = (_o), \ + .name = (_n), \ + .type = AR8XXX_MIB_BASIC, \ + } + +#define MIB_DESC_EXT(_s , _o, _n) \ + { \ + .size = (_s), \ + .offset = (_o), \ + .name = (_n), \ + .type = AR8XXX_MIB_EXTENDED, \ + } + +static const struct ar8xxx_mib_desc ar8216_mibs[] = { + MIB_DESC_EXT(1, AR8216_STATS_RXBROAD, "RxBroad"), + MIB_DESC_EXT(1, AR8216_STATS_RXPAUSE, "RxPause"), + MIB_DESC_EXT(1, AR8216_STATS_RXMULTI, "RxMulti"), + MIB_DESC_EXT(1, AR8216_STATS_RXFCSERR, "RxFcsErr"), + MIB_DESC_EXT(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"), + MIB_DESC_EXT(1, AR8216_STATS_RXRUNT, "RxRunt"), + MIB_DESC_EXT(1, AR8216_STATS_RXFRAGMENT, "RxFragment"), + MIB_DESC_EXT(1, AR8216_STATS_RX64BYTE, "Rx64Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX128BYTE, "Rx128Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX256BYTE, "Rx256Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX512BYTE, "Rx512Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"), + MIB_DESC_EXT(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"), + MIB_DESC_EXT(1, AR8216_STATS_RXTOOLONG, "RxTooLong"), + MIB_DESC_BASIC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"), + MIB_DESC_EXT(2, AR8216_STATS_RXBADBYTE, "RxBadByte"), + MIB_DESC_EXT(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"), + MIB_DESC_EXT(1, AR8216_STATS_FILTERED, "Filtered"), + MIB_DESC_EXT(1, AR8216_STATS_TXBROAD, "TxBroad"), + MIB_DESC_EXT(1, AR8216_STATS_TXPAUSE, "TxPause"), + MIB_DESC_EXT(1, AR8216_STATS_TXMULTI, "TxMulti"), + MIB_DESC_EXT(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"), + MIB_DESC_EXT(1, AR8216_STATS_TX64BYTE, "Tx64Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX128BYTE, "Tx128Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX256BYTE, "Tx256Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX512BYTE, "Tx512Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"), + MIB_DESC_EXT(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"), + MIB_DESC_EXT(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"), + MIB_DESC_BASIC(2, AR8216_STATS_TXBYTE, "TxByte"), + MIB_DESC_EXT(1, AR8216_STATS_TXCOLLISION, "TxCollision"), + MIB_DESC_EXT(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"), + MIB_DESC_EXT(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"), + MIB_DESC_EXT(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"), + MIB_DESC_EXT(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"), + MIB_DESC_EXT(1, AR8216_STATS_TXDEFER, "TxDefer"), + MIB_DESC_EXT(1, AR8216_STATS_TXLATECOL, "TxLateCol"), +}; + +const struct ar8xxx_mib_desc ar8236_mibs[39] = { + MIB_DESC_EXT(1, AR8236_STATS_RXBROAD, "RxBroad"), + MIB_DESC_EXT(1, AR8236_STATS_RXPAUSE, "RxPause"), + MIB_DESC_EXT(1, AR8236_STATS_RXMULTI, "RxMulti"), + MIB_DESC_EXT(1, AR8236_STATS_RXFCSERR, "RxFcsErr"), + MIB_DESC_EXT(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"), + MIB_DESC_EXT(1, AR8236_STATS_RXRUNT, "RxRunt"), + MIB_DESC_EXT(1, AR8236_STATS_RXFRAGMENT, "RxFragment"), + MIB_DESC_EXT(1, AR8236_STATS_RX64BYTE, "Rx64Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX128BYTE, "Rx128Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX256BYTE, "Rx256Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX512BYTE, "Rx512Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"), + MIB_DESC_EXT(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"), + MIB_DESC_EXT(1, AR8236_STATS_RXTOOLONG, "RxTooLong"), + MIB_DESC_BASIC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"), + MIB_DESC_EXT(2, AR8236_STATS_RXBADBYTE, "RxBadByte"), + MIB_DESC_EXT(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"), + MIB_DESC_EXT(1, AR8236_STATS_FILTERED, "Filtered"), + MIB_DESC_EXT(1, AR8236_STATS_TXBROAD, "TxBroad"), + MIB_DESC_EXT(1, AR8236_STATS_TXPAUSE, "TxPause"), + MIB_DESC_EXT(1, AR8236_STATS_TXMULTI, "TxMulti"), + MIB_DESC_EXT(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"), + MIB_DESC_EXT(1, AR8236_STATS_TX64BYTE, "Tx64Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX128BYTE, "Tx128Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX256BYTE, "Tx256Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX512BYTE, "Tx512Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"), + MIB_DESC_EXT(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"), + MIB_DESC_EXT(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"), + MIB_DESC_BASIC(2, AR8236_STATS_TXBYTE, "TxByte"), + MIB_DESC_EXT(1, AR8236_STATS_TXCOLLISION, "TxCollision"), + MIB_DESC_EXT(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"), + MIB_DESC_EXT(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"), + MIB_DESC_EXT(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"), + MIB_DESC_EXT(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"), + MIB_DESC_EXT(1, AR8236_STATS_TXDEFER, "TxDefer"), + MIB_DESC_EXT(1, AR8236_STATS_TXLATECOL, "TxLateCol"), +}; + +static DEFINE_MUTEX(ar8xxx_dev_list_lock); +static LIST_HEAD(ar8xxx_dev_list); + +static void +ar8xxx_mib_start(struct ar8xxx_priv *priv); +static void +ar8xxx_mib_stop(struct ar8xxx_priv *priv); + +/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */ +static int +ar8xxx_phy_poll_reset(struct mii_bus *bus) +{ + unsigned int sleep_msecs = 20; + int ret, elapsed, i; + + for (elapsed = sleep_msecs; elapsed <= 600; + elapsed += sleep_msecs) { + msleep(sleep_msecs); + for (i = 0; i < AR8XXX_NUM_PHYS; i++) { + ret = mdiobus_read(bus, i, MII_BMCR); + if (ret < 0) + return ret; + if (ret & BMCR_RESET) + break; + if (i == AR8XXX_NUM_PHYS - 1) { + usleep_range(1000, 2000); + return 0; + } + } + } + return -ETIMEDOUT; +} + +static int +ar8xxx_phy_check_aneg(struct phy_device *phydev) +{ + int ret; + + if (phydev->autoneg != AUTONEG_ENABLE) + return 0; + /* + * BMCR_ANENABLE might have been cleared + * by phy_init_hw in certain kernel versions + * therefore check for it + */ + ret = phy_read(phydev, MII_BMCR); + if (ret < 0) + return ret; + if (ret & BMCR_ANENABLE) + return 0; + + dev_info(&phydev->mdio.dev, "ANEG disabled, re-enabling ...\n"); + ret |= BMCR_ANENABLE | BMCR_ANRESTART; + return phy_write(phydev, MII_BMCR, ret); +} + +void +ar8xxx_phy_init(struct ar8xxx_priv *priv) +{ + int i; + struct mii_bus *bus; + + bus = priv->sw_mii_bus ?: priv->mii_bus; + for (i = 0; i < AR8XXX_NUM_PHYS; i++) { + if (priv->chip->phy_fixup) + priv->chip->phy_fixup(priv, i); + + /* initialize the port itself */ + mdiobus_write(bus, i, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + if (ar8xxx_has_gige(priv)) + mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); + mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); + } + + ar8xxx_phy_poll_reset(bus); +} + +u32 +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum) +{ + struct mii_bus *bus = priv->mii_bus; + u16 lo, hi; + + lo = bus->read(bus, phy_id, regnum); + hi = bus->read(bus, phy_id, regnum + 1); + + return (hi << 16) | lo; +} + +void +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 lo, hi; + + lo = val & 0xffff; + hi = (u16) (val >> 16); + + if (priv->chip->mii_lo_first) + { + bus->write(bus, phy_id, regnum, lo); + bus->write(bus, phy_id, regnum + 1, hi); + } else { + bus->write(bus, phy_id, regnum + 1, hi); + bus->write(bus, phy_id, regnum, lo); + } +} + +u32 +ar8xxx_read(struct ar8xxx_priv *priv, int reg) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + u32 val; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + val = ar8xxx_mii_read32(priv, 0x10 | r2, r1); + + mutex_unlock(&bus->mdio_lock); + + return val; +} + +void +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + ar8xxx_mii_write32(priv, 0x10 | r2, r1, val); + + mutex_unlock(&bus->mdio_lock); +} + +u32 +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r1, r2, page; + u32 ret; + + split_addr((u32) reg, &r1, &r2, &page); + + mutex_lock(&bus->mdio_lock); + + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1); + ret &= ~mask; + ret |= val; + ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret); + + mutex_unlock(&bus->mdio_lock); + + return ret; +} +void +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 *dbg_data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); + *dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA); + mutex_unlock(&bus->mdio_lock); +} + +void +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 dbg_data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); + bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); + mutex_unlock(&bus->mdio_lock); +} + +static inline void +ar8xxx_phy_mmd_prep(struct mii_bus *bus, int phy_addr, u16 addr, u16 reg) +{ + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); + bus->write(bus, phy_addr, MII_ATH_MMD_DATA, reg); + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr | 0x4000); +} + +void +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data) +{ + struct mii_bus *bus = priv->mii_bus; + + mutex_lock(&bus->mdio_lock); + ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg); + bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data); + mutex_unlock(&bus->mdio_lock); +} + +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg) +{ + struct mii_bus *bus = priv->mii_bus; + u16 data; + + mutex_lock(&bus->mdio_lock); + ar8xxx_phy_mmd_prep(bus, phy_addr, addr, reg); + data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA); + mutex_unlock(&bus->mdio_lock); + + return data; +} + +static int +ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val, + unsigned timeout) +{ + int i; + + for (i = 0; i < timeout; i++) { + u32 t; + + t = ar8xxx_read(priv, reg); + if ((t & mask) == val) + return 0; + + usleep_range(1000, 2000); + cond_resched(); + } + + return -ETIMEDOUT; +} + +static int +ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op) +{ + unsigned mib_func = priv->chip->mib_func; + int ret; + + lockdep_assert_held(&priv->mib_lock); + + /* Capture the hardware statistics for all ports */ + ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S)); + + /* Wait for the capturing to complete. */ + ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10); + if (ret) + goto out; + + ret = 0; + +out: + return ret; +} + +static int +ar8xxx_mib_capture(struct ar8xxx_priv *priv) +{ + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE); +} + +static int +ar8xxx_mib_flush(struct ar8xxx_priv *priv) +{ + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH); +} + +static void +ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush) +{ + unsigned int base; + u64 *mib_stats; + int i; + + WARN_ON(port >= priv->dev.ports); + + lockdep_assert_held(&priv->mib_lock); + + base = priv->chip->reg_port_stats_start + + priv->chip->reg_port_stats_length * port; + + mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; + for (i = 0; i < priv->chip->num_mibs; i++) { + const struct ar8xxx_mib_desc *mib; + u64 t; + + mib = &priv->chip->mib_decs[i]; + if (mib->type > priv->mib_type) + continue; + t = ar8xxx_read(priv, base + mib->offset); + if (mib->size == 2) { + u64 hi; + + hi = ar8xxx_read(priv, base + mib->offset + 4); + t |= hi << 32; + } + + if (flush) + mib_stats[i] = 0; + else + mib_stats[i] += t; + cond_resched(); + } +} + +static void +ar8216_read_port_link(struct ar8xxx_priv *priv, int port, + struct switch_port_link *link) +{ + u32 status; + u32 speed; + + memset(link, '\0', sizeof(*link)); + + status = priv->chip->read_port_status(priv, port); + + link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO); + if (link->aneg) { + link->link = !!(status & AR8216_PORT_STATUS_LINK_UP); + } else { + link->link = true; + + if (priv->get_port_link) { + int err; + + err = priv->get_port_link(port); + if (err >= 0) + link->link = !!err; + } + } + + if (!link->link) + return; + + link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX); + link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW); + link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW); + + if (link->aneg && link->duplex && priv->chip->read_port_eee_status) + link->eee = priv->chip->read_port_eee_status(priv, port); + + speed = (status & AR8216_PORT_STATUS_SPEED) >> + AR8216_PORT_STATUS_SPEED_S; + + switch (speed) { + case AR8216_PORT_SPEED_10M: + link->speed = SWITCH_PORT_SPEED_10; + break; + case AR8216_PORT_SPEED_100M: + link->speed = SWITCH_PORT_SPEED_100; + break; + case AR8216_PORT_SPEED_1000M: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } +} + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + +static struct sk_buff * +ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb) +{ + struct ar8xxx_priv *priv = dev->phy_ptr; + unsigned char *buf; + + if (unlikely(!priv)) + goto error; + + if (!priv->vlan) + goto send; + + if (unlikely(skb_headroom(skb) < 2)) { + if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0) + goto error; + } + + buf = skb_push(skb, 2); + buf[0] = 0x10; + buf[1] = 0x80; + +send: + return skb; + +error: + dev_kfree_skb_any(skb); + return NULL; +} + +static void +ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) +{ + struct ar8xxx_priv *priv; + unsigned char *buf; + int port, vlan; + + priv = dev->phy_ptr; + if (!priv) + return; + + /* don't strip the header if vlan mode is disabled */ + if (!priv->vlan) + return; + + /* strip header, get vlan id */ + buf = skb->data; + skb_pull(skb, 2); + + /* check for vlan header presence */ + if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) + return; + + port = buf[0] & 0x7; + + /* no need to fix up packets coming from a tagged source */ + if (priv->vlan_tagged & (1 << port)) + return; + + /* lookup port vid from local table, the switch passes an invalid vlan id */ + vlan = priv->vlan_id[priv->pvid[port]]; + + buf[14 + 2] &= 0xf0; + buf[14 + 2] |= vlan >> 8; + buf[15 + 2] = vlan & 0xff; +} + +#endif + +int +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) +{ + int timeout = 20; + u32 t = 0; + + while (1) { + t = ar8xxx_read(priv, reg); + if ((t & mask) == val) + return 0; + + if (timeout-- <= 0) + break; + + udelay(10); + cond_resched(); + } + + pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n", + (unsigned int) reg, t, mask, val); + return -ETIMEDOUT; +} + +static void +ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) +{ + if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0)) + return; + if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) { + val &= AR8216_VTUDATA_MEMBER; + val |= AR8216_VTUDATA_VALID; + ar8xxx_write(priv, AR8216_REG_VTU_DATA, val); + } + op |= AR8216_VTU_ACTIVE; + ar8xxx_write(priv, AR8216_REG_VTU, op); +} + +static void +ar8216_vtu_flush(struct ar8xxx_priv *priv) +{ + ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0); +} + +static void +ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) +{ + u32 op; + + op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S); + ar8216_vtu_op(priv, op, port_mask); +} + +static int +ar8216_atu_flush(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); + if (!ret) + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH | + AR8216_ATU_ACTIVE); + + return ret; +} + +static int +ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port) +{ + u32 t; + int ret; + + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); + if (!ret) { + t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT; + t |= AR8216_ATU_ACTIVE; + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t); + } + + return ret; +} + +static u32 +ar8216_read_port_status(struct ar8xxx_priv *priv, int port) +{ + return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port)); +} + +static void +__ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members, + bool ath_hdr_en) +{ + u32 header; + u32 egress, ingress; + u32 pvid; + + if (priv->vlan) { + pvid = priv->vlan_id[priv->pvid[port]]; + if (priv->vlan_tagged & (1 << port)) + egress = AR8216_OUT_ADD_VLAN; + else + egress = AR8216_OUT_STRIP_VLAN; + ingress = AR8216_IN_SECURE; + } else { + pvid = port; + egress = AR8216_OUT_KEEP; + ingress = AR8216_IN_PORT_ONLY; + } + + header = ath_hdr_en ? AR8216_PORT_CTRL_HEADER : 0; + + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, + AR8216_PORT_CTRL_LEARN | header | + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port), + AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE | + AR8216_PORT_VLAN_DEFAULT_ID, + (members << AR8216_PORT_VLAN_DEST_PORTS_S) | + (ingress << AR8216_PORT_VLAN_MODE_S) | + (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S)); +} + +static void +ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + return __ar8216_setup_port(priv, port, members, + chip_is_ar8216(priv) && priv->vlan && + port == AR8216_PORT_CPU); +} + +static int +ar8216_hw_init(struct ar8xxx_priv *priv) +{ + if (priv->initialized) + return 0; + + ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); + ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); + + ar8xxx_phy_init(priv); + + priv->initialized = true; + return 0; +} + +static void +ar8216_init_globals(struct ar8xxx_priv *priv) +{ + /* standard atheros magic */ + ar8xxx_write(priv, 0x38, 0xc000050e); + + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8216_GCTRL_MTU, 1518 + 8 + 2); +} + +static void +__ar8216_init_port(struct ar8xxx_priv *priv, int port, + bool cpu_ge, bool flow_en) +{ + /* Enable port learning and tx */ + ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | + (4 << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0); + + if (port == AR8216_PORT_CPU) { + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), + AR8216_PORT_STATUS_LINK_UP | + (cpu_ge ? AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) | + AR8216_PORT_STATUS_TXMAC | + AR8216_PORT_STATUS_RXMAC | + (flow_en ? AR8216_PORT_STATUS_RXFLOW : 0) | + (flow_en ? AR8216_PORT_STATUS_TXFLOW : 0) | + AR8216_PORT_STATUS_DUPLEX); + } else { + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), + AR8216_PORT_STATUS_LINK_AUTO); + } +} + +static void +ar8216_init_port(struct ar8xxx_priv *priv, int port) +{ + __ar8216_init_port(priv, port, ar8xxx_has_gige(priv), + chip_is_ar8316(priv)); +} + +static void +ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) +{ + int timeout = 20; + + while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) { + udelay(10); + cond_resched(); + } + + if (!timeout) + pr_err("ar8216: timeout waiting for atu to become ready\n"); +} + +static void ar8216_get_arl_entry(struct ar8xxx_priv *priv, + struct arl_entry *a, u32 *status, enum arl_op op) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r2, page; + u16 r1_func0, r1_func1, r1_func2; + u32 t, val0, val1, val2; + + split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page); + r2 |= 0x10; + + r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e; + r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e; + + switch (op) { + case AR8XXX_ARL_INITIALIZE: + /* all ATU registers are on the same page + * therefore set page only once + */ + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ar8216_wait_atu_ready(priv, r2, r1_func0); + + ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT); + ar8xxx_mii_write32(priv, r2, r1_func1, 0); + ar8xxx_mii_write32(priv, r2, r1_func2, 0); + break; + case AR8XXX_ARL_GET_NEXT: + t = ar8xxx_mii_read32(priv, r2, r1_func0); + t |= AR8216_ATU_ACTIVE; + ar8xxx_mii_write32(priv, r2, r1_func0, t); + ar8216_wait_atu_ready(priv, r2, r1_func0); + + val0 = ar8xxx_mii_read32(priv, r2, r1_func0); + val1 = ar8xxx_mii_read32(priv, r2, r1_func1); + val2 = ar8xxx_mii_read32(priv, r2, r1_func2); + + *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S; + if (!*status) + break; + + a->portmap = (val2 & AR8216_ATU_PORTS) >> AR8216_ATU_PORTS_S; + a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S; + a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S; + a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S; + a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S; + a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S; + a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S; + break; + } +} + +static int +ar8216_phy_read(struct ar8xxx_priv *priv, int addr, int regnum) +{ + u32 t, val = 0xffff; + int err; + + if (addr >= AR8216_NUM_PORTS) + return 0xffff; + t = (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) | + (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) | + AR8216_MDIO_CTRL_MASTER_EN | + AR8216_MDIO_CTRL_BUSY | + AR8216_MDIO_CTRL_CMD_READ; + + ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t); + err = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL, + AR8216_MDIO_CTRL_BUSY, 0, 5); + if (!err) + val = ar8xxx_read(priv, AR8216_REG_MDIO_CTRL); + + return val & AR8216_MDIO_CTRL_DATA_M; +} + +static int +ar8216_phy_write(struct ar8xxx_priv *priv, int addr, int regnum, u16 val) +{ + u32 t; + int ret; + + if (addr >= AR8216_NUM_PORTS) + return -EINVAL; + + t = (addr << AR8216_MDIO_CTRL_PHY_ADDR_S) | + (regnum << AR8216_MDIO_CTRL_REG_ADDR_S) | + AR8216_MDIO_CTRL_MASTER_EN | + AR8216_MDIO_CTRL_BUSY | + AR8216_MDIO_CTRL_CMD_WRITE | + val; + + ar8xxx_write(priv, AR8216_REG_MDIO_CTRL, t); + ret = ar8xxx_reg_wait(priv, AR8216_REG_MDIO_CTRL, + AR8216_MDIO_CTRL_BUSY, 0, 5); + + return ret; +} + +static int +ar8229_hw_init(struct ar8xxx_priv *priv) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) + phy_interface_t phy_if_mode; +#else + int phy_if_mode; +#endif + + if (priv->initialized) + return 0; + + ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); + ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) + of_get_phy_mode(priv->pdev->of_node, &phy_if_mode); +#else + phy_if_mode = of_get_phy_mode(priv->pdev->of_node); +#endif + + if (phy_if_mode == PHY_INTERFACE_MODE_GMII) { + ar8xxx_write(priv, AR8229_REG_OPER_MODE0, + AR8229_OPER_MODE0_MAC_GMII_EN); + } else if (phy_if_mode == PHY_INTERFACE_MODE_MII) { + ar8xxx_write(priv, AR8229_REG_OPER_MODE0, + AR8229_OPER_MODE0_PHY_MII_EN); + } else { + pr_err("ar8229: unsupported mii mode\n"); + return -EINVAL; + } + + if (priv->port4_phy) { + ar8xxx_write(priv, AR8229_REG_OPER_MODE1, + AR8229_REG_OPER_MODE1_PHY4_MII_EN); + /* disable port5 to prevent mii conflict */ + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0); + } + + ar8xxx_phy_init(priv); + + priv->initialized = true; + return 0; +} + +static void +ar8229_init_globals(struct ar8xxx_priv *priv) +{ + + /* Enable CPU port, and disable mirror port */ + ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_EN | + (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + + /* Setup TAG priority mapping */ + ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50); + + /* Enable aging, MAC replacing */ + ar8xxx_write(priv, AR8216_REG_ATU_CTRL, + 0x2b /* 5 min age time */ | + AR8216_ATU_CTRL_AGE_EN | + AR8216_ATU_CTRL_LEARN_CHANGE); + + /* Enable ARP frame acknowledge */ + ar8xxx_reg_set(priv, AR8229_REG_QM_CTRL, + AR8229_QM_CTRL_ARP_EN); + + /* + * Enable Broadcast/unknown multicast and unicast frames + * transmitted to the CPU port. + */ + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, + AR8229_FLOOD_MASK_BC_DP(0) | + AR8229_FLOOD_MASK_MC_DP(0) | + AR8229_FLOOD_MASK_UC_DP(0)); + + /* setup MTU */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8236_GCTRL_MTU, AR8236_GCTRL_MTU); + + /* Enable MIB counters */ + ar8xxx_reg_set(priv, AR8216_REG_MIB_FUNC, + AR8236_MIB_EN); + + /* setup Service TAG */ + ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0); +} + +static void +ar8229_init_port(struct ar8xxx_priv *priv, int port) +{ + __ar8216_init_port(priv, port, true, true); +} + + +static int +ar7240sw_hw_init(struct ar8xxx_priv *priv) +{ + if (priv->initialized) + return 0; + + ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); + ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); + + priv->port4_phy = 1; + /* disable port5 to prevent mii conflict */ + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(5), 0); + + ar8xxx_phy_init(priv); + + priv->initialized = true; + return 0; +} + +static void +ar7240sw_init_globals(struct ar8xxx_priv *priv) +{ + + /* Enable CPU port, and disable mirror port */ + ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_EN | + (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + + /* Setup TAG priority mapping */ + ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50); + + /* Enable ARP frame acknowledge, aging, MAC replacing */ + ar8xxx_write(priv, AR8216_REG_ATU_CTRL, + AR8216_ATU_CTRL_RESERVED | + 0x2b /* 5 min age time */ | + AR8216_ATU_CTRL_AGE_EN | + AR8216_ATU_CTRL_ARP_EN | + AR8216_ATU_CTRL_LEARN_CHANGE); + + /* Enable Broadcast frames transmitted to the CPU */ + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, + AR8216_FM_CPU_BROADCAST_EN); + + /* setup MTU */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8216_GCTRL_MTU, + AR8216_GCTRL_MTU); + + /* setup Service TAG */ + ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0); +} + +static void +ar7240sw_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + return __ar8216_setup_port(priv, port, members, false); +} + +static void +ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + u32 egress, ingress; + u32 pvid; + + if (priv->vlan) { + pvid = priv->vlan_id[priv->pvid[port]]; + if (priv->vlan_tagged & (1 << port)) + egress = AR8216_OUT_ADD_VLAN; + else + egress = AR8216_OUT_STRIP_VLAN; + ingress = AR8216_IN_SECURE; + } else { + pvid = port; + egress = AR8216_OUT_KEEP; + ingress = AR8216_IN_PORT_ONLY; + } + + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, + AR8216_PORT_CTRL_LEARN | + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); + + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port), + AR8236_PORT_VLAN_DEFAULT_ID, + (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S)); + + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port), + AR8236_PORT_VLAN2_VLAN_MODE | + AR8236_PORT_VLAN2_MEMBER, + (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) | + (members << AR8236_PORT_VLAN2_MEMBER_S)); +} + +static void +ar8236_init_globals(struct ar8xxx_priv *priv) +{ + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8316_GCTRL_MTU, 9018 + 8 + 2); + + /* enable cpu port to receive arp frames */ + ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL, + AR8236_ATU_CTRL_RES); + + /* + * Enable Broadcast/unknown multicast and unicast frames + * transmitted to the CPU port. + */ + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, + AR8229_FLOOD_MASK_BC_DP(0) | + AR8229_FLOOD_MASK_MC_DP(0) | + AR8229_FLOOD_MASK_UC_DP(0)); + + /* Enable MIB counters */ + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | + AR8236_MIB_EN); +} + +static int +ar8316_hw_init(struct ar8xxx_priv *priv) +{ + u32 val, newval; + + val = ar8xxx_read(priv, AR8316_REG_POSTRIP); + + if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { + if (priv->port4_phy) { + /* value taken from Ubiquiti RouterStation Pro */ + newval = 0x81461bea; + pr_info("ar8316: Using port 4 as PHY\n"); + } else { + newval = 0x01261be2; + pr_info("ar8316: Using port 4 as switch port\n"); + } + } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) { + /* value taken from AVM Fritz!Box 7390 sources */ + newval = 0x010e5b71; + } else { + /* no known value for phy interface */ + pr_err("ar8316: unsupported mii mode: %d.\n", + priv->phy->interface); + return -EINVAL; + } + + if (val == newval) + goto out; + + ar8xxx_write(priv, AR8316_REG_POSTRIP, newval); + + if (priv->port4_phy && + priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { + /* work around for phy4 rgmii mode */ + ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c); + /* rx delay */ + ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e); + /* tx delay */ + ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47); + msleep(1000); + } + + ar8xxx_phy_init(priv); + +out: + priv->initialized = true; + return 0; +} + +static void +ar8316_init_globals(struct ar8xxx_priv *priv) +{ + /* standard atheros magic */ + ar8xxx_write(priv, 0x38, 0xc000050e); + + /* enable cpu port to receive multicast and broadcast frames */ + ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); + + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, + AR8316_GCTRL_MTU, 9018 + 8 + 2); + + /* Enable MIB counters */ + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | + AR8236_MIB_EN); +} + +int +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + priv->vlan = !!val->value.i; + return 0; +} + +int +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->vlan; + return 0; +} + + +int +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + /* make sure no invalid PVIDs get set */ + + if (vlan < 0 || vlan >= dev->vlans || + port < 0 || port >= AR8X16_MAX_PORTS) + return -EINVAL; + + priv->pvid[port] = vlan; + return 0; +} + +int +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (port < 0 || port >= AR8X16_MAX_PORTS) + return -EINVAL; + + *vlan = priv->pvid[port]; + return 0; +} + +static int +ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + priv->vlan_id[val->port_vlan] = val->value.i; + return 0; +} + +static int +ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->vlan_id[val->port_vlan]; + return 0; +} + +int +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + ar8216_read_port_link(priv, port, link); + return 0; +} + +static int +ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 ports; + int i; + + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + ports = priv->vlan_table[val->port_vlan]; + val->len = 0; + for (i = 0; i < dev->ports; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (priv->vlan_tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int +ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i, j; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + priv->vlan_tagged |= (1 << p->id); + } else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + + /* make sure that an untagged port does not + * appear in other vlans */ + for (j = 0; j < dev->vlans; j++) { + if (j == val->port_vlan) + continue; + priv->vlan_table[j] &= ~(1 << p->id); + } + } + + *vt |= 1 << p->id; + } + return 0; +} + +static void +ar8216_set_mirror_regs(struct ar8xxx_priv *priv) +{ + int port; + + /* reset all mirror registers */ + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_MIRROR_PORT, + (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + for (port = 0; port < AR8216_NUM_PORTS; port++) { + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_MIRROR_RX); + + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), + AR8216_PORT_CTRL_MIRROR_TX); + } + + /* now enable mirroring if necessary */ + if (priv->source_port >= AR8216_NUM_PORTS || + priv->monitor_port >= AR8216_NUM_PORTS || + priv->source_port == priv->monitor_port) { + return; + } + + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, + AR8216_GLOBAL_CPUPORT_MIRROR_PORT, + (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + + if (priv->mirror_rx) + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), + AR8216_PORT_CTRL_MIRROR_RX); + + if (priv->mirror_tx) + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), + AR8216_PORT_CTRL_MIRROR_TX); +} + +static inline u32 +ar8xxx_age_time_val(int age_time) +{ + return (age_time + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS / 2) / + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS; +} + +static inline void +ar8xxx_set_age_time(struct ar8xxx_priv *priv, int reg) +{ + u32 age_time = ar8xxx_age_time_val(priv->arl_age_time); + ar8xxx_rmw(priv, reg, AR8216_ATU_CTRL_AGE_TIME, age_time << AR8216_ATU_CTRL_AGE_TIME_S); +} + +int +ar8xxx_sw_hw_apply(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + u8 portmask[AR8X16_MAX_PORTS]; + int i, j; + + mutex_lock(&priv->reg_mutex); + /* flush all vlan translation unit entries */ + priv->chip->vtu_flush(priv); + + memset(portmask, 0, sizeof(portmask)); + if (!priv->init) { + /* calculate the port destination masks and load vlans + * into the vlan translation unit */ + for (j = 0; j < dev->vlans; j++) { + u8 vp = priv->vlan_table[j]; + + if (!vp) + continue; + + for (i = 0; i < dev->ports; i++) { + u8 mask = (1 << i); + if (vp & mask) + portmask[i] |= vp & ~mask; + } + + chip->vtu_load_vlan(priv, priv->vlan_id[j], + priv->vlan_table[j]); + } + } else { + /* vlan disabled: + * isolate all ports, but connect them to the cpu port */ + for (i = 0; i < dev->ports; i++) { + if (i == AR8216_PORT_CPU) + continue; + + portmask[i] = 1 << AR8216_PORT_CPU; + portmask[AR8216_PORT_CPU] |= (1 << i); + } + } + + /* update the port destination mask registers and tag settings */ + for (i = 0; i < dev->ports; i++) { + chip->setup_port(priv, i, portmask[i]); + } + + chip->set_mirror_regs(priv); + + /* set age time */ + if (chip->reg_arl_ctrl) + ar8xxx_set_age_time(priv, chip->reg_arl_ctrl); + + mutex_unlock(&priv->reg_mutex); + return 0; +} + +int +ar8xxx_sw_reset_switch(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + int i; + + mutex_lock(&priv->reg_mutex); + memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) - + offsetof(struct ar8xxx_priv, vlan)); + + for (i = 0; i < dev->vlans; i++) + priv->vlan_id[i] = i; + + /* Configure all ports */ + for (i = 0; i < dev->ports; i++) + chip->init_port(priv, i); + + priv->mirror_rx = false; + priv->mirror_tx = false; + priv->source_port = 0; + priv->monitor_port = 0; + priv->arl_age_time = AR8XXX_DEFAULT_ARL_AGE_TIME; + + chip->init_globals(priv); + chip->atu_flush(priv); + + mutex_unlock(&priv->reg_mutex); + + return chip->sw_hw_apply(dev); +} + +int +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + unsigned int len; + int ret; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + mutex_lock(&priv->mib_lock); + + len = priv->dev.ports * priv->chip->num_mibs * + sizeof(*priv->mib_stats); + memset(priv->mib_stats, '\0', len); + ret = ar8xxx_mib_flush(priv); + if (ret) + goto unlock; + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +int +ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + ar8xxx_mib_stop(priv); + priv->mib_poll_interval = val->value.i; + ar8xxx_mib_start(priv); + + return 0; +} + +int +ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + val->value.i = priv->mib_poll_interval; + return 0; +} + +int +ar8xxx_sw_set_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + priv->mib_type = val->value.i; + return 0; +} + +int +ar8xxx_sw_get_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + val->value.i = priv->mib_type; + return 0; +} + +int +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->mirror_rx = !!val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->mirror_rx; + return 0; +} + +int +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->mirror_tx = !!val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->mirror_tx; + return 0; +} + +int +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->monitor_port = val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->monitor_port; + return 0; +} + +int +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + priv->source_port = val->value.i; + priv->chip->set_mirror_regs(priv); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->source_port; + return 0; +} + +int +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port; + int ret; + + if (!ar8xxx_has_mib_counters(priv)) + return -EOPNOTSUPP; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + ret = ar8xxx_mib_capture(priv); + if (ret) + goto unlock; + + ar8xxx_mib_fetch_port_stat(priv, port, true); + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +static void +ar8xxx_byte_to_str(char *buf, int len, u64 byte) +{ + unsigned long b; + const char *unit; + + if (byte >= 0x40000000) { /* 1 GiB */ + b = byte * 10 / 0x40000000; + unit = "GiB"; + } else if (byte >= 0x100000) { /* 1 MiB */ + b = byte * 10 / 0x100000; + unit = "MiB"; + } else if (byte >= 0x400) { /* 1 KiB */ + b = byte * 10 / 0x400; + unit = "KiB"; + } else { + b = byte; + unit = "Byte"; + } + if (strcmp(unit, "Byte")) + snprintf(buf, len, "%lu.%lu %s", b / 10, b % 10, unit); + else + snprintf(buf, len, "%lu %s", b, unit); +} + +int +ar8xxx_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8xxx_chip *chip = priv->chip; + u64 *mib_stats, mib_data; + unsigned int port; + int ret; + char *buf = priv->buf; + char buf1[64]; + const char *mib_name; + int i, len = 0; + bool mib_stats_empty = true; + + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return -EOPNOTSUPP; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + ret = ar8xxx_mib_capture(priv); + if (ret) + goto unlock; + + ar8xxx_mib_fetch_port_stat(priv, port, false); + + len += snprintf(buf + len, sizeof(priv->buf) - len, + "MIB counters\n"); + + mib_stats = &priv->mib_stats[port * chip->num_mibs]; + for (i = 0; i < chip->num_mibs; i++) { + if (chip->mib_decs[i].type > priv->mib_type) + continue; + mib_name = chip->mib_decs[i].name; + mib_data = mib_stats[i]; + len += snprintf(buf + len, sizeof(priv->buf) - len, + "%-12s: %llu\n", mib_name, mib_data); + if ((!strcmp(mib_name, "TxByte") || + !strcmp(mib_name, "RxGoodByte")) && + mib_data >= 1024) { + ar8xxx_byte_to_str(buf1, sizeof(buf1), mib_data); + --len; /* discard newline at the end of buf */ + len += snprintf(buf + len, sizeof(priv->buf) - len, + " (%s)\n", buf1); + } + if (mib_stats_empty && mib_data) + mib_stats_empty = false; + } + + if (mib_stats_empty) + len = snprintf(buf, sizeof(priv->buf), "No MIB data"); + + val->value.s = buf; + val->len = len; + + ret = 0; + +unlock: + mutex_unlock(&priv->mib_lock); + return ret; +} + +int +ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int age_time = val->value.i; + u32 age_time_val; + + if (age_time < 0) + return -EINVAL; + + age_time_val = ar8xxx_age_time_val(age_time); + if (age_time_val == 0 || age_time_val > 0xffff) + return -EINVAL; + + priv->arl_age_time = age_time; + return 0; +} + +int +ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + val->value.i = priv->arl_age_time; + return 0; +} + +int +ar8xxx_sw_get_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + struct mii_bus *bus = priv->mii_bus; + const struct ar8xxx_chip *chip = priv->chip; + char *buf = priv->arl_buf; + int i, j, k, len = 0; + struct arl_entry *a, *a1; + u32 status; + + if (!chip->get_arl_entry) + return -EOPNOTSUPP; + + mutex_lock(&priv->reg_mutex); + mutex_lock(&bus->mdio_lock); + + chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE); + + for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) { + a = &priv->arl_table[i]; + duplicate: + chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT); + + if (!status) + break; + + /* avoid duplicates + * ARL table can include multiple valid entries + * per MAC, just with differing status codes + */ + for (j = 0; j < i; ++j) { + a1 = &priv->arl_table[j]; + if (!memcmp(a->mac, a1->mac, sizeof(a->mac))) { + /* ignore ports already seen in former entry */ + a->portmap &= ~a1->portmap; + if (!a->portmap) + goto duplicate; + } + } + } + + mutex_unlock(&bus->mdio_lock); + + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "address resolution table\n"); + + if (i == AR8XXX_NUM_ARL_RECORDS) + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "Too many entries found, displaying the first %d only!\n", + AR8XXX_NUM_ARL_RECORDS); + + for (j = 0; j < priv->dev.ports; ++j) { + for (k = 0; k < i; ++k) { + a = &priv->arl_table[k]; + if (!(a->portmap & BIT(j))) + continue; + len += snprintf(buf + len, sizeof(priv->arl_buf) - len, + "Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + j, + a->mac[5], a->mac[4], a->mac[3], + a->mac[2], a->mac[1], a->mac[0]); + } + } + + val->value.s = buf; + val->len = len; + + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int ret; + + mutex_lock(&priv->reg_mutex); + ret = priv->chip->atu_flush(priv); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +int +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port, ret; + + port = val->port_vlan; + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->reg_mutex); + ret = priv->chip->atu_flush_port(priv, port); + mutex_unlock(&priv->reg_mutex); + + return ret; +} + +int +ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u64 *mib_stats; + + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return -EOPNOTSUPP; + + if (!(priv->chip->mib_rxb_id || priv->chip->mib_txb_id)) + return -EOPNOTSUPP; + + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->mib_lock); + + mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; + + stats->tx_bytes = mib_stats[priv->chip->mib_txb_id]; + stats->rx_bytes = mib_stats[priv->chip->mib_rxb_id]; + + mutex_unlock(&priv->mib_lock); + return 0; +} + +static int +ar8xxx_phy_read(struct mii_bus *bus, int phy_addr, int reg_addr) +{ + struct ar8xxx_priv *priv = bus->priv; + return priv->chip->phy_read(priv, phy_addr, reg_addr); +} + +static int +ar8xxx_phy_write(struct mii_bus *bus, int phy_addr, int reg_addr, + u16 reg_val) +{ + struct ar8xxx_priv *priv = bus->priv; + return priv->chip->phy_write(priv, phy_addr, reg_addr, reg_val); +} + +static const struct switch_attr ar8xxx_sw_attr_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = ar8xxx_sw_set_vlan, + .get = ar8xxx_sw_get_vlan, + .max = 1 + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = ar8xxx_sw_set_reset_mibs, + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_poll_interval", + .description = "MIB polling interval in msecs (0 to disable)", + .set = ar8xxx_sw_set_mib_poll_interval, + .get = ar8xxx_sw_get_mib_poll_interval + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_type", + .description = "MIB type (0=basic 1=extended)", + .set = ar8xxx_sw_set_mib_type, + .get = ar8xxx_sw_get_mib_type + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = ar8xxx_sw_set_mirror_rx_enable, + .get = ar8xxx_sw_get_mirror_rx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = ar8xxx_sw_set_mirror_tx_enable, + .get = ar8xxx_sw_get_mirror_tx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = ar8xxx_sw_set_mirror_monitor_port, + .get = ar8xxx_sw_get_mirror_monitor_port, + .max = AR8216_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = ar8xxx_sw_set_mirror_source_port, + .get = ar8xxx_sw_get_mirror_source_port, + .max = AR8216_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_STRING, + .name = "arl_table", + .description = "Get ARL table", + .set = NULL, + .get = ar8xxx_sw_get_arl_table, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush ARL table", + .set = ar8xxx_sw_set_flush_arl_table, + }, +}; + +const struct switch_attr ar8xxx_sw_attr_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = ar8xxx_sw_set_port_reset_mib, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = ar8xxx_sw_get_port_mib, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush port's ARL table entries", + .set = ar8xxx_sw_set_flush_port_arl_table, + }, +}; + +const struct switch_attr ar8xxx_sw_attr_vlan[1] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID (0-4094)", + .set = ar8xxx_sw_set_vid, + .get = ar8xxx_sw_get_vid, + .max = 4094, + }, +}; + +static const struct switch_dev_ops ar8xxx_sw_ops = { + .attr_global = { + .attr = ar8xxx_sw_attr_globals, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals), + }, + .attr_port = { + .attr = ar8xxx_sw_attr_port, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port), + }, + .attr_vlan = { + .attr = ar8xxx_sw_attr_vlan, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), + }, + .get_port_pvid = ar8xxx_sw_get_pvid, + .set_port_pvid = ar8xxx_sw_set_pvid, + .get_vlan_ports = ar8xxx_sw_get_ports, + .set_vlan_ports = ar8xxx_sw_set_ports, + .apply_config = ar8xxx_sw_hw_apply, + .reset_switch = ar8xxx_sw_reset_switch, + .get_port_link = ar8xxx_sw_get_port_link, + .get_port_stats = ar8xxx_sw_get_port_stats, +}; + +static const struct ar8xxx_chip ar7240sw_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR724X/AR933X built-in", + .ports = AR7240SW_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar7240sw_hw_init, + .init_globals = ar7240sw_init_globals, + .init_port = ar8229_init_port, + .phy_read = ar8216_phy_read, + .phy_write = ar8216_phy_write, + .setup_port = ar7240sw_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8216_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x19000, + .reg_port_stats_length = 0xa0, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8216", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8216_hw_init, + .init_globals = ar8216_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8216_mibs), + .mib_decs = ar8216_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8216_MIB_RXB_ID, + .mib_txb_id = AR8216_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8229_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8229", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8229_hw_init, + .init_globals = ar8229_init_globals, + .init_port = ar8229_init_port, + .phy_read = ar8216_phy_read, + .phy_write = ar8216_phy_write, + .setup_port = ar8236_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8236_chip = { + .caps = AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8236", + .ports = AR8216_NUM_PORTS, + .vlans = AR8216_NUM_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8216_hw_init, + .init_globals = ar8236_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8236_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static const struct ar8xxx_chip ar8316_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + + .reg_port_stats_start = 0x20000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8216_REG_ATU_CTRL, + + .name = "Atheros AR8316", + .ports = AR8216_NUM_PORTS, + .vlans = AR8X16_MAX_VLANS, + .swops = &ar8xxx_sw_ops, + + .hw_init = ar8316_hw_init, + .init_globals = ar8316_init_globals, + .init_port = ar8216_init_port, + .setup_port = ar8216_setup_port, + .read_port_status = ar8216_read_port_status, + .atu_flush = ar8216_atu_flush, + .atu_flush_port = ar8216_atu_flush_port, + .vtu_flush = ar8216_vtu_flush, + .vtu_load_vlan = ar8216_vtu_load_vlan, + .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, + .sw_hw_apply = ar8xxx_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8216_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +static int +ar8xxx_read_id(struct ar8xxx_priv *priv) +{ + u32 val; + u16 id; + int i; + + val = ar8xxx_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { + u16 t; + + val = ar8xxx_read(priv, AR8216_REG_CTRL); + if (val == ~0) + return -ENODEV; + + t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); + if (t != id) + return -ENODEV; + } + + priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S; + priv->chip_rev = (id & AR8216_CTRL_REVISION); + return 0; +} + +static int +ar8xxx_id_chip(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8xxx_read_id(priv); + if(ret) + return ret; + + switch (priv->chip_ver) { + case AR8XXX_VER_AR8216: + priv->chip = &ar8216_chip; + break; + case AR8XXX_VER_AR8236: + priv->chip = &ar8236_chip; + break; + case AR8XXX_VER_AR8316: + priv->chip = &ar8316_chip; + break; + case AR8XXX_VER_AR8327: + priv->chip = &ar8327_chip; + break; + case AR8XXX_VER_AR8337: + priv->chip = &ar8337_chip; + break; + default: + pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n", + priv->chip_ver, priv->chip_rev); + + return -ENODEV; + } + + return 0; +} + +static void +ar8xxx_mib_work_func(struct work_struct *work) +{ + struct ar8xxx_priv *priv; + int err, i; + + priv = container_of(work, struct ar8xxx_priv, mib_work.work); + + mutex_lock(&priv->mib_lock); + + err = ar8xxx_mib_capture(priv); + if (err) + goto next_attempt; + + for (i = 0; i < priv->dev.ports; i++) + ar8xxx_mib_fetch_port_stat(priv, i, false); + +next_attempt: + mutex_unlock(&priv->mib_lock); + schedule_delayed_work(&priv->mib_work, + msecs_to_jiffies(priv->mib_poll_interval)); +} + +static int +ar8xxx_mib_init(struct ar8xxx_priv *priv) +{ + unsigned int len; + + if (!ar8xxx_has_mib_counters(priv)) + return 0; + + BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs); + + len = priv->dev.ports * priv->chip->num_mibs * + sizeof(*priv->mib_stats); + priv->mib_stats = kzalloc(len, GFP_KERNEL); + + if (!priv->mib_stats) + return -ENOMEM; + + return 0; +} + +static void +ar8xxx_mib_start(struct ar8xxx_priv *priv) +{ + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return; + + schedule_delayed_work(&priv->mib_work, + msecs_to_jiffies(priv->mib_poll_interval)); +} + +static void +ar8xxx_mib_stop(struct ar8xxx_priv *priv) +{ + if (!ar8xxx_has_mib_counters(priv) || !priv->mib_poll_interval) + return; + + cancel_delayed_work_sync(&priv->mib_work); +} + +static struct ar8xxx_priv * +ar8xxx_create(void) +{ + struct ar8xxx_priv *priv; + + priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + mutex_init(&priv->reg_mutex); + mutex_init(&priv->mib_lock); + INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func); + + return priv; +} + +static void +ar8xxx_free(struct ar8xxx_priv *priv) +{ + if (priv->chip && priv->chip->cleanup) + priv->chip->cleanup(priv); + + kfree(priv->chip_data); + kfree(priv->mib_stats); + kfree(priv); +} + +static int +ar8xxx_probe_switch(struct ar8xxx_priv *priv) +{ + const struct ar8xxx_chip *chip; + struct switch_dev *swdev; + int ret; + + chip = priv->chip; + + swdev = &priv->dev; + swdev->cpu_port = AR8216_PORT_CPU; + swdev->name = chip->name; + swdev->vlans = chip->vlans; + swdev->ports = chip->ports; + swdev->ops = chip->swops; + + ret = ar8xxx_mib_init(priv); + if (ret) + return ret; + + return 0; +} + +static int +ar8xxx_start(struct ar8xxx_priv *priv) +{ + int ret; + + priv->init = true; + + ret = priv->chip->hw_init(priv); + if (ret) + return ret; + + ret = ar8xxx_sw_reset_switch(&priv->dev); + if (ret) + return ret; + + priv->init = false; + + ar8xxx_mib_start(priv); + + return 0; +} + +static int +ar8xxx_phy_config_init(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + struct net_device *dev = phydev->attached_dev; + int ret; + + if (WARN_ON(!priv)) + return -ENODEV; + + if (priv->chip->config_at_probe) + return ar8xxx_phy_check_aneg(phydev); + + priv->phy = phydev; + + if (phydev->mdio.addr != 0) { + if (chip_is_ar8316(priv)) { + /* switch device has been initialized, reinit */ + priv->dev.ports = (AR8216_NUM_PORTS - 1); + priv->initialized = false; + priv->port4_phy = true; + ar8316_hw_init(priv); + return 0; + } + + return 0; + } + + ret = ar8xxx_start(priv); + if (ret) + return ret; + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + /* VID fixup only needed on ar8216 */ + if (chip_is_ar8216(priv)) { + dev->phy_ptr = priv; + dev->priv_flags |= IFF_NO_IP_ALIGN; + dev->eth_mangle_rx = ar8216_mangle_rx; + dev->eth_mangle_tx = ar8216_mangle_tx; + } +#endif + + return 0; +} + +static bool +ar8xxx_check_link_states(struct ar8xxx_priv *priv) +{ + bool link_new, changed = false; + u32 status; + int i; + + mutex_lock(&priv->reg_mutex); + + for (i = 0; i < priv->dev.ports; i++) { + status = priv->chip->read_port_status(priv, i); + link_new = !!(status & AR8216_PORT_STATUS_LINK_UP); + if (link_new == priv->link_up[i]) + continue; + + priv->link_up[i] = link_new; + changed = true; + /* flush ARL entries for this port if it went down*/ + if (!link_new) + priv->chip->atu_flush_port(priv, i); + dev_info(&priv->phy->mdio.dev, "Port %d is %s\n", + i, link_new ? "up" : "down"); + } + + mutex_unlock(&priv->reg_mutex); + + return changed; +} + +static int +ar8xxx_phy_read_status(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + struct switch_port_link link; + + /* check for switch port link changes */ + ar8xxx_check_link_states(priv); + + if (phydev->mdio.addr != 0) + return genphy_read_status(phydev); + + ar8216_read_port_link(priv, phydev->mdio.addr, &link); + phydev->link = !!link.link; + if (!phydev->link) + return 0; + + switch (link.speed) { + case SWITCH_PORT_SPEED_10: + phydev->speed = SPEED_10; + break; + case SWITCH_PORT_SPEED_100: + phydev->speed = SPEED_100; + break; + case SWITCH_PORT_SPEED_1000: + phydev->speed = SPEED_1000; + break; + default: + phydev->speed = 0; + } + phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + if (phydev->adjust_link) + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +static int +ar8xxx_phy_config_aneg(struct phy_device *phydev) +{ + if (phydev->mdio.addr == 0) + return 0; + + return genphy_config_aneg(phydev); +} + +static int +ar8xxx_get_features(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + + linkmode_copy(phydev->supported, PHY_BASIC_FEATURES); + if (ar8xxx_has_gige(priv)) + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported); + + return 0; +} + +static const u32 ar8xxx_phy_ids[] = { + 0x004dd033, + 0x004dd034, /* AR8327 */ + 0x004dd036, /* AR8337 */ + 0x004dd041, + 0x004dd042, + 0x004dd043, /* AR8236 */ +}; + +static bool +ar8xxx_phy_match(u32 phy_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++) + if (phy_id == ar8xxx_phy_ids[i]) + return true; + + return false; +} + +static bool +ar8xxx_is_possible(struct mii_bus *bus) +{ + unsigned int i, found_phys = 0; + + for (i = 0; i < 5; i++) { + u32 phy_id; + + phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16; + phy_id |= mdiobus_read(bus, i, MII_PHYSID2); + if (ar8xxx_phy_match(phy_id)) { + found_phys++; + } else if (phy_id) { + pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n", + dev_name(&bus->dev), i, phy_id); + } + } + return !!found_phys; +} + +static int +ar8xxx_phy_probe(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv; + struct switch_dev *swdev; + int ret; + + /* skip PHYs at unused adresses */ + if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4) + return -ENODEV; + + if (!ar8xxx_is_possible(phydev->mdio.bus)) + return -ENODEV; + + mutex_lock(&ar8xxx_dev_list_lock); + list_for_each_entry(priv, &ar8xxx_dev_list, list) + if (priv->mii_bus == phydev->mdio.bus) + goto found; + + priv = ar8xxx_create(); + if (priv == NULL) { + ret = -ENOMEM; + goto unlock; + } + + priv->mii_bus = phydev->mdio.bus; + priv->pdev = &phydev->mdio.dev; + + ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval", + &priv->mib_poll_interval); + if (ret) + priv->mib_poll_interval = 0; + + ret = ar8xxx_id_chip(priv); + if (ret) + goto free_priv; + + ret = ar8xxx_probe_switch(priv); + if (ret) + goto free_priv; + + swdev = &priv->dev; + swdev->alias = dev_name(&priv->mii_bus->dev); + ret = register_switch(swdev, NULL); + if (ret) + goto free_priv; + + pr_info("%s: %s rev. %u switch registered on %s\n", + swdev->devname, swdev->name, priv->chip_rev, + dev_name(&priv->mii_bus->dev)); + + list_add(&priv->list, &ar8xxx_dev_list); + +found: + priv->use_count++; + + if (phydev->mdio.addr == 0 && priv->chip->config_at_probe) { + priv->phy = phydev; + + ret = ar8xxx_start(priv); + if (ret) + goto err_unregister_switch; + } else if (priv->chip->phy_rgmii_set) { + priv->chip->phy_rgmii_set(priv, phydev); + } + + phydev->priv = priv; + + mutex_unlock(&ar8xxx_dev_list_lock); + + return 0; + +err_unregister_switch: + if (--priv->use_count) + goto unlock; + + unregister_switch(&priv->dev); + +free_priv: + ar8xxx_free(priv); +unlock: + mutex_unlock(&ar8xxx_dev_list_lock); + return ret; +} + +static void +ar8xxx_phy_detach(struct phy_device *phydev) +{ + struct net_device *dev = phydev->attached_dev; + + if (!dev) + return; + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE + dev->phy_ptr = NULL; + dev->priv_flags &= ~IFF_NO_IP_ALIGN; + dev->eth_mangle_rx = NULL; + dev->eth_mangle_tx = NULL; +#endif +} + +static void +ar8xxx_phy_remove(struct phy_device *phydev) +{ + struct ar8xxx_priv *priv = phydev->priv; + + if (WARN_ON(!priv)) + return; + + phydev->priv = NULL; + + mutex_lock(&ar8xxx_dev_list_lock); + + if (--priv->use_count > 0) { + mutex_unlock(&ar8xxx_dev_list_lock); + return; + } + + list_del(&priv->list); + mutex_unlock(&ar8xxx_dev_list_lock); + + unregister_switch(&priv->dev); + ar8xxx_mib_stop(priv); + ar8xxx_free(priv); +} + +static int +ar8xxx_phy_soft_reset(struct phy_device *phydev) +{ + /* we don't need an extra reset */ + return 0; +} + +static struct phy_driver ar8xxx_phy_driver[] = { + { + .phy_id = 0x004d0000, + .name = "Atheros AR8216/AR8236/AR8316", + .phy_id_mask = 0xffff0000, + .probe = ar8xxx_phy_probe, + .remove = ar8xxx_phy_remove, + .detach = ar8xxx_phy_detach, + .config_init = ar8xxx_phy_config_init, + .config_aneg = ar8xxx_phy_config_aneg, + .read_status = ar8xxx_phy_read_status, + .soft_reset = ar8xxx_phy_soft_reset, + .get_features = ar8xxx_get_features, + } +}; + +static const struct of_device_id ar8xxx_mdiodev_of_match[] = { + { + .compatible = "qca,ar7240sw", + .data = &ar7240sw_chip, + }, { + .compatible = "qca,ar8229", + .data = &ar8229_chip, + }, { + .compatible = "qca,ar8236", + .data = &ar8236_chip, + }, { + .compatible = "qca,ar8327", + .data = &ar8327_chip, + }, + { /* sentinel */ }, +}; + +static int +ar8xxx_mdiodev_probe(struct mdio_device *mdiodev) +{ + const struct of_device_id *match; + struct ar8xxx_priv *priv; + struct switch_dev *swdev; + struct device_node *mdio_node; + int ret; + + match = of_match_device(ar8xxx_mdiodev_of_match, &mdiodev->dev); + if (!match) + return -EINVAL; + + priv = ar8xxx_create(); + if (priv == NULL) + return -ENOMEM; + + priv->mii_bus = mdiodev->bus; + priv->pdev = &mdiodev->dev; + priv->chip = (const struct ar8xxx_chip *) match->data; + + ret = of_property_read_u32(priv->pdev->of_node, "qca,mib-poll-interval", + &priv->mib_poll_interval); + if (ret) + priv->mib_poll_interval = 0; + + ret = ar8xxx_read_id(priv); + if (ret) + goto free_priv; + + ret = ar8xxx_probe_switch(priv); + if (ret) + goto free_priv; + + if (priv->chip->phy_read && priv->chip->phy_write) { + priv->sw_mii_bus = devm_mdiobus_alloc(&mdiodev->dev); + priv->sw_mii_bus->name = "ar8xxx-mdio"; + priv->sw_mii_bus->read = ar8xxx_phy_read; + priv->sw_mii_bus->write = ar8xxx_phy_write; + priv->sw_mii_bus->priv = priv; + priv->sw_mii_bus->parent = &mdiodev->dev; + snprintf(priv->sw_mii_bus->id, MII_BUS_ID_SIZE, "%s", + dev_name(&mdiodev->dev)); + mdio_node = of_get_child_by_name(priv->pdev->of_node, "mdio-bus"); + ret = of_mdiobus_register(priv->sw_mii_bus, mdio_node); + if (ret) + goto free_priv; + } + + swdev = &priv->dev; + swdev->alias = dev_name(&mdiodev->dev); + + if (of_property_read_bool(priv->pdev->of_node, "qca,phy4-mii-enable")) { + priv->port4_phy = true; + swdev->ports--; + } + + ret = register_switch(swdev, NULL); + if (ret) + goto free_priv; + + pr_info("%s: %s rev. %u switch registered on %s\n", + swdev->devname, swdev->name, priv->chip_rev, + dev_name(&priv->mii_bus->dev)); + + mutex_lock(&ar8xxx_dev_list_lock); + list_add(&priv->list, &ar8xxx_dev_list); + mutex_unlock(&ar8xxx_dev_list_lock); + + priv->use_count++; + + ret = ar8xxx_start(priv); + if (ret) + goto err_unregister_switch; + + dev_set_drvdata(&mdiodev->dev, priv); + + return 0; + +err_unregister_switch: + if (--priv->use_count) + return ret; + + unregister_switch(&priv->dev); + +free_priv: + ar8xxx_free(priv); + return ret; +} + +static void +ar8xxx_mdiodev_remove(struct mdio_device *mdiodev) +{ + struct ar8xxx_priv *priv = dev_get_drvdata(&mdiodev->dev); + + if (WARN_ON(!priv)) + return; + + mutex_lock(&ar8xxx_dev_list_lock); + + if (--priv->use_count > 0) { + mutex_unlock(&ar8xxx_dev_list_lock); + return; + } + + list_del(&priv->list); + mutex_unlock(&ar8xxx_dev_list_lock); + + unregister_switch(&priv->dev); + ar8xxx_mib_stop(priv); + if(priv->sw_mii_bus) + mdiobus_unregister(priv->sw_mii_bus); + ar8xxx_free(priv); +} + +static struct mdio_driver ar8xxx_mdio_driver = { + .probe = ar8xxx_mdiodev_probe, + .remove = ar8xxx_mdiodev_remove, + .mdiodrv.driver = { + .name = "ar8xxx-switch", + .of_match_table = ar8xxx_mdiodev_of_match, + }, +}; + +static int __init ar8216_init(void) +{ + int ret; + + ret = phy_drivers_register(ar8xxx_phy_driver, + ARRAY_SIZE(ar8xxx_phy_driver), + THIS_MODULE); + if (ret) + return ret; + + ret = mdio_driver_register(&ar8xxx_mdio_driver); + if (ret) + phy_drivers_unregister(ar8xxx_phy_driver, + ARRAY_SIZE(ar8xxx_phy_driver)); + + return ret; +} +module_init(ar8216_init); + +static void __exit ar8216_exit(void) +{ + mdio_driver_unregister(&ar8xxx_mdio_driver); + phy_drivers_unregister(ar8xxx_phy_driver, + ARRAY_SIZE(ar8xxx_phy_driver)); +} +module_exit(ar8216_exit); + +MODULE_LICENSE("GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/ar8216.h b/ipq806x/files-5.4/drivers/net/phy/ar8216.h new file mode 100644 index 0000000..d62cf60 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/ar8216.h @@ -0,0 +1,723 @@ +/* + * ar8216.h: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AR8216_H +#define __AR8216_H + +#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s) + +#define AR8XXX_CAP_GIGE BIT(0) +#define AR8XXX_CAP_MIB_COUNTERS BIT(1) + +#define AR8XXX_NUM_PHYS 5 +#define AR8216_PORT_CPU 0 +#define AR8216_NUM_PORTS 6 +#define AR8216_NUM_VLANS 16 +#define AR7240SW_NUM_PORTS 5 +#define AR8316_NUM_VLANS 4096 + +/* size of the vlan table */ +#define AR8X16_MAX_VLANS 128 +#define AR83X7_MAX_VLANS 4096 +#define AR8XXX_MAX_VLANS AR83X7_MAX_VLANS + +#define AR8X16_PROBE_RETRIES 10 +#define AR8X16_MAX_PORTS 8 + +#define AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS 7 +#define AR8XXX_DEFAULT_ARL_AGE_TIME 300 + +/* Atheros specific MII registers */ +#define MII_ATH_MMD_ADDR 0x0d +#define MII_ATH_MMD_DATA 0x0e +#define MII_ATH_DBG_ADDR 0x1d +#define MII_ATH_DBG_DATA 0x1e + +#define AR8216_REG_CTRL 0x0000 +#define AR8216_CTRL_REVISION BITS(0, 8) +#define AR8216_CTRL_REVISION_S 0 +#define AR8216_CTRL_VERSION BITS(8, 8) +#define AR8216_CTRL_VERSION_S 8 +#define AR8216_CTRL_RESET BIT(31) + +#define AR8216_REG_FLOOD_MASK 0x002C +#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6) +#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6) +#define AR8216_FM_CPU_BROADCAST_EN BIT(26) +#define AR8229_FLOOD_MASK_UC_DP(_p) BIT(_p) +#define AR8229_FLOOD_MASK_MC_DP(_p) BIT(16 + (_p)) +#define AR8229_FLOOD_MASK_BC_DP(_p) BIT(25 + (_p)) + +#define AR8216_REG_GLOBAL_CTRL 0x0030 +#define AR8216_GCTRL_MTU BITS(0, 11) +#define AR8236_GCTRL_MTU BITS(0, 14) +#define AR8316_GCTRL_MTU BITS(0, 14) + +#define AR8216_REG_VTU 0x0040 +#define AR8216_VTU_OP BITS(0, 3) +#define AR8216_VTU_OP_NOOP 0x0 +#define AR8216_VTU_OP_FLUSH 0x1 +#define AR8216_VTU_OP_LOAD 0x2 +#define AR8216_VTU_OP_PURGE 0x3 +#define AR8216_VTU_OP_REMOVE_PORT 0x4 +#define AR8216_VTU_ACTIVE BIT(3) +#define AR8216_VTU_FULL BIT(4) +#define AR8216_VTU_PORT BITS(8, 4) +#define AR8216_VTU_PORT_S 8 +#define AR8216_VTU_VID BITS(16, 12) +#define AR8216_VTU_VID_S 16 +#define AR8216_VTU_PRIO BITS(28, 3) +#define AR8216_VTU_PRIO_S 28 +#define AR8216_VTU_PRIO_EN BIT(31) + +#define AR8216_REG_VTU_DATA 0x0044 +#define AR8216_VTUDATA_MEMBER BITS(0, 10) +#define AR8236_VTUDATA_MEMBER BITS(0, 7) +#define AR8216_VTUDATA_VALID BIT(11) + +#define AR8216_REG_ATU_FUNC0 0x0050 +#define AR8216_ATU_OP BITS(0, 3) +#define AR8216_ATU_OP_NOOP 0x0 +#define AR8216_ATU_OP_FLUSH 0x1 +#define AR8216_ATU_OP_LOAD 0x2 +#define AR8216_ATU_OP_PURGE 0x3 +#define AR8216_ATU_OP_FLUSH_UNLOCKED 0x4 +#define AR8216_ATU_OP_FLUSH_PORT 0x5 +#define AR8216_ATU_OP_GET_NEXT 0x6 +#define AR8216_ATU_ACTIVE BIT(3) +#define AR8216_ATU_PORT_NUM BITS(8, 4) +#define AR8216_ATU_PORT_NUM_S 8 +#define AR8216_ATU_FULL_VIO BIT(12) +#define AR8216_ATU_ADDR5 BITS(16, 8) +#define AR8216_ATU_ADDR5_S 16 +#define AR8216_ATU_ADDR4 BITS(24, 8) +#define AR8216_ATU_ADDR4_S 24 + +#define AR8216_REG_ATU_FUNC1 0x0054 +#define AR8216_ATU_ADDR3 BITS(0, 8) +#define AR8216_ATU_ADDR3_S 0 +#define AR8216_ATU_ADDR2 BITS(8, 8) +#define AR8216_ATU_ADDR2_S 8 +#define AR8216_ATU_ADDR1 BITS(16, 8) +#define AR8216_ATU_ADDR1_S 16 +#define AR8216_ATU_ADDR0 BITS(24, 8) +#define AR8216_ATU_ADDR0_S 24 + +#define AR8216_REG_ATU_FUNC2 0x0058 +#define AR8216_ATU_PORTS BITS(0, 6) +#define AR8216_ATU_PORTS_S 0 +#define AR8216_ATU_PORT0 BIT(0) +#define AR8216_ATU_PORT1 BIT(1) +#define AR8216_ATU_PORT2 BIT(2) +#define AR8216_ATU_PORT3 BIT(3) +#define AR8216_ATU_PORT4 BIT(4) +#define AR8216_ATU_PORT5 BIT(5) +#define AR8216_ATU_STATUS BITS(16, 4) +#define AR8216_ATU_STATUS_S 16 + +#define AR8216_REG_ATU_CTRL 0x005C +#define AR8216_ATU_CTRL_AGE_EN BIT(17) +#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16) +#define AR8216_ATU_CTRL_AGE_TIME_S 0 +#define AR8236_ATU_CTRL_RES BIT(20) +#define AR8216_ATU_CTRL_LEARN_CHANGE BIT(18) +#define AR8216_ATU_CTRL_RESERVED BIT(19) +#define AR8216_ATU_CTRL_ARP_EN BIT(20) + +#define AR8216_REG_TAG_PRIORITY 0x0070 + +#define AR8216_REG_SERVICE_TAG 0x0074 +#define AR8216_SERVICE_TAG_M BITS(0, 16) + +#define AR8216_REG_MIB_FUNC 0x0080 +#define AR8216_MIB_TIMER BITS(0, 16) +#define AR8216_MIB_AT_HALF_EN BIT(16) +#define AR8216_MIB_BUSY BIT(17) +#define AR8216_MIB_FUNC BITS(24, 3) +#define AR8216_MIB_FUNC_S 24 +#define AR8216_MIB_FUNC_NO_OP 0x0 +#define AR8216_MIB_FUNC_FLUSH 0x1 +#define AR8216_MIB_FUNC_CAPTURE 0x3 +#define AR8236_MIB_EN BIT(30) + +#define AR8216_REG_GLOBAL_CPUPORT 0x0078 +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4) +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4 +#define AR8216_GLOBAL_CPUPORT_EN BIT(8) + +#define AR8216_REG_MDIO_CTRL 0x98 +#define AR8216_MDIO_CTRL_DATA_M BITS(0, 16) +#define AR8216_MDIO_CTRL_REG_ADDR_S 16 +#define AR8216_MDIO_CTRL_PHY_ADDR_S 21 +#define AR8216_MDIO_CTRL_CMD_WRITE 0 +#define AR8216_MDIO_CTRL_CMD_READ BIT(27) +#define AR8216_MDIO_CTRL_MASTER_EN BIT(30) +#define AR8216_MDIO_CTRL_BUSY BIT(31) + +#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1)) +#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000) +#define AR8216_PORT_STATUS_SPEED BITS(0,2) +#define AR8216_PORT_STATUS_SPEED_S 0 +#define AR8216_PORT_STATUS_TXMAC BIT(2) +#define AR8216_PORT_STATUS_RXMAC BIT(3) +#define AR8216_PORT_STATUS_TXFLOW BIT(4) +#define AR8216_PORT_STATUS_RXFLOW BIT(5) +#define AR8216_PORT_STATUS_DUPLEX BIT(6) +#define AR8216_PORT_STATUS_LINK_UP BIT(8) +#define AR8216_PORT_STATUS_LINK_AUTO BIT(9) +#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10) +#define AR8216_PORT_STATUS_FLOW_CONTROL BIT(12) + +#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004) + +/* port forwarding state */ +#define AR8216_PORT_CTRL_STATE BITS(0, 3) +#define AR8216_PORT_CTRL_STATE_S 0 + +#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7) + +/* egress 802.1q mode */ +#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2) +#define AR8216_PORT_CTRL_VLAN_MODE_S 8 + +#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10) +#define AR8216_PORT_CTRL_HEADER BIT(11) +#define AR8216_PORT_CTRL_MAC_LOOP BIT(12) +#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13) +#define AR8216_PORT_CTRL_LEARN BIT(14) +#define AR8216_PORT_CTRL_MIRROR_TX BIT(16) +#define AR8216_PORT_CTRL_MIRROR_RX BIT(17) + +#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008) + +#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12) +#define AR8216_PORT_VLAN_DEFAULT_ID_S 0 + +#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9) +#define AR8216_PORT_VLAN_DEST_PORTS_S 16 + +/* bit0 added to the priority field of egress frames */ +#define AR8216_PORT_VLAN_TX_PRIO BIT(27) + +/* port default priority */ +#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2) +#define AR8216_PORT_VLAN_PRIORITY_S 28 + +/* ingress 802.1q mode */ +#define AR8216_PORT_VLAN_MODE BITS(30, 2) +#define AR8216_PORT_VLAN_MODE_S 30 + +#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c) +#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010) + +#define AR8216_STATS_RXBROAD 0x00 +#define AR8216_STATS_RXPAUSE 0x04 +#define AR8216_STATS_RXMULTI 0x08 +#define AR8216_STATS_RXFCSERR 0x0c +#define AR8216_STATS_RXALIGNERR 0x10 +#define AR8216_STATS_RXRUNT 0x14 +#define AR8216_STATS_RXFRAGMENT 0x18 +#define AR8216_STATS_RX64BYTE 0x1c +#define AR8216_STATS_RX128BYTE 0x20 +#define AR8216_STATS_RX256BYTE 0x24 +#define AR8216_STATS_RX512BYTE 0x28 +#define AR8216_STATS_RX1024BYTE 0x2c +#define AR8216_STATS_RXMAXBYTE 0x30 +#define AR8216_STATS_RXTOOLONG 0x34 +#define AR8216_STATS_RXGOODBYTE 0x38 +#define AR8216_STATS_RXBADBYTE 0x40 +#define AR8216_STATS_RXOVERFLOW 0x48 +#define AR8216_STATS_FILTERED 0x4c +#define AR8216_STATS_TXBROAD 0x50 +#define AR8216_STATS_TXPAUSE 0x54 +#define AR8216_STATS_TXMULTI 0x58 +#define AR8216_STATS_TXUNDERRUN 0x5c +#define AR8216_STATS_TX64BYTE 0x60 +#define AR8216_STATS_TX128BYTE 0x64 +#define AR8216_STATS_TX256BYTE 0x68 +#define AR8216_STATS_TX512BYTE 0x6c +#define AR8216_STATS_TX1024BYTE 0x70 +#define AR8216_STATS_TXMAXBYTE 0x74 +#define AR8216_STATS_TXOVERSIZE 0x78 +#define AR8216_STATS_TXBYTE 0x7c +#define AR8216_STATS_TXCOLLISION 0x84 +#define AR8216_STATS_TXABORTCOL 0x88 +#define AR8216_STATS_TXMULTICOL 0x8c +#define AR8216_STATS_TXSINGLECOL 0x90 +#define AR8216_STATS_TXEXCDEFER 0x94 +#define AR8216_STATS_TXDEFER 0x98 +#define AR8216_STATS_TXLATECOL 0x9c + +#define AR8216_MIB_RXB_ID 14 /* RxGoodByte */ +#define AR8216_MIB_TXB_ID 29 /* TxByte */ + +#define AR8229_REG_OPER_MODE0 0x04 +#define AR8229_OPER_MODE0_MAC_GMII_EN BIT(6) +#define AR8229_OPER_MODE0_PHY_MII_EN BIT(10) + +#define AR8229_REG_OPER_MODE1 0x08 +#define AR8229_REG_OPER_MODE1_PHY4_MII_EN BIT(28) + +#define AR8229_REG_QM_CTRL 0x3c +#define AR8229_QM_CTRL_ARP_EN BIT(15) + +#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008) +#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12) +#define AR8236_PORT_VLAN_DEFAULT_ID_S 16 +#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3) +#define AR8236_PORT_VLAN_PRIORITY_S 28 + +#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c) +#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7) +#define AR8236_PORT_VLAN2_MEMBER_S 16 +#define AR8236_PORT_VLAN2_TX_PRIO BIT(23) +#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2) +#define AR8236_PORT_VLAN2_VLAN_MODE_S 30 + +#define AR8236_STATS_RXBROAD 0x00 +#define AR8236_STATS_RXPAUSE 0x04 +#define AR8236_STATS_RXMULTI 0x08 +#define AR8236_STATS_RXFCSERR 0x0c +#define AR8236_STATS_RXALIGNERR 0x10 +#define AR8236_STATS_RXRUNT 0x14 +#define AR8236_STATS_RXFRAGMENT 0x18 +#define AR8236_STATS_RX64BYTE 0x1c +#define AR8236_STATS_RX128BYTE 0x20 +#define AR8236_STATS_RX256BYTE 0x24 +#define AR8236_STATS_RX512BYTE 0x28 +#define AR8236_STATS_RX1024BYTE 0x2c +#define AR8236_STATS_RX1518BYTE 0x30 +#define AR8236_STATS_RXMAXBYTE 0x34 +#define AR8236_STATS_RXTOOLONG 0x38 +#define AR8236_STATS_RXGOODBYTE 0x3c +#define AR8236_STATS_RXBADBYTE 0x44 +#define AR8236_STATS_RXOVERFLOW 0x4c +#define AR8236_STATS_FILTERED 0x50 +#define AR8236_STATS_TXBROAD 0x54 +#define AR8236_STATS_TXPAUSE 0x58 +#define AR8236_STATS_TXMULTI 0x5c +#define AR8236_STATS_TXUNDERRUN 0x60 +#define AR8236_STATS_TX64BYTE 0x64 +#define AR8236_STATS_TX128BYTE 0x68 +#define AR8236_STATS_TX256BYTE 0x6c +#define AR8236_STATS_TX512BYTE 0x70 +#define AR8236_STATS_TX1024BYTE 0x74 +#define AR8236_STATS_TX1518BYTE 0x78 +#define AR8236_STATS_TXMAXBYTE 0x7c +#define AR8236_STATS_TXOVERSIZE 0x80 +#define AR8236_STATS_TXBYTE 0x84 +#define AR8236_STATS_TXCOLLISION 0x8c +#define AR8236_STATS_TXABORTCOL 0x90 +#define AR8236_STATS_TXMULTICOL 0x94 +#define AR8236_STATS_TXSINGLECOL 0x98 +#define AR8236_STATS_TXEXCDEFER 0x9c +#define AR8236_STATS_TXDEFER 0xa0 +#define AR8236_STATS_TXLATECOL 0xa4 + +#define AR8236_MIB_RXB_ID 15 /* RxGoodByte */ +#define AR8236_MIB_TXB_ID 31 /* TxByte */ + +#define AR8316_REG_POSTRIP 0x0008 +#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0) +#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1) +#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2) +#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3) +#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4) +#define AR8316_POSTRIP_RTL_MODE BIT(5) +#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6) +#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7) +#define AR8316_POSTRIP_SERDES_EN BIT(8) +#define AR8316_POSTRIP_SEL_ANA_RST BIT(9) +#define AR8316_POSTRIP_GATE_25M_EN BIT(10) +#define AR8316_POSTRIP_SEL_CLK25M BIT(11) +#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12) +#define AR8316_POSTRIP_DBG_MODE_I BIT(13) +#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14) +#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15) +#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16) +#define AR8316_POSTRIP_LPW_STATE_EN BIT(17) +#define AR8316_POSTRIP_MAN_EN BIT(18) +#define AR8316_POSTRIP_PHY_PLL_ON BIT(19) +#define AR8316_POSTRIP_LPW_EXIT BIT(20) +#define AR8316_POSTRIP_TXDELAY_S0 BIT(21) +#define AR8316_POSTRIP_TXDELAY_S1 BIT(22) +#define AR8316_POSTRIP_RXDELAY_S0 BIT(23) +#define AR8316_POSTRIP_LED_OPEN_EN BIT(24) +#define AR8316_POSTRIP_SPI_EN BIT(25) +#define AR8316_POSTRIP_RXDELAY_S1 BIT(26) +#define AR8316_POSTRIP_POWER_ON_SEL BIT(31) + +/* port speed */ +enum { + AR8216_PORT_SPEED_10M = 0, + AR8216_PORT_SPEED_100M = 1, + AR8216_PORT_SPEED_1000M = 2, + AR8216_PORT_SPEED_ERR = 3, +}; + +/* ingress 802.1q mode */ +enum { + AR8216_IN_PORT_ONLY = 0, + AR8216_IN_PORT_FALLBACK = 1, + AR8216_IN_VLAN_ONLY = 2, + AR8216_IN_SECURE = 3 +}; + +/* egress 802.1q mode */ +enum { + AR8216_OUT_KEEP = 0, + AR8216_OUT_STRIP_VLAN = 1, + AR8216_OUT_ADD_VLAN = 2 +}; + +/* port forwarding state */ +enum { + AR8216_PORT_STATE_DISABLED = 0, + AR8216_PORT_STATE_BLOCK = 1, + AR8216_PORT_STATE_LISTEN = 2, + AR8216_PORT_STATE_LEARN = 3, + AR8216_PORT_STATE_FORWARD = 4 +}; + +/* mib counter type */ +enum { + AR8XXX_MIB_BASIC = 0, + AR8XXX_MIB_EXTENDED = 1 +}; + +enum { + AR8XXX_VER_AR8216 = 0x01, + AR8XXX_VER_AR8236 = 0x03, + AR8XXX_VER_AR8316 = 0x10, + AR8XXX_VER_AR8327 = 0x12, + AR8XXX_VER_AR8337 = 0x13, +}; + +#define AR8XXX_NUM_ARL_RECORDS 100 + +enum arl_op { + AR8XXX_ARL_INITIALIZE, + AR8XXX_ARL_GET_NEXT +}; + +struct arl_entry { + u16 portmap; + u8 mac[6]; +}; + +struct ar8xxx_priv; + +struct ar8xxx_mib_desc { + unsigned int size; + unsigned int offset; + const char *name; + u8 type; +}; + +struct ar8xxx_chip { + unsigned long caps; + bool config_at_probe; + bool mii_lo_first; + + /* parameters to calculate REG_PORT_STATS_BASE */ + unsigned reg_port_stats_start; + unsigned reg_port_stats_length; + + unsigned reg_arl_ctrl; + + int (*hw_init)(struct ar8xxx_priv *priv); + void (*cleanup)(struct ar8xxx_priv *priv); + + const char *name; + int vlans; + int ports; + const struct switch_dev_ops *swops; + + void (*init_globals)(struct ar8xxx_priv *priv); + void (*init_port)(struct ar8xxx_priv *priv, int port); + void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members); + u32 (*read_port_status)(struct ar8xxx_priv *priv, int port); + u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port); + int (*atu_flush)(struct ar8xxx_priv *priv); + int (*atu_flush_port)(struct ar8xxx_priv *priv, int port); + void (*vtu_flush)(struct ar8xxx_priv *priv); + void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask); + void (*phy_fixup)(struct ar8xxx_priv *priv, int phy); + void (*set_mirror_regs)(struct ar8xxx_priv *priv); + void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a, + u32 *status, enum arl_op op); + int (*sw_hw_apply)(struct switch_dev *dev); + void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev); + int (*phy_read)(struct ar8xxx_priv *priv, int addr, int regnum); + int (*phy_write)(struct ar8xxx_priv *priv, int addr, int regnum, u16 val); + + const struct ar8xxx_mib_desc *mib_decs; + unsigned num_mibs; + unsigned mib_func; + int mib_rxb_id; + int mib_txb_id; +}; + +struct ar8xxx_priv { + struct switch_dev dev; + struct mii_bus *mii_bus; + struct mii_bus *sw_mii_bus; + struct phy_device *phy; + struct device *pdev; + + int (*get_port_link)(unsigned port); + + const struct net_device_ops *ndo_old; + struct net_device_ops ndo; + struct mutex reg_mutex; + u8 chip_ver; + u8 chip_rev; + const struct ar8xxx_chip *chip; + void *chip_data; + bool initialized; + bool port4_phy; + char buf[2048]; + struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS]; + char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256]; + bool link_up[AR8X16_MAX_PORTS]; + + bool init; + + struct mutex mib_lock; + struct delayed_work mib_work; + u64 *mib_stats; + u32 mib_poll_interval; + u8 mib_type; + + struct list_head list; + unsigned int use_count; + + /* all fields below are cleared on reset */ + bool vlan; + + u16 vlan_id[AR8XXX_MAX_VLANS]; + u8 vlan_table[AR8XXX_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[AR8X16_MAX_PORTS]; + int arl_age_time; + + /* mirroring */ + bool mirror_rx; + bool mirror_tx; + int source_port; + int monitor_port; + u8 port_vlan_prio[AR8X16_MAX_PORTS]; +}; + +u32 +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum); +void +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val); +u32 +ar8xxx_read(struct ar8xxx_priv *priv, int reg); +void +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val); +u32 +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); + +void +ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 *dbg_data); +void +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, + u16 dbg_addr, u16 dbg_data); +void +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data); +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg); +void +ar8xxx_phy_init(struct ar8xxx_priv *priv); +int +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mib_type(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan); +int +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan); +int +ar8xxx_sw_hw_apply(struct switch_dev *dev); +int +ar8xxx_sw_reset_switch(struct switch_dev *dev); +int +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, + struct switch_port_link *link); +int +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int +ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats); +int +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); + +static inline struct ar8xxx_priv * +swdev_to_ar8xxx(struct switch_dev *swdev) +{ + return container_of(swdev, struct ar8xxx_priv, dev); +} + +static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv) +{ + return priv->chip->caps & AR8XXX_CAP_GIGE; +} + +static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv) +{ + return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS; +} + +static inline bool chip_is_ar8216(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8216; +} + +static inline bool chip_is_ar8236(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8236; +} + +static inline bool chip_is_ar8316(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8316; +} + +static inline bool chip_is_ar8327(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8327; +} + +static inline bool chip_is_ar8337(struct ar8xxx_priv *priv) +{ + return priv->chip_ver == AR8XXX_VER_AR8337; +} + +static inline void +ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val) +{ + ar8xxx_rmw(priv, reg, 0, val); +} + +static inline void +ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val) +{ + ar8xxx_rmw(priv, reg, val, 0); +} + +static inline void +split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) +{ + regaddr >>= 1; + *r1 = regaddr & 0x1e; + + regaddr >>= 5; + *r2 = regaddr & 0x7; + + regaddr >>= 3; + *page = regaddr & 0x1ff; +} + +static inline void +wait_for_page_switch(void) +{ + udelay(5); +} + +#endif diff --git a/ipq806x/files-5.4/drivers/net/phy/ar8327.c b/ipq806x/files-5.4/drivers/net/phy/ar8327.c new file mode 100644 index 0000000..dce52ce --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/ar8327.c @@ -0,0 +1,1550 @@ +/* + * ar8327.c: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * Copyright (C) 2011-2012 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar8216.h" +#include "ar8327.h" + +extern const struct ar8xxx_mib_desc ar8236_mibs[39]; +extern const struct switch_attr ar8xxx_sw_attr_vlan[1]; + +static u32 +ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) +{ + u32 t; + + if (!cfg) + return 0; + + t = 0; + switch (cfg->mode) { + case AR8327_PAD_NC: + break; + + case AR8327_PAD_MAC2MAC_MII: + t = AR8327_PAD_MAC_MII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_MAC_MII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_MAC_MII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC2MAC_GMII: + t = AR8327_PAD_MAC_GMII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC_SGMII: + t = AR8327_PAD_SGMII_EN; + + /* + * WAR for the QUalcomm Atheros AP136 board. + * It seems that RGMII TX/RX delay settings needs to be + * applied for SGMII mode as well, The ethernet is not + * reliable without this. + */ + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; + if (cfg->rxclk_delay_en) + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; + if (cfg->txclk_delay_en) + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; + + if (cfg->sgmii_delay_en) + t |= AR8327_PAD_SGMII_DELAY_EN; + + break; + + case AR8327_PAD_MAC2PHY_MII: + t = AR8327_PAD_PHY_MII_EN; + if (cfg->rxclk_sel) + t |= AR8327_PAD_PHY_MII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_PHY_MII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC2PHY_GMII: + t = AR8327_PAD_PHY_GMII_EN; + if (cfg->pipe_rxclk_sel) + t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; + if (cfg->rxclk_sel) + t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; + if (cfg->txclk_sel) + t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; + break; + + case AR8327_PAD_MAC_RGMII: + t = AR8327_PAD_RGMII_EN; + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; + if (cfg->rxclk_delay_en) + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; + if (cfg->txclk_delay_en) + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; + break; + + case AR8327_PAD_PHY_GMII: + t = AR8327_PAD_PHYX_GMII_EN; + break; + + case AR8327_PAD_PHY_RGMII: + t = AR8327_PAD_PHYX_RGMII_EN; + break; + + case AR8327_PAD_PHY_MII: + t = AR8327_PAD_PHYX_MII_EN; + break; + } + + return t; +} + +static void +ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device *phydev) +{ + u16 phy_val = 0; + int phyaddr = phydev->mdio.addr; + struct device_node *np = phydev->mdio.dev.of_node; + + if (!np) + return; + + if (!of_property_read_bool(np, "qca,phy-rgmii-en")) { + pr_err("ar8327: qca,phy-rgmii-en is not specified\n"); + return; + } + ar8xxx_phy_dbg_read(priv, phyaddr, + AR8327_PHY_MODE_SEL, &phy_val); + phy_val |= AR8327_PHY_MODE_SEL_RGMII; + ar8xxx_phy_dbg_write(priv, phyaddr, + AR8327_PHY_MODE_SEL, phy_val); + + /* set rgmii tx clock delay if needed */ + if (!of_property_read_bool(np, "qca,txclk-delay-en")) { + pr_err("ar8327: qca,txclk-delay-en is not specified\n"); + return; + } + ar8xxx_phy_dbg_read(priv, phyaddr, + AR8327_PHY_SYS_CTRL, &phy_val); + phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY; + ar8xxx_phy_dbg_write(priv, phyaddr, + AR8327_PHY_SYS_CTRL, phy_val); + + /* set rgmii rx clock delay if needed */ + if (!of_property_read_bool(np, "qca,rxclk-delay-en")) { + pr_err("ar8327: qca,rxclk-delay-en is not specified\n"); + return; + } + ar8xxx_phy_dbg_read(priv, phyaddr, + AR8327_PHY_TEST_CTRL, &phy_val); + phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY; + ar8xxx_phy_dbg_write(priv, phyaddr, + AR8327_PHY_TEST_CTRL, phy_val); +} + +static void +ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy) +{ + switch (priv->chip_rev) { + case 1: + /* For 100M waveform */ + ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea); + /* Turn on Gigabit clock */ + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0); + break; + + case 2: + ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0); + /* fallthrough */ + case 4: + ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f); + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860); + ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46); + ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000); + break; + } +} + +static u32 +ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) +{ + u32 t; + + if (!cfg->force_link) + return AR8216_PORT_STATUS_LINK_AUTO; + + t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC; + t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0; + t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0; + t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0; + + switch (cfg->speed) { + case AR8327_PORT_SPEED_10: + t |= AR8216_PORT_SPEED_10M; + break; + case AR8327_PORT_SPEED_100: + t |= AR8216_PORT_SPEED_100M; + break; + case AR8327_PORT_SPEED_1000: + t |= AR8216_PORT_SPEED_1000M; + break; + } + + return t; +} + +#define AR8327_LED_ENTRY(_num, _reg, _shift) \ + [_num] = { .reg = (_reg), .shift = (_shift) } + +static const struct ar8327_led_entry +ar8327_led_map[AR8327_NUM_LEDS] = { + AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14), + + AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8), + AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10), + AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12), + + AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14), + AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16), + AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18), + + AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20), + AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22), + AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24), + + AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30), + AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30), + AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30), +}; + +static void +ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num, + enum ar8327_led_pattern pattern) +{ + const struct ar8327_led_entry *entry; + + entry = &ar8327_led_map[led_num]; + ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg), + (3 << entry->shift), pattern << entry->shift); +} + +static void +ar8327_led_work_func(struct work_struct *work) +{ + struct ar8327_led *aled; + u8 pattern; + + aled = container_of(work, struct ar8327_led, led_work); + + pattern = aled->pattern; + + ar8327_set_led_pattern(aled->sw_priv, aled->led_num, + pattern); +} + +static void +ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern) +{ + if (aled->pattern == pattern) + return; + + aled->pattern = pattern; + schedule_work(&aled->led_work); +} + +static inline struct ar8327_led * +led_cdev_to_ar8327_led(struct led_classdev *led_cdev) +{ + return container_of(led_cdev, struct ar8327_led, cdev); +} + +static int +ar8327_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + + if (*delay_on == 0 && *delay_off == 0) { + *delay_on = 125; + *delay_off = 125; + } + + if (*delay_on != 125 || *delay_off != 125) { + /* + * The hardware only supports blinking at 4Hz. Fall back + * to software implementation in other cases. + */ + return -EINVAL; + } + + spin_lock(&aled->lock); + + aled->enable_hw_mode = false; + ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK); + + spin_unlock(&aled->lock); + + return 0; +} + +static void +ar8327_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + u8 pattern; + bool active; + + active = (brightness != LED_OFF); + active ^= aled->active_low; + + pattern = (active) ? AR8327_LED_PATTERN_ON : + AR8327_LED_PATTERN_OFF; + + spin_lock(&aled->lock); + + aled->enable_hw_mode = false; + ar8327_led_schedule_change(aled, pattern); + + spin_unlock(&aled->lock); +} + +static ssize_t +ar8327_led_enable_hw_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + ssize_t ret = 0; + + ret += scnprintf(buf, PAGE_SIZE, "%d\n", aled->enable_hw_mode); + + return ret; +} + +static ssize_t +ar8327_led_enable_hw_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); + u8 pattern; + u8 value; + int ret; + + ret = kstrtou8(buf, 10, &value); + if (ret < 0) + return -EINVAL; + + spin_lock(&aled->lock); + + aled->enable_hw_mode = !!value; + if (aled->enable_hw_mode) + pattern = AR8327_LED_PATTERN_RULE; + else + pattern = AR8327_LED_PATTERN_OFF; + + ar8327_led_schedule_change(aled, pattern); + + spin_unlock(&aled->lock); + + return size; +} + +static DEVICE_ATTR(enable_hw_mode, S_IRUGO | S_IWUSR, + ar8327_led_enable_hw_mode_show, + ar8327_led_enable_hw_mode_store); + +static int +ar8327_led_register(struct ar8327_led *aled) +{ + int ret; + + ret = led_classdev_register(NULL, &aled->cdev); + if (ret < 0) + return ret; + + if (aled->mode == AR8327_LED_MODE_HW) { + ret = device_create_file(aled->cdev.dev, + &dev_attr_enable_hw_mode); + if (ret) + goto err_unregister; + } + + return 0; + +err_unregister: + led_classdev_unregister(&aled->cdev); + return ret; +} + +static void +ar8327_led_unregister(struct ar8327_led *aled) +{ + if (aled->mode == AR8327_LED_MODE_HW) + device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode); + + led_classdev_unregister(&aled->cdev); + cancel_work_sync(&aled->led_work); +} + +static int +ar8327_led_create(struct ar8xxx_priv *priv, + const struct ar8327_led_info *led_info) +{ + struct ar8327_data *data = priv->chip_data; + struct ar8327_led *aled; + int ret; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return 0; + + if (!led_info->name) + return -EINVAL; + + if (led_info->led_num >= AR8327_NUM_LEDS) + return -EINVAL; + + aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1, + GFP_KERNEL); + if (!aled) + return -ENOMEM; + + aled->sw_priv = priv; + aled->led_num = led_info->led_num; + aled->active_low = led_info->active_low; + aled->mode = led_info->mode; + + if (aled->mode == AR8327_LED_MODE_HW) + aled->enable_hw_mode = true; + + aled->name = (char *)(aled + 1); + strcpy(aled->name, led_info->name); + + aled->cdev.name = aled->name; + aled->cdev.brightness_set = ar8327_led_set_brightness; + aled->cdev.blink_set = ar8327_led_blink_set; + aled->cdev.default_trigger = led_info->default_trigger; + + spin_lock_init(&aled->lock); + mutex_init(&aled->mutex); + INIT_WORK(&aled->led_work, ar8327_led_work_func); + + ret = ar8327_led_register(aled); + if (ret) + goto err_free; + + data->leds[data->num_leds++] = aled; + + return 0; + +err_free: + kfree(aled); + return ret; +} + +static void +ar8327_led_destroy(struct ar8327_led *aled) +{ + ar8327_led_unregister(aled); + kfree(aled); +} + +static void +ar8327_leds_init(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + unsigned i; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return; + + for (i = 0; i < data->num_leds; i++) { + struct ar8327_led *aled; + + aled = data->leds[i]; + + if (aled->enable_hw_mode) + aled->pattern = AR8327_LED_PATTERN_RULE; + else + aled->pattern = AR8327_LED_PATTERN_OFF; + + ar8327_set_led_pattern(priv, aled->led_num, aled->pattern); + } +} + +static void +ar8327_leds_cleanup(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + unsigned i; + + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) + return; + + for (i = 0; i < data->num_leds; i++) { + struct ar8327_led *aled; + + aled = data->leds[i]; + ar8327_led_destroy(aled); + } + + kfree(data->leds); +} + +static int +ar8327_hw_config_pdata(struct ar8xxx_priv *priv, + struct ar8327_platform_data *pdata) +{ + struct ar8327_led_cfg *led_cfg; + struct ar8327_data *data = priv->chip_data; + u32 pos, new_pos; + u32 t; + + if (!pdata) + return -EINVAL; + + priv->get_port_link = pdata->get_port_link; + + data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg); + data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg); + + t = ar8327_get_pad_cfg(pdata->pad0_cfg); + if (chip_is_ar8337(priv) && !pdata->pad0_cfg->mac06_exchange_dis) + t |= AR8337_PAD_MAC06_EXCHANGE_EN; + ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t); + + t = ar8327_get_pad_cfg(pdata->pad5_cfg); + ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t); + t = ar8327_get_pad_cfg(pdata->pad6_cfg); + ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t); + + pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRAP); + new_pos = pos; + + led_cfg = pdata->led_cfg; + if (led_cfg) { + if (led_cfg->open_drain) + new_pos |= AR8327_POWER_ON_STRAP_LED_OPEN_EN; + else + new_pos &= ~AR8327_POWER_ON_STRAP_LED_OPEN_EN; + + ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0); + ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1); + ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2); + ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3); + + if (new_pos != pos) + new_pos |= AR8327_POWER_ON_STRAP_POWER_ON_SEL; + } + + if (pdata->sgmii_cfg) { + t = pdata->sgmii_cfg->sgmii_ctrl; + if (priv->chip_rev == 1) + t |= AR8327_SGMII_CTRL_EN_PLL | + AR8327_SGMII_CTRL_EN_RX | + AR8327_SGMII_CTRL_EN_TX; + else + t &= ~(AR8327_SGMII_CTRL_EN_PLL | + AR8327_SGMII_CTRL_EN_RX | + AR8327_SGMII_CTRL_EN_TX); + + ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t); + + if (pdata->sgmii_cfg->serdes_aen) + new_pos &= ~AR8327_POWER_ON_STRAP_SERDES_AEN; + else + new_pos |= AR8327_POWER_ON_STRAP_SERDES_AEN; + } + + ar8xxx_write(priv, AR8327_REG_POWER_ON_STRAP, new_pos); + + if (pdata->leds && pdata->num_leds) { + int i; + + data->leds = kzalloc(pdata->num_leds * sizeof(void *), + GFP_KERNEL); + if (!data->leds) + return -ENOMEM; + + for (i = 0; i < pdata->num_leds; i++) + ar8327_led_create(priv, &pdata->leds[i]); + } + + return 0; +} + +#ifdef CONFIG_OF +static int +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) +{ + struct ar8327_data *data = priv->chip_data; + const __be32 *paddr; + int len; + int i; + + paddr = of_get_property(np, "qca,ar8327-initvals", &len); + if (!paddr || len < (2 * sizeof(*paddr))) + return -EINVAL; + + len /= sizeof(*paddr); + + for (i = 0; i < len - 1; i += 2) { + u32 reg; + u32 val; + + reg = be32_to_cpup(paddr + i); + val = be32_to_cpup(paddr + i + 1); + + switch (reg) { + case AR8327_REG_PORT_STATUS(0): + data->port0_status = val; + break; + case AR8327_REG_PORT_STATUS(6): + data->port6_status = val; + break; + default: + ar8xxx_write(priv, reg, val); + break; + } + } + + return 0; +} +#else +static inline int +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) +{ + return -EINVAL; +} +#endif + +static int +ar8327_hw_init(struct ar8xxx_priv *priv) +{ + int ret; + + priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL); + if (!priv->chip_data) + return -ENOMEM; + + if (priv->pdev->of_node) + ret = ar8327_hw_config_of(priv, priv->pdev->of_node); + else + ret = ar8327_hw_config_pdata(priv, + priv->phy->mdio.dev.platform_data); + + if (ret) + return ret; + + ar8327_leds_init(priv); + + ar8xxx_phy_init(priv); + + return 0; +} + +static void +ar8327_cleanup(struct ar8xxx_priv *priv) +{ + ar8327_leds_cleanup(priv); +} + +static void +ar8327_init_globals(struct ar8xxx_priv *priv) +{ + struct ar8327_data *data = priv->chip_data; + u32 t; + int i; + + /* enable CPU port and disable mirror port */ + t = AR8327_FWD_CTRL0_CPU_PORT_EN | + AR8327_FWD_CTRL0_MIRROR_PORT; + ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t); + + /* forward multicast and broadcast frames to CPU */ + t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); + ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t); + + /* enable jumbo frames */ + ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE, + AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); + + /* Enable MIB counters */ + ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN, + AR8327_MODULE_EN_MIB); + + /* Disable EEE on all phy's due to stability issues */ + for (i = 0; i < AR8XXX_NUM_PHYS; i++) + data->eee[i] = false; +} + +static void +ar8327_init_port(struct ar8xxx_priv *priv, int port) +{ + struct ar8327_data *data = priv->chip_data; + u32 t; + + if (port == AR8216_PORT_CPU) + t = data->port0_status; + else if (port == 6) + t = data->port6_status; + else + t = AR8216_PORT_STATUS_LINK_AUTO; + + if (port != AR8216_PORT_CPU && port != 6) { + /*hw limitation:if configure mac when there is traffic, + port MAC may work abnormal. Need disable lan&wan mac at fisrt*/ + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), 0); + msleep(100); + t |= AR8216_PORT_STATUS_FLOW_CONTROL; + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); + } else { + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); + } + + ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0); + + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), 0); + + t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); + + t = AR8327_PORT_LOOKUP_LEARN; + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); +} + +static u32 +ar8327_read_port_status(struct ar8xxx_priv *priv, int port) +{ + u32 t; + + t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port)); + /* map the flow control autoneg result bits to the flow control bits + * used in forced mode to allow ar8216_read_port_link detect + * flow control properly if autoneg is used + */ + if (t & AR8216_PORT_STATUS_LINK_UP && + t & AR8216_PORT_STATUS_LINK_AUTO) { + t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW); + if (t & AR8327_PORT_STATUS_TXFLOW_AUTO) + t |= AR8216_PORT_STATUS_TXFLOW; + if (t & AR8327_PORT_STATUS_RXFLOW_AUTO) + t |= AR8216_PORT_STATUS_RXFLOW; + } + + return t; +} + +static u32 +ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port) +{ + int phy; + u16 t; + + if (port >= priv->dev.ports) + return 0; + + if (port == 0 || port == 6) + return 0; + + phy = port - 1; + + /* EEE Ability Auto-negotiation Result */ + t = ar8xxx_phy_mmd_read(priv, phy, 0x7, 0x8000); + + return mmd_eee_adv_to_ethtool_adv_t(t); +} + +static int +ar8327_atu_flush(struct ar8xxx_priv *priv) +{ + int ret; + + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_BUSY, 0); + if (!ret) + ar8xxx_write(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_OP_FLUSH | + AR8327_ATU_FUNC_BUSY); + + return ret; +} + +static int +ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port) +{ + u32 t; + int ret; + + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, + AR8327_ATU_FUNC_BUSY, 0); + if (!ret) { + t = (port << AR8327_ATU_PORT_NUM_S); + t |= AR8327_ATU_FUNC_OP_FLUSH_PORT; + t |= AR8327_ATU_FUNC_BUSY; + ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t); + } + + return ret; +} + +static int +ar8327_get_port_igmp(struct ar8xxx_priv *priv, int port) +{ + u32 fwd_ctrl, frame_ack; + + fwd_ctrl = (BIT(port) << AR8327_FWD_CTRL1_IGMP_S); + frame_ack = ((AR8327_FRAME_ACK_CTRL_IGMP_MLD | + AR8327_FRAME_ACK_CTRL_IGMP_JOIN | + AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) << + AR8327_FRAME_ACK_CTRL_S(port)); + + return (ar8xxx_read(priv, AR8327_REG_FWD_CTRL1) & + fwd_ctrl) == fwd_ctrl && + (ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL(port)) & + frame_ack) == frame_ack; +} + +static void +ar8327_set_port_igmp(struct ar8xxx_priv *priv, int port, int enable) +{ + int reg_frame_ack = AR8327_REG_FRAME_ACK_CTRL(port); + u32 val_frame_ack = (AR8327_FRAME_ACK_CTRL_IGMP_MLD | + AR8327_FRAME_ACK_CTRL_IGMP_JOIN | + AR8327_FRAME_ACK_CTRL_IGMP_LEAVE) << + AR8327_FRAME_ACK_CTRL_S(port); + + if (enable) { + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1, + BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S, + BIT(port) << AR8327_FWD_CTRL1_IGMP_S); + ar8xxx_reg_set(priv, reg_frame_ack, val_frame_ack); + } else { + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1, + BIT(port) << AR8327_FWD_CTRL1_IGMP_S, + BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S); + ar8xxx_reg_clear(priv, reg_frame_ack, val_frame_ack); + } +} + +static void +ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) +{ + if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1, + AR8327_VTU_FUNC1_BUSY, 0)) + return; + + if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD) + ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val); + + op |= AR8327_VTU_FUNC1_BUSY; + ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op); +} + +static void +ar8327_vtu_flush(struct ar8xxx_priv *priv) +{ + ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0); +} + +static void +ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) +{ + u32 op; + u32 val; + int i; + + op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S); + val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL; + for (i = 0; i < AR8327_NUM_PORTS; i++) { + u32 mode; + + if ((port_mask & BIT(i)) == 0) + mode = AR8327_VTU_FUNC0_EG_MODE_NOT; + else if (priv->vlan == 0) + mode = AR8327_VTU_FUNC0_EG_MODE_KEEP; + else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid)) + mode = AR8327_VTU_FUNC0_EG_MODE_TAG; + else + mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG; + + val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i); + } + ar8327_vtu_op(priv, op, val); +} + +static void +ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members) +{ + u32 t; + u32 egress, ingress; + u32 pvid = priv->vlan_id[priv->pvid[port]]; + + if (priv->vlan) { + egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD; + ingress = AR8216_IN_SECURE; + } else { + egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; + ingress = AR8216_IN_PORT_ONLY; + } + + t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S; + t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S; + if (priv->vlan && priv->port_vlan_prio[port]) { + u32 prio = priv->port_vlan_prio[port]; + + t |= prio << AR8327_PORT_VLAN0_DEF_SPRI_S; + t |= prio << AR8327_PORT_VLAN0_DEF_CPRI_S; + } + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t); + + t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; + t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S; + if (priv->vlan && priv->port_vlan_prio[port]) + t |= AR8327_PORT_VLAN1_VLAN_PRI_PROP; + + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); + + t = members; + t |= AR8327_PORT_LOOKUP_LEARN; + t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S; + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); +} + +static int +ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + int i; + + val->len = 0; + for (i = 0; i < dev->ports; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int +ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + if (val->port_vlan == priv->pvid[p->id]) { + priv->vlan_tagged |= (1 << p->id); + } + } else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + } + + *vt |= 1 << p->id; + } + return 0; +} + +static void +ar8327_set_mirror_regs(struct ar8xxx_priv *priv) +{ + int port; + + /* reset all mirror registers */ + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + for (port = 0; port < AR8327_NUM_PORTS; port++) { + ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN); + + ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); + } + + /* now enable mirroring if necessary */ + if (priv->source_port >= AR8327_NUM_PORTS || + priv->monitor_port >= AR8327_NUM_PORTS || + priv->source_port == priv->monitor_port) { + return; + } + + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, + AR8327_FWD_CTRL0_MIRROR_PORT, + (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + + if (priv->mirror_rx) + ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port), + AR8327_PORT_LOOKUP_ING_MIRROR_EN); + + if (priv->mirror_tx) + ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port), + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); +} + +static int +ar8327_sw_set_eee(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + struct ar8327_data *data = priv->chip_data; + int port = val->port_vlan; + int phy; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + + phy = port - 1; + + data->eee[phy] = !!(val->value.i); + + return 0; +} + +static int +ar8327_sw_get_eee(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8327_data *data = priv->chip_data; + int port = val->port_vlan; + int phy; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + + phy = port - 1; + + val->value.i = data->eee[phy]; + + return 0; +} + +static void +ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) +{ + int timeout = 20; + + while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout) { + udelay(10); + cond_resched(); + } + + if (!timeout) + pr_err("ar8327: timeout waiting for atu to become ready\n"); +} + +static void ar8327_get_arl_entry(struct ar8xxx_priv *priv, + struct arl_entry *a, u32 *status, enum arl_op op) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r2, page; + u16 r1_data0, r1_data1, r1_data2, r1_func; + u32 val0, val1, val2; + + split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page); + r2 |= 0x10; + + r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e; + r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e; + r1_func = (AR8327_REG_ATU_FUNC >> 1) & 0x1e; + + switch (op) { + case AR8XXX_ARL_INITIALIZE: + /* all ATU registers are on the same page + * therefore set page only once + */ + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ar8327_wait_atu_ready(priv, r2, r1_func); + + ar8xxx_mii_write32(priv, r2, r1_data0, 0); + ar8xxx_mii_write32(priv, r2, r1_data1, 0); + ar8xxx_mii_write32(priv, r2, r1_data2, 0); + break; + case AR8XXX_ARL_GET_NEXT: + ar8xxx_mii_write32(priv, r2, r1_func, + AR8327_ATU_FUNC_OP_GET_NEXT | + AR8327_ATU_FUNC_BUSY); + ar8327_wait_atu_ready(priv, r2, r1_func); + + val0 = ar8xxx_mii_read32(priv, r2, r1_data0); + val1 = ar8xxx_mii_read32(priv, r2, r1_data1); + val2 = ar8xxx_mii_read32(priv, r2, r1_data2); + + *status = val2 & AR8327_ATU_STATUS; + if (!*status) + break; + + a->portmap = (val1 & AR8327_ATU_PORTS) >> AR8327_ATU_PORTS_S; + a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S; + a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S; + a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S; + a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S; + a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S; + a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S; + break; + } +} + +static int +ar8327_sw_hw_apply(struct switch_dev *dev) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + const struct ar8327_data *data = priv->chip_data; + int ret, i; + + ret = ar8xxx_sw_hw_apply(dev); + if (ret) + return ret; + + for (i=0; i < AR8XXX_NUM_PHYS; i++) { + if (data->eee[i]) + ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL, + AR8327_EEE_CTRL_DISABLE_PHY(i)); + else + ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL, + AR8327_EEE_CTRL_DISABLE_PHY(i)); + } + + return 0; +} + +int +ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->reg_mutex); + val->value.i = ar8327_get_port_igmp(priv, port); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + if (port >= dev->ports) + return -EINVAL; + + mutex_lock(&priv->reg_mutex); + ar8327_set_port_igmp(priv, port, val->value.i); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8327_sw_get_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int port; + + for (port = 0; port < dev->ports; port++) { + val->port_vlan = port; + if (ar8327_sw_get_port_igmp_snooping(dev, attr, val) || + !val->value.i) + break; + } + + return 0; +} + +int +ar8327_sw_set_igmp_snooping(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int port; + + for (port = 0; port < dev->ports; port++) { + val->port_vlan = port; + if (ar8327_sw_set_port_igmp_snooping(dev, attr, val)) + break; + } + + return 0; +} + +int +ar8327_sw_get_igmp_v3(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + u32 val_reg; + + mutex_lock(&priv->reg_mutex); + val_reg = ar8xxx_read(priv, AR8327_REG_FRAME_ACK_CTRL1); + val->value.i = ((val_reg & AR8327_FRAME_ACK_CTRL_IGMP_V3_EN) != 0); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +int +ar8327_sw_set_igmp_v3(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + mutex_lock(&priv->reg_mutex); + if (val->value.i) + ar8xxx_reg_set(priv, AR8327_REG_FRAME_ACK_CTRL1, + AR8327_FRAME_ACK_CTRL_IGMP_V3_EN); + else + ar8xxx_reg_clear(priv, AR8327_REG_FRAME_ACK_CTRL1, + AR8327_FRAME_ACK_CTRL_IGMP_V3_EN); + mutex_unlock(&priv->reg_mutex); + + return 0; +} + +static int +ar8327_sw_set_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + if (port >= dev->ports) + return -EINVAL; + if (port == 0 || port == 6) + return -EOPNOTSUPP; + if (val->value.i < 0 || val->value.i > 7) + return -EINVAL; + + priv->port_vlan_prio[port] = val->value.i; + + return 0; +} + +static int +ar8327_sw_get_port_vlan_prio(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + int port = val->port_vlan; + + val->value.i = priv->port_vlan_prio[port]; + + return 0; +} + +static const struct switch_attr ar8327_sw_attr_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = ar8xxx_sw_set_vlan, + .get = ar8xxx_sw_get_vlan, + .max = 1 + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = ar8xxx_sw_set_reset_mibs, + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_poll_interval", + .description = "MIB polling interval in msecs (0 to disable)", + .set = ar8xxx_sw_set_mib_poll_interval, + .get = ar8xxx_sw_get_mib_poll_interval + }, + { + .type = SWITCH_TYPE_INT, + .name = "ar8xxx_mib_type", + .description = "MIB type (0=basic 1=extended)", + .set = ar8xxx_sw_set_mib_type, + .get = ar8xxx_sw_get_mib_type + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = ar8xxx_sw_set_mirror_rx_enable, + .get = ar8xxx_sw_get_mirror_rx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = ar8xxx_sw_set_mirror_tx_enable, + .get = ar8xxx_sw_get_mirror_tx_enable, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = ar8xxx_sw_set_mirror_monitor_port, + .get = ar8xxx_sw_get_mirror_monitor_port, + .max = AR8327_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = ar8xxx_sw_set_mirror_source_port, + .get = ar8xxx_sw_get_mirror_source_port, + .max = AR8327_NUM_PORTS - 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "arl_age_time", + .description = "ARL age time (secs)", + .set = ar8xxx_sw_set_arl_age_time, + .get = ar8xxx_sw_get_arl_age_time, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "arl_table", + .description = "Get ARL table", + .set = NULL, + .get = ar8xxx_sw_get_arl_table, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush ARL table", + .set = ar8xxx_sw_set_flush_arl_table, + }, + { + .type = SWITCH_TYPE_INT, + .name = "igmp_snooping", + .description = "Enable IGMP Snooping", + .set = ar8327_sw_set_igmp_snooping, + .get = ar8327_sw_get_igmp_snooping, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "igmp_v3", + .description = "Enable IGMPv3 support", + .set = ar8327_sw_set_igmp_v3, + .get = ar8327_sw_get_igmp_v3, + .max = 1 + }, +}; + +static const struct switch_attr ar8327_sw_attr_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = ar8xxx_sw_set_port_reset_mib, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .set = NULL, + .get = ar8xxx_sw_get_port_mib, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_eee", + .description = "Enable EEE PHY sleep mode", + .set = ar8327_sw_set_eee, + .get = ar8327_sw_get_eee, + .max = 1, + }, + { + .type = SWITCH_TYPE_NOVAL, + .name = "flush_arl_table", + .description = "Flush port's ARL table entries", + .set = ar8xxx_sw_set_flush_port_arl_table, + }, + { + .type = SWITCH_TYPE_INT, + .name = "igmp_snooping", + .description = "Enable port's IGMP Snooping", + .set = ar8327_sw_set_port_igmp_snooping, + .get = ar8327_sw_get_port_igmp_snooping, + .max = 1 + }, + { + .type = SWITCH_TYPE_INT, + .name = "vlan_prio", + .description = "Port VLAN default priority (VLAN PCP) (0-7)", + .set = ar8327_sw_set_port_vlan_prio, + .get = ar8327_sw_get_port_vlan_prio, + .max = 7, + }, +}; + +static const struct switch_dev_ops ar8327_sw_ops = { + .attr_global = { + .attr = ar8327_sw_attr_globals, + .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals), + }, + .attr_port = { + .attr = ar8327_sw_attr_port, + .n_attr = ARRAY_SIZE(ar8327_sw_attr_port), + }, + .attr_vlan = { + .attr = ar8xxx_sw_attr_vlan, + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), + }, + .get_port_pvid = ar8xxx_sw_get_pvid, + .set_port_pvid = ar8xxx_sw_set_pvid, + .get_vlan_ports = ar8327_sw_get_ports, + .set_vlan_ports = ar8327_sw_set_ports, + .apply_config = ar8327_sw_hw_apply, + .reset_switch = ar8xxx_sw_reset_switch, + .get_port_link = ar8xxx_sw_get_port_link, + .get_port_stats = ar8xxx_sw_get_port_stats, +}; + +const struct ar8xxx_chip ar8327_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + .config_at_probe = true, + .mii_lo_first = true, + + .name = "Atheros AR8327", + .ports = AR8327_NUM_PORTS, + .vlans = AR83X7_MAX_VLANS, + .swops = &ar8327_sw_ops, + + .reg_port_stats_start = 0x1000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8327_REG_ARL_CTRL, + + .hw_init = ar8327_hw_init, + .cleanup = ar8327_cleanup, + .init_globals = ar8327_init_globals, + .init_port = ar8327_init_port, + .setup_port = ar8327_setup_port, + .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, + .atu_flush = ar8327_atu_flush, + .atu_flush_port = ar8327_atu_flush_port, + .vtu_flush = ar8327_vtu_flush, + .vtu_load_vlan = ar8327_vtu_load_vlan, + .phy_fixup = ar8327_phy_fixup, + .set_mirror_regs = ar8327_set_mirror_regs, + .get_arl_entry = ar8327_get_arl_entry, + .sw_hw_apply = ar8327_sw_hw_apply, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8327_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; + +const struct ar8xxx_chip ar8337_chip = { + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, + .config_at_probe = true, + .mii_lo_first = true, + + .name = "Atheros AR8337", + .ports = AR8327_NUM_PORTS, + .vlans = AR83X7_MAX_VLANS, + .swops = &ar8327_sw_ops, + + .reg_port_stats_start = 0x1000, + .reg_port_stats_length = 0x100, + .reg_arl_ctrl = AR8327_REG_ARL_CTRL, + + .hw_init = ar8327_hw_init, + .cleanup = ar8327_cleanup, + .init_globals = ar8327_init_globals, + .init_port = ar8327_init_port, + .setup_port = ar8327_setup_port, + .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, + .atu_flush = ar8327_atu_flush, + .atu_flush_port = ar8327_atu_flush_port, + .vtu_flush = ar8327_vtu_flush, + .vtu_load_vlan = ar8327_vtu_load_vlan, + .phy_fixup = ar8327_phy_fixup, + .set_mirror_regs = ar8327_set_mirror_regs, + .get_arl_entry = ar8327_get_arl_entry, + .sw_hw_apply = ar8327_sw_hw_apply, + .phy_rgmii_set = ar8327_phy_rgmii_set, + + .num_mibs = ARRAY_SIZE(ar8236_mibs), + .mib_decs = ar8236_mibs, + .mib_func = AR8327_REG_MIB_FUNC, + .mib_rxb_id = AR8236_MIB_RXB_ID, + .mib_txb_id = AR8236_MIB_TXB_ID, +}; diff --git a/ipq806x/files-5.4/drivers/net/phy/ar8327.h b/ipq806x/files-5.4/drivers/net/phy/ar8327.h new file mode 100644 index 0000000..088b288 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/ar8327.h @@ -0,0 +1,333 @@ +/* + * ar8327.h: AR8216 switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AR8327_H +#define __AR8327_H + +#define AR8327_NUM_PORTS 7 +#define AR8327_NUM_LEDS 15 +#define AR8327_PORTS_ALL 0x7f +#define AR8327_NUM_LED_CTRL_REGS 4 + +#define AR8327_REG_MASK 0x000 + +#define AR8327_REG_PAD0_MODE 0x004 +#define AR8327_REG_PAD5_MODE 0x008 +#define AR8327_REG_PAD6_MODE 0x00c +#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0) +#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1) +#define AR8327_PAD_MAC_MII_EN BIT(2) +#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4) +#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5) +#define AR8327_PAD_MAC_GMII_EN BIT(6) +#define AR8327_PAD_SGMII_EN BIT(7) +#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8) +#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9) +#define AR8327_PAD_PHY_MII_EN BIT(10) +#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11) +#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12) +#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13) +#define AR8327_PAD_PHY_GMII_EN BIT(14) +#define AR8327_PAD_PHYX_GMII_EN BIT(16) +#define AR8327_PAD_PHYX_RGMII_EN BIT(17) +#define AR8327_PAD_PHYX_MII_EN BIT(18) +#define AR8327_PAD_SGMII_DELAY_EN BIT(19) +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2) +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20 +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2) +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22 +#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24) +#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25) +#define AR8327_PAD_RGMII_EN BIT(26) + +#define AR8327_REG_POWER_ON_STRAP 0x010 +#define AR8327_POWER_ON_STRAP_POWER_ON_SEL BIT(31) +#define AR8327_POWER_ON_STRAP_LED_OPEN_EN BIT(24) +#define AR8327_POWER_ON_STRAP_SERDES_AEN BIT(7) + +#define AR8327_REG_INT_STATUS0 0x020 +#define AR8327_INT0_VT_DONE BIT(20) + +#define AR8327_REG_INT_STATUS1 0x024 +#define AR8327_REG_INT_MASK0 0x028 +#define AR8327_REG_INT_MASK1 0x02c + +#define AR8327_REG_MODULE_EN 0x030 +#define AR8327_MODULE_EN_MIB BIT(0) + +#define AR8327_REG_MIB_FUNC 0x034 +#define AR8327_MIB_CPU_KEEP BIT(20) + +#define AR8327_REG_SERVICE_TAG 0x048 +#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4) +#define AR8327_REG_LED_CTRL0 0x050 +#define AR8327_REG_LED_CTRL1 0x054 +#define AR8327_REG_LED_CTRL2 0x058 +#define AR8327_REG_LED_CTRL3 0x05c +#define AR8327_REG_MAC_ADDR0 0x060 +#define AR8327_REG_MAC_ADDR1 0x064 + +#define AR8327_REG_MAX_FRAME_SIZE 0x078 +#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14) + +#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) +#define AR8327_PORT_STATUS_TXFLOW_AUTO BIT(10) +#define AR8327_PORT_STATUS_RXFLOW_AUTO BIT(11) + +#define AR8327_REG_HEADER_CTRL 0x098 +#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4) + +#define AR8327_REG_SGMII_CTRL 0x0e0 +#define AR8327_SGMII_CTRL_EN_PLL BIT(1) +#define AR8327_SGMII_CTRL_EN_RX BIT(2) +#define AR8327_SGMII_CTRL_EN_TX BIT(3) + +#define AR8327_REG_EEE_CTRL 0x100 +#define AR8327_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2) + +#define AR8327_REG_FRAME_ACK_CTRL0 0x210 +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN0 BIT(0) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN0 BIT(1) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN0 BIT(2) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN0 BIT(3) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN0 BIT(4) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN0 BIT(5) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN0 BIT(6) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN1 BIT(8) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN1 BIT(9) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN1 BIT(10) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN1 BIT(11) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN1 BIT(12) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN1 BIT(13) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN1 BIT(14) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN2 BIT(16) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN2 BIT(17) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN2 BIT(18) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN2 BIT(19) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN2 BIT(20) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN2 BIT(21) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN2 BIT(22) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN3 BIT(24) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN3 BIT(25) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN3 BIT(26) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN3 BIT(27) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN3 BIT(28) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN3 BIT(29) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN3 BIT(30) + +#define AR8327_REG_FRAME_ACK_CTRL1 0x214 +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN4 BIT(0) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN4 BIT(1) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN4 BIT(2) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN4 BIT(3) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN4 BIT(4) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN4 BIT(5) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN4 BIT(6) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN5 BIT(8) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN5 BIT(9) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN5 BIT(10) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN5 BIT(11) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN5 BIT(12) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN5 BIT(13) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN5 BIT(14) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN6 BIT(16) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN6 BIT(17) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN6 BIT(18) +#define AR8327_FRAME_ACK_CTRL_EAPOL_EN6 BIT(19) +#define AR8327_FRAME_ACK_CTRL_DHCP_EN6 BIT(20) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN6 BIT(21) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN6 BIT(22) +#define AR8327_FRAME_ACK_CTRL_IGMP_V3_EN BIT(24) +#define AR8327_FRAME_ACK_CTRL_PPPOE_EN BIT(25) + +#define AR8327_REG_FRAME_ACK_CTRL(_i) (0x210 + ((_i) / 4) * 0x4) +#define AR8327_FRAME_ACK_CTRL_IGMP_MLD BIT(0) +#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN BIT(1) +#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE BIT(2) +#define AR8327_FRAME_ACK_CTRL_EAPOL BIT(3) +#define AR8327_FRAME_ACK_CTRL_DHCP BIT(4) +#define AR8327_FRAME_ACK_CTRL_ARP_ACK BIT(5) +#define AR8327_FRAME_ACK_CTRL_ARP_REQ BIT(6) +#define AR8327_FRAME_ACK_CTRL_S(_i) (((_i) % 4) * 8) + +#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8) +#define AR8327_PORT_VLAN0_DEF_PRI_MASK BITS(0, 3) +#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12) +#define AR8327_PORT_VLAN0_DEF_SVID_S 0 +#define AR8327_PORT_VLAN0_DEF_SPRI BITS(13, 3) +#define AR8327_PORT_VLAN0_DEF_SPRI_S 13 +#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12) +#define AR8327_PORT_VLAN0_DEF_CVID_S 16 +#define AR8327_PORT_VLAN0_DEF_CPRI BITS(29, 3) +#define AR8327_PORT_VLAN0_DEF_CPRI_S 29 + +#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8) +#define AR8327_PORT_VLAN1_VLAN_PRI_PROP BIT(4) +#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6) +#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2) +#define AR8327_PORT_VLAN1_OUT_MODE_S 12 +#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0 +#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1 +#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2 +#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3 + +#define AR8327_REG_ATU_DATA0 0x600 +#define AR8327_ATU_ADDR0 BITS(0, 8) +#define AR8327_ATU_ADDR0_S 0 +#define AR8327_ATU_ADDR1 BITS(8, 8) +#define AR8327_ATU_ADDR1_S 8 +#define AR8327_ATU_ADDR2 BITS(16, 8) +#define AR8327_ATU_ADDR2_S 16 +#define AR8327_ATU_ADDR3 BITS(24, 8) +#define AR8327_ATU_ADDR3_S 24 +#define AR8327_REG_ATU_DATA1 0x604 +#define AR8327_ATU_ADDR4 BITS(0, 8) +#define AR8327_ATU_ADDR4_S 0 +#define AR8327_ATU_ADDR5 BITS(8, 8) +#define AR8327_ATU_ADDR5_S 8 +#define AR8327_ATU_PORTS BITS(16, 7) +#define AR8327_ATU_PORTS_S 16 +#define AR8327_ATU_PORT0 BIT(16) +#define AR8327_ATU_PORT1 BIT(17) +#define AR8327_ATU_PORT2 BIT(18) +#define AR8327_ATU_PORT3 BIT(19) +#define AR8327_ATU_PORT4 BIT(20) +#define AR8327_ATU_PORT5 BIT(21) +#define AR8327_ATU_PORT6 BIT(22) +#define AR8327_REG_ATU_DATA2 0x608 +#define AR8327_ATU_STATUS BITS(0, 4) + +#define AR8327_REG_ATU_FUNC 0x60c +#define AR8327_ATU_FUNC_OP BITS(0, 4) +#define AR8327_ATU_FUNC_OP_NOOP 0x0 +#define AR8327_ATU_FUNC_OP_FLUSH 0x1 +#define AR8327_ATU_FUNC_OP_LOAD 0x2 +#define AR8327_ATU_FUNC_OP_PURGE 0x3 +#define AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED 0x4 +#define AR8327_ATU_FUNC_OP_FLUSH_PORT 0x5 +#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6 +#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7 +#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8 +#define AR8327_ATU_PORT_NUM BITS(8, 4) +#define AR8327_ATU_PORT_NUM_S 8 +#define AR8327_ATU_FUNC_BUSY BIT(31) + +#define AR8327_REG_VTU_FUNC0 0x0610 +#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14) +#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) +#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0 +#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1 +#define AR8327_VTU_FUNC0_EG_MODE_TAG 2 +#define AR8327_VTU_FUNC0_EG_MODE_NOT 3 +#define AR8327_VTU_FUNC0_IVL BIT(19) +#define AR8327_VTU_FUNC0_VALID BIT(20) + +#define AR8327_REG_VTU_FUNC1 0x0614 +#define AR8327_VTU_FUNC1_OP BITS(0, 3) +#define AR8327_VTU_FUNC1_OP_NOOP 0 +#define AR8327_VTU_FUNC1_OP_FLUSH 1 +#define AR8327_VTU_FUNC1_OP_LOAD 2 +#define AR8327_VTU_FUNC1_OP_PURGE 3 +#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4 +#define AR8327_VTU_FUNC1_OP_GET_NEXT 5 +#define AR8327_VTU_FUNC1_OP_GET_ONE 6 +#define AR8327_VTU_FUNC1_FULL BIT(4) +#define AR8327_VTU_FUNC1_PORT BIT(8, 4) +#define AR8327_VTU_FUNC1_PORT_S 8 +#define AR8327_VTU_FUNC1_VID BIT(16, 12) +#define AR8327_VTU_FUNC1_VID_S 16 +#define AR8327_VTU_FUNC1_BUSY BIT(31) + +#define AR8327_REG_ARL_CTRL 0x0618 + +#define AR8327_REG_FWD_CTRL0 0x620 +#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10) +#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4) +#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4 + +#define AR8327_REG_FWD_CTRL1 0x624 +#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7) +#define AR8327_FWD_CTRL1_UC_FLOOD_S 0 +#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7) +#define AR8327_FWD_CTRL1_MC_FLOOD_S 8 +#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7) +#define AR8327_FWD_CTRL1_BC_FLOOD_S 16 +#define AR8327_FWD_CTRL1_IGMP BITS(24, 7) +#define AR8327_FWD_CTRL1_IGMP_S 24 + +#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc) +#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7) +#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2) +#define AR8327_PORT_LOOKUP_IN_MODE_S 8 +#define AR8327_PORT_LOOKUP_STATE BITS(16, 3) +#define AR8327_PORT_LOOKUP_STATE_S 16 +#define AR8327_PORT_LOOKUP_LEARN BIT(20) +#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25) + +#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc) + +#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) +#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) + +#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31) + +#define AR8327_PHY_MODE_SEL 0x12 +#define AR8327_PHY_MODE_SEL_RGMII BIT(3) +#define AR8327_PHY_TEST_CTRL 0x0 +#define AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY BIT(15) +#define AR8327_PHY_SYS_CTRL 0x5 +#define AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY BIT(8) + +enum ar8327_led_pattern { + AR8327_LED_PATTERN_OFF = 0, + AR8327_LED_PATTERN_BLINK, + AR8327_LED_PATTERN_ON, + AR8327_LED_PATTERN_RULE, +}; + +struct ar8327_led_entry { + unsigned reg; + unsigned shift; +}; + +struct ar8327_led { + struct led_classdev cdev; + struct ar8xxx_priv *sw_priv; + + char *name; + bool active_low; + u8 led_num; + enum ar8327_led_mode mode; + + struct mutex mutex; + spinlock_t lock; + struct work_struct led_work; + bool enable_hw_mode; + enum ar8327_led_pattern pattern; +}; + +struct ar8327_data { + u32 port0_status; + u32 port6_status; + + struct ar8327_led **leds; + unsigned int num_leds; + + /* all fields below are cleared on reset */ + bool eee[AR8XXX_NUM_PHYS]; +}; + +#endif diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/Kconfig b/ipq806x/files-5.4/drivers/net/phy/b53/Kconfig new file mode 100644 index 0000000..08287e7 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/Kconfig @@ -0,0 +1,37 @@ +menuconfig SWCONFIG_B53 + tristate "Broadcom bcm53xx managed switch support" + depends on SWCONFIG + help + This driver adds support for Broadcom managed switch chips. It supports + BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX + integrated switches. + +config SWCONFIG_B53_SPI_DRIVER + tristate "B53 SPI connected switch driver" + depends on SWCONFIG_B53 && SPI + help + Select to enable support for registering switches configured through SPI. + +config SWCONFIG_B53_PHY_DRIVER + tristate "B53 MDIO connected switch driver" + depends on SWCONFIG_B53 + select SWCONFIG_B53_PHY_FIXUP + help + Select to enable support for registering switches configured through MDIO. + +config SWCONFIG_B53_MMAP_DRIVER + tristate "B53 MMAP connected switch driver" + depends on SWCONFIG_B53 + help + Select to enable support for memory-mapped switches like the BCM63XX + integrated switches. + +config SWCONFIG_B53_SRAB_DRIVER + tristate "B53 SRAB connected switch driver" + depends on SWCONFIG_B53 + help + Select to enable support for memory-mapped Switch Register Access + Bridge Registers (SRAB) like it is found on the BCM53010 + +config SWCONFIG_B53_PHY_FIXUP + bool diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/Makefile b/ipq806x/files-5.4/drivers/net/phy/b53/Makefile new file mode 100644 index 0000000..13ff366 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/Makefile @@ -0,0 +1,10 @@ +obj-$(CONFIG_SWCONFIG_B53) += b53_common.o + +obj-$(CONFIG_SWCONFIG_B53_PHY_FIXUP) += b53_phy_fixup.o + +obj-$(CONFIG_SWCONFIG_B53_MMAP_DRIVER) += b53_mmap.o +obj-$(CONFIG_SWCONFIG_B53_SRAB_DRIVER) += b53_srab.o +obj-$(CONFIG_SWCONFIG_B53_PHY_DRIVER) += b53_mdio.o +obj-$(CONFIG_SWCONFIG_B53_SPI_DRIVER) += b53_spi.o + +ccflags-y += -Werror diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_common.c b/ipq806x/files-5.4/drivers/net/phy/b53/b53_common.c new file mode 100644 index 0000000..030c5c8 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_common.c @@ -0,0 +1,1730 @@ +/* + * B53 switch driver main logic + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "b53_regs.h" +#include "b53_priv.h" + +/* buffer size needed for displaying all MIBs with max'd values */ +#define B53_BUF_SIZE 1188 + +struct b53_mib_desc { + u8 size; + u8 offset; + const char *name; +}; + +/* BCM5365 MIB counters */ +static const struct b53_mib_desc b53_mibs_65[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, + { }, +}; + +#define B63XX_MIB_TXB_ID 0 /* TxOctets */ +#define B63XX_MIB_RXB_ID 14 /* RxOctets */ + +/* BCM63xx MIB counters */ +static const struct b53_mib_desc b53_mibs_63xx[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x0c, "TxQoSPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x3c, "TxQoSOctets" }, + { 8, 0x44, "RxOctets" }, + { 4, 0x4c, "RxUndersizePkts" }, + { 4, 0x50, "RxPausePkts" }, + { 4, 0x54, "Pkts64Octets" }, + { 4, 0x58, "Pkts65to127Octets" }, + { 4, 0x5c, "Pkts128to255Octets" }, + { 4, 0x60, "Pkts256to511Octets" }, + { 4, 0x64, "Pkts512to1023Octets" }, + { 4, 0x68, "Pkts1024to1522Octets" }, + { 4, 0x6c, "RxOversizePkts" }, + { 4, 0x70, "RxJabbers" }, + { 4, 0x74, "RxAlignmentErrors" }, + { 4, 0x78, "RxFCSErrors" }, + { 8, 0x7c, "RxGoodOctets" }, + { 4, 0x84, "RxDropPkts" }, + { 4, 0x88, "RxUnicastPkts" }, + { 4, 0x8c, "RxMulticastPkts" }, + { 4, 0x90, "RxBroadcastPkts" }, + { 4, 0x94, "RxSAChanges" }, + { 4, 0x98, "RxFragments" }, + { 4, 0xa0, "RxSymbolErrors" }, + { 4, 0xa4, "RxQoSPkts" }, + { 8, 0xa8, "RxQoSOctets" }, + { 4, 0xb0, "Pkts1523to2047Octets" }, + { 4, 0xb4, "Pkts2048to4095Octets" }, + { 4, 0xb8, "Pkts4096to8191Octets" }, + { 4, 0xbc, "Pkts8192to9728Octets" }, + { 4, 0xc0, "RxDiscarded" }, + { } +}; + +#define B53XX_MIB_TXB_ID 0 /* TxOctets */ +#define B53XX_MIB_RXB_ID 12 /* RxOctets */ + +/* MIB counters */ +static const struct b53_mib_desc b53_mibs[] = { + { 8, 0x00, "TxOctets" }, + { 4, 0x08, "TxDropPkts" }, + { 4, 0x10, "TxBroadcastPkts" }, + { 4, 0x14, "TxMulticastPkts" }, + { 4, 0x18, "TxUnicastPkts" }, + { 4, 0x1c, "TxCollisions" }, + { 4, 0x20, "TxSingleCollision" }, + { 4, 0x24, "TxMultipleCollision" }, + { 4, 0x28, "TxDeferredTransmit" }, + { 4, 0x2c, "TxLateCollision" }, + { 4, 0x30, "TxExcessiveCollision" }, + { 4, 0x38, "TxPausePkts" }, + { 8, 0x50, "RxOctets" }, + { 4, 0x58, "RxUndersizePkts" }, + { 4, 0x5c, "RxPausePkts" }, + { 4, 0x60, "Pkts64Octets" }, + { 4, 0x64, "Pkts65to127Octets" }, + { 4, 0x68, "Pkts128to255Octets" }, + { 4, 0x6c, "Pkts256to511Octets" }, + { 4, 0x70, "Pkts512to1023Octets" }, + { 4, 0x74, "Pkts1024to1522Octets" }, + { 4, 0x78, "RxOversizePkts" }, + { 4, 0x7c, "RxJabbers" }, + { 4, 0x80, "RxAlignmentErrors" }, + { 4, 0x84, "RxFCSErrors" }, + { 8, 0x88, "RxGoodOctets" }, + { 4, 0x90, "RxDropPkts" }, + { 4, 0x94, "RxUnicastPkts" }, + { 4, 0x98, "RxMulticastPkts" }, + { 4, 0x9c, "RxBroadcastPkts" }, + { 4, 0xa0, "RxSAChanges" }, + { 4, 0xa4, "RxFragments" }, + { 4, 0xa8, "RxJumboPkts" }, + { 4, 0xac, "RxSymbolErrors" }, + { 4, 0xc0, "RxDiscarded" }, + { } +}; + +static int b53_do_vlan_op(struct b53_device *dev, u8 op) +{ + unsigned int i; + + b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op); + + for (i = 0; i < 10; i++) { + u8 vta; + + b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta); + if (!(vta & VTA_START_CMD)) + return 0; + + usleep_range(100, 200); + } + + return -EIO; +} + +static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, + u16 untag) +{ + if (is5325(dev)) { + u32 entry = 0; + + if (members) { + entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | + members; + if (dev->core_rev >= 3) + entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; + else + entry |= VA_VALID_25; + } + + b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else if (is5365(dev)) { + u16 entry = 0; + + if (members) + entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | + members | VA_VALID_65; + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | + VTA_RW_STATE_WR | VTA_RW_OP_EN); + } else { + b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); + b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], + (untag << VTE_UNTAG_S) | members); + + b53_do_vlan_op(dev, VTA_CMD_WRITE); + } +} + +void b53_set_forwarding(struct b53_device *dev, int enable) +{ + u8 mgmt; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (enable) + mgmt |= SM_SW_FWD_EN; + else + mgmt &= ~SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static void b53_enable_vlan(struct b53_device *dev, int enable) +{ + u8 mgmt, vc0, vc1, vc4 = 0, vc5; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1); + + if (is5325(dev) || is5365(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5); + } else if (is63xx(dev)) { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5); + } else { + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4); + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); + } + + mgmt &= ~SM_SW_FWD_MODE; + + if (enable) { + vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; + vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; + vc5 |= VC5_DROP_VTABLE_MISS; + + if (is5325(dev)) + vc0 &= ~VC0_RESERVED_1; + + if (is5325(dev) || is5365(dev)) + vc1 |= VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) { + if (dev->allow_vid_4095) + vc5 |= VC5_VID_FFF_EN; + else + vc5 &= ~VC5_VID_FFF_EN; + } + } else { + vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); + vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); + vc4 &= ~VC4_ING_VID_CHECK_MASK; + vc5 &= ~VC5_DROP_VTABLE_MISS; + + if (is5325(dev) || is5365(dev)) + vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; + else + vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S; + + if (is5325(dev) || is5365(dev)) + vc1 &= ~VC1_RX_MCST_TAG_EN; + + if (!is5325(dev) && !is5365(dev)) + vc5 &= ~VC5_VID_FFF_EN; + } + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1); + + if (is5325(dev) || is5365(dev)) { + /* enable the high 8 bit vid check on 5325 */ + if (is5325(dev) && enable) + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, + VC3_HIGH_8BIT_EN); + else + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5); + } else if (is63xx(dev)) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5); + } else { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4); + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5); + } + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); +} + +static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100) +{ + u32 port_mask = 0; + u16 max_size = JMS_MIN_SIZE; + + if (is5325(dev) || is5365(dev)) + return -EINVAL; + + if (enable) { + port_mask = dev->enabled_ports; + max_size = JMS_MAX_SIZE; + if (allow_10_100) + port_mask |= JPM_10_100_JUMBO_EN; + } + + b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask); + return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); +} + +static int b53_flush_arl(struct b53_device *dev) +{ + unsigned int i; + + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); + + for (i = 0; i < 10; i++) { + u8 fast_age_ctrl; + + b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + &fast_age_ctrl); + + if (!(fast_age_ctrl & FAST_AGE_DONE)) + return 0; + + mdelay(1); + } + + pr_warn("time out while flushing ARL\n"); + + return -EINVAL; +} + +static void b53_enable_ports(struct b53_device *dev) +{ + unsigned i; + + b53_for_each_port(dev, i) { + u8 port_ctrl; + u16 pvlan_mask; + + /* + * prevent leaking packets between wan and lan in unmanaged + * mode through port vlans. + */ + if (dev->enable_vlan || is_cpu_port(dev, i)) + pvlan_mask = 0x1ff; + else if (is531x5(dev) || is5301x(dev)) + /* BCM53115 may use a different port as cpu port */ + pvlan_mask = BIT(dev->sw_dev.cpu_port); + else + pvlan_mask = BIT(B53_CPU_PORT); + + /* BCM5325 CPU port is at 8 */ + if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25) + i = B53_CPU_PORT; + + if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7)) + /* disable unused ports 6 & 7 */ + port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; + else if (i == B53_CPU_PORT) + port_ctrl = PORT_CTRL_RX_BCST_EN | + PORT_CTRL_RX_MCST_EN | + PORT_CTRL_RX_UCST_EN; + else + port_ctrl = 0; + + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), + pvlan_mask); + + /* port state is handled by bcm63xx_enet driver */ + if (!is63xx(dev) && !(is5301x(dev) && i == 6)) + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i), + port_ctrl); + } +} + +static void b53_enable_mib(struct b53_device *dev) +{ + u8 gc; + + b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + + gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN); + + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); +} + +static int b53_apply(struct b53_device *dev) +{ + int i; + + /* clear all vlan entries */ + if (is5325(dev) || is5365(dev)) { + for (i = 1; i < dev->sw_dev.vlans; i++) + b53_set_vlan_entry(dev, i, 0, 0); + } else { + b53_do_vlan_op(dev, VTA_CMD_CLEAR); + } + + b53_enable_vlan(dev, dev->enable_vlan); + + /* fill VLAN table */ + if (dev->enable_vlan) { + for (i = 0; i < dev->sw_dev.vlans; i++) { + struct b53_vlan *vlan = &dev->vlans[i]; + + if (!vlan->members) + continue; + + b53_set_vlan_entry(dev, i, vlan->members, vlan->untag); + } + + b53_for_each_port(dev, i) + b53_write16(dev, B53_VLAN_PAGE, + B53_VLAN_PORT_DEF_TAG(i), + dev->ports[i].pvid); + } else { + b53_for_each_port(dev, i) + b53_write16(dev, B53_VLAN_PAGE, + B53_VLAN_PORT_DEF_TAG(i), 1); + + } + + b53_enable_ports(dev); + + if (!is5325(dev) && !is5365(dev)) + b53_set_jumbo(dev, dev->enable_jumbo, 1); + + return 0; +} + +static void b53_switch_reset_gpio(struct b53_device *dev) +{ + int gpio = dev->reset_gpio; + + if (gpio < 0) + return; + + /* + * Reset sequence: RESET low(50ms)->high(20ms) + */ + gpio_set_value(gpio, 0); + mdelay(50); + + gpio_set_value(gpio, 1); + mdelay(20); + + dev->current_page = 0xff; +} + +static int b53_configure_ports_of(struct b53_device *dev) +{ + struct device_node *dn, *pn; + u32 port_num; + + dn = of_get_child_by_name(dev_of_node(dev->dev), "ports"); + + for_each_available_child_of_node(dn, pn) { + struct device_node *fixed_link; + + if (of_property_read_u32(pn, "reg", &port_num)) + continue; + + if (port_num > B53_CPU_PORT) + continue; + + fixed_link = of_get_child_by_name(pn, "fixed-link"); + if (fixed_link) { + u32 spd; + u8 po = GMII_PO_LINK; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) + phy_interface_t mode; +#else + int mode = of_get_phy_mode(pn); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) + of_get_phy_mode(pn, &mode); +#endif + + if (!of_property_read_u32(fixed_link, "speed", &spd)) { + switch (spd) { + case 10: + po |= GMII_PO_SPEED_10M; + break; + case 100: + po |= GMII_PO_SPEED_100M; + break; + case 2000: + if (is_imp_port(dev, port_num)) + po |= PORT_OVERRIDE_SPEED_2000M; + else + po |= GMII_PO_SPEED_2000M; + /* fall through */ + case 1000: + po |= GMII_PO_SPEED_1000M; + break; + } + } + + if (of_property_read_bool(fixed_link, "full-duplex")) + po |= PORT_OVERRIDE_FULL_DUPLEX; + if (of_property_read_bool(fixed_link, "pause")) + po |= GMII_PO_RX_FLOW; + if (of_property_read_bool(fixed_link, "asym-pause")) + po |= GMII_PO_TX_FLOW; + + if (is_imp_port(dev, port_num)) { + po |= PORT_OVERRIDE_EN; + + if (is5325(dev) && + mode == PHY_INTERFACE_MODE_REVMII) + po |= PORT_OVERRIDE_RV_MII_25; + + b53_write8(dev, B53_CTRL_PAGE, + B53_PORT_OVERRIDE_CTRL, po); + + if (is5325(dev) && + mode == PHY_INTERFACE_MODE_REVMII) { + b53_read8(dev, B53_CTRL_PAGE, + B53_PORT_OVERRIDE_CTRL, &po); + if (!(po & PORT_OVERRIDE_RV_MII_25)) + pr_err("Failed to enable reverse MII mode\n"); + return -EINVAL; + } + } else { + po |= GMII_PO_EN; + b53_write8(dev, B53_CTRL_PAGE, + B53_GMII_PORT_OVERRIDE_CTRL(port_num), + po); + } + } + } + + return 0; +} + +static int b53_configure_ports(struct b53_device *dev) +{ + u8 cpu_port = dev->sw_dev.cpu_port; + + /* configure MII port if necessary */ + if (is5325(dev)) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + /* reverse mii needs to be enabled */ + if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override | PORT_OVERRIDE_RV_MII_25); + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + + if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) { + pr_err("Failed to enable reverse MII mode\n"); + return -EINVAL; + } + } + } else if (is531x5(dev) && cpu_port == B53_CPU_PORT) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override | PORT_OVERRIDE_EN | + PORT_OVERRIDE_LINK); + + /* BCM47189 has another interface connected to the port 5 */ + if (dev->enabled_ports & BIT(5)) { + u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(5); + u8 gmii_po; + + b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); + gmii_po |= GMII_PO_LINK | + GMII_PO_RX_FLOW | + GMII_PO_TX_FLOW | + GMII_PO_EN; + b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); + } + } else if (is5301x(dev)) { + if (cpu_port == 8) { + u8 mii_port_override; + + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + &mii_port_override); + mii_port_override |= PORT_OVERRIDE_LINK | + PORT_OVERRIDE_RX_FLOW | + PORT_OVERRIDE_TX_FLOW | + PORT_OVERRIDE_SPEED_2000M | + PORT_OVERRIDE_EN; + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, + mii_port_override); + + /* TODO: Ports 5 & 7 require some extra handling */ + } else { + u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(cpu_port); + u8 gmii_po; + + b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); + gmii_po |= GMII_PO_LINK | + GMII_PO_RX_FLOW | + GMII_PO_TX_FLOW | + GMII_PO_EN | + GMII_PO_SPEED_2000M; + b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); + } + } + + return 0; +} + +static int b53_switch_reset(struct b53_device *dev) +{ + int ret = 0; + u8 mgmt; + + b53_switch_reset_gpio(dev); + + if (is539x(dev)) { + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83); + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00); + } + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + mgmt &= ~SM_SW_FWD_MODE; + mgmt |= SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + pr_err("Failed to enable switch!\n"); + return -EINVAL; + } + } + + /* enable all ports */ + b53_enable_ports(dev); + + if (dev->dev->of_node) + ret = b53_configure_ports_of(dev); + else + ret = b53_configure_ports(dev); + + if (ret) + return ret; + + b53_enable_mib(dev); + + return b53_flush_arl(dev); +} + +/* + * Swconfig glue functions + */ + +static int b53_global_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->enable_vlan; + + return 0; +} + +static int b53_global_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->enable_vlan = val->value.i; + + return 0; +} + +static int b53_global_get_jumbo_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->enable_jumbo; + + return 0; +} + +static int b53_global_set_jumbo_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->enable_jumbo = val->value.i; + + return 0; +} + +static int b53_global_get_4095_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->value.i = priv->allow_vid_4095; + + return 0; +} + +static int b53_global_set_4095_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + priv->allow_vid_4095 = val->value.i; + + return 0; +} + +static int b53_global_get_ports(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + val->len = snprintf(priv->buf, B53_BUF_SIZE, "0x%04x", + priv->enabled_ports); + val->value.s = priv->buf; + + return 0; +} + +static int b53_port_get_pvid(struct switch_dev *dev, int port, int *val) +{ + struct b53_device *priv = sw_to_b53(dev); + + *val = priv->ports[port].pvid; + + return 0; +} + +static int b53_port_set_pvid(struct switch_dev *dev, int port, int val) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (val > 15 && is5325(priv)) + return -EINVAL; + if (val == 4095 && !priv->allow_vid_4095) + return -EINVAL; + + priv->ports[port].pvid = val; + + return 0; +} + +static int b53_vlan_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + struct switch_port *port = &val->value.ports[0]; + struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; + int i; + + val->len = 0; + + if (!vlan->members) + return 0; + + for (i = 0; i < dev->ports; i++) { + if (!(vlan->members & BIT(i))) + continue; + + + if (!(vlan->untag & BIT(i))) + port->flags = BIT(SWITCH_PORT_FLAG_TAGGED); + else + port->flags = 0; + + port->id = i; + val->len++; + port++; + } + + return 0; +} + +static int b53_vlan_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + struct switch_port *port; + struct b53_vlan *vlan = &priv->vlans[val->port_vlan]; + int i; + + /* only BCM5325 and BCM5365 supports VID 0 */ + if (val->port_vlan == 0 && !is5325(priv) && !is5365(priv)) + return -EINVAL; + + /* VLAN 4095 needs special handling */ + if (val->port_vlan == 4095 && !priv->allow_vid_4095) + return -EINVAL; + + port = &val->value.ports[0]; + vlan->members = 0; + vlan->untag = 0; + for (i = 0; i < val->len; i++, port++) { + vlan->members |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) { + vlan->untag |= BIT(port->id); + priv->ports[port->id].pvid = val->port_vlan; + }; + } + + /* ignore disabled ports */ + vlan->members &= priv->enabled_ports; + vlan->untag &= priv->enabled_ports; + + return 0; +} + +static int b53_port_get_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (is_cpu_port(priv, port)) { + link->link = 1; + link->duplex = 1; + link->speed = is5325(priv) || is5365(priv) ? + SWITCH_PORT_SPEED_100 : SWITCH_PORT_SPEED_1000; + link->aneg = 0; + } else if (priv->enabled_ports & BIT(port)) { + u32 speed; + u16 lnk, duplex; + + b53_read16(priv, B53_STAT_PAGE, B53_LINK_STAT, &lnk); + b53_read16(priv, B53_STAT_PAGE, priv->duplex_reg, &duplex); + + lnk = (lnk >> port) & 1; + duplex = (duplex >> port) & 1; + + if (is5325(priv) || is5365(priv)) { + u16 tmp; + + b53_read16(priv, B53_STAT_PAGE, B53_SPEED_STAT, &tmp); + speed = SPEED_PORT_FE(tmp, port); + } else { + b53_read32(priv, B53_STAT_PAGE, B53_SPEED_STAT, &speed); + speed = SPEED_PORT_GE(speed, port); + } + + link->link = lnk; + if (lnk) { + link->duplex = duplex; + switch (speed) { + case SPEED_STAT_10M: + link->speed = SWITCH_PORT_SPEED_10; + break; + case SPEED_STAT_100M: + link->speed = SWITCH_PORT_SPEED_100; + break; + case SPEED_STAT_1000M: + link->speed = SWITCH_PORT_SPEED_1000; + break; + } + } + + link->aneg = 1; + } else { + link->link = 0; + } + + return 0; + +} + +static int b53_port_set_link(struct switch_dev *sw_dev, int port, + struct switch_port_link *link) +{ + struct b53_device *dev = sw_to_b53(sw_dev); + + /* + * TODO: BCM63XX requires special handling as it can have external phys + * and ports might be GE or only FE + */ + if (is63xx(dev)) + return -ENOTSUPP; + + if (port == sw_dev->cpu_port) + return -EINVAL; + + if (!(BIT(port) & dev->enabled_ports)) + return -EINVAL; + + if (link->speed == SWITCH_PORT_SPEED_1000 && + (is5325(dev) || is5365(dev))) + return -EINVAL; + + if (link->speed == SWITCH_PORT_SPEED_1000 && !link->duplex) + return -EINVAL; + + return switch_generic_set_link(sw_dev, port, link); +} + +static int b53_phy_read16(struct switch_dev *dev, int addr, u8 reg, u16 *value) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (priv->ops->phy_read16) + return priv->ops->phy_read16(priv, addr, reg, value); + + return b53_read16(priv, B53_PORT_MII_PAGE(addr), reg, value); +} + +static int b53_phy_write16(struct switch_dev *dev, int addr, u8 reg, u16 value) +{ + struct b53_device *priv = sw_to_b53(dev); + + if (priv->ops->phy_write16) + return priv->ops->phy_write16(priv, addr, reg, value); + + return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg, value); +} + +static int b53_global_reset_switch(struct switch_dev *dev) +{ + struct b53_device *priv = sw_to_b53(dev); + + /* reset vlans */ + priv->enable_vlan = 0; + priv->enable_jumbo = 0; + priv->allow_vid_4095 = 0; + + memset(priv->vlans, 0, sizeof(*priv->vlans) * dev->vlans); + memset(priv->ports, 0, sizeof(*priv->ports) * dev->ports); + + return b53_switch_reset(priv); +} + +static int b53_global_apply_config(struct switch_dev *dev) +{ + struct b53_device *priv = sw_to_b53(dev); + + /* disable switching */ + b53_set_forwarding(priv, 0); + + b53_apply(priv); + + /* enable switching */ + b53_set_forwarding(priv, 1); + + return 0; +} + + +static int b53_global_reset_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *priv = sw_to_b53(dev); + u8 gc; + + b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); + + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB); + mdelay(1); + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB); + mdelay(1); + + return 0; +} + +static int b53_port_get_mib(struct switch_dev *sw_dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct b53_device *dev = sw_to_b53(sw_dev); + const struct b53_mib_desc *mibs; + int port = val->port_vlan; + int len = 0; + + if (!(BIT(port) & dev->enabled_ports)) + return -1; + + if (is5365(dev)) { + if (port == 5) + port = 8; + + mibs = b53_mibs_65; + } else if (is63xx(dev)) { + mibs = b53_mibs_63xx; + } else { + mibs = b53_mibs; + } + + dev->buf[0] = 0; + + for (; mibs->size > 0; mibs++) { + u64 val; + + if (mibs->size == 8) { + b53_read64(dev, B53_MIB_PAGE(port), mibs->offset, &val); + } else { + u32 val32; + + b53_read32(dev, B53_MIB_PAGE(port), mibs->offset, + &val32); + val = val32; + } + + len += snprintf(dev->buf + len, B53_BUF_SIZE - len, + "%-20s: %llu\n", mibs->name, val); + } + + val->len = len; + val->value.s = dev->buf; + + return 0; +} + +static int b53_port_get_stats(struct switch_dev *sw_dev, int port, + struct switch_port_stats *stats) +{ + struct b53_device *dev = sw_to_b53(sw_dev); + const struct b53_mib_desc *mibs; + int txb_id, rxb_id; + u64 rxb, txb; + + if (!(BIT(port) & dev->enabled_ports)) + return -EINVAL; + + txb_id = B53XX_MIB_TXB_ID; + rxb_id = B53XX_MIB_RXB_ID; + + if (is5365(dev)) { + if (port == 5) + port = 8; + + mibs = b53_mibs_65; + } else if (is63xx(dev)) { + mibs = b53_mibs_63xx; + txb_id = B63XX_MIB_TXB_ID; + rxb_id = B63XX_MIB_RXB_ID; + } else { + mibs = b53_mibs; + } + + dev->buf[0] = 0; + + if (mibs->size == 8) { + b53_read64(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &txb); + b53_read64(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &rxb); + } else { + u32 val32; + + b53_read32(dev, B53_MIB_PAGE(port), mibs[txb_id].offset, &val32); + txb = val32; + + b53_read32(dev, B53_MIB_PAGE(port), mibs[rxb_id].offset, &val32); + rxb = val32; + } + + stats->tx_bytes = txb; + stats->rx_bytes = rxb; + + return 0; +} + +static struct switch_attr b53_global_ops_25[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available ports (as bitmask)", + .get = b53_global_get_ports, + }, +}; + +static struct switch_attr b53_global_ops_65[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available ports (as bitmask)", + .get = b53_global_get_ports, + }, + { + .type = SWITCH_TYPE_INT, + .name = "reset_mib", + .description = "Reset MIB counters", + .set = b53_global_reset_mib, + }, +}; + +static struct switch_attr b53_global_ops[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = b53_global_set_vlan_enable, + .get = b53_global_get_vlan_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_STRING, + .name = "ports", + .description = "Available Ports (as bitmask)", + .get = b53_global_get_ports, + }, + { + .type = SWITCH_TYPE_INT, + .name = "reset_mib", + .description = "Reset MIB counters", + .set = b53_global_reset_mib, + }, + { + .type = SWITCH_TYPE_INT, + .name = "enable_jumbo", + .description = "Enable Jumbo Frames", + .set = b53_global_set_jumbo_enable, + .get = b53_global_get_jumbo_enable, + .max = 1, + }, + { + .type = SWITCH_TYPE_INT, + .name = "allow_vid_4095", + .description = "Allow VID 4095", + .set = b53_global_set_4095_enable, + .get = b53_global_get_4095_enable, + .max = 1, + }, +}; + +static struct switch_attr b53_port_ops[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get port's MIB counters", + .get = b53_port_get_mib, + }, +}; + +static struct switch_attr b53_no_ops[] = { +}; + +static const struct switch_dev_ops b53_switch_ops_25 = { + .attr_global = { + .attr = b53_global_ops_25, + .n_attr = ARRAY_SIZE(b53_global_ops_25), + }, + .attr_port = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, + .set_port_link = b53_port_set_link, + .get_port_stats = b53_port_get_stats, + .phy_read16 = b53_phy_read16, + .phy_write16 = b53_phy_write16, +}; + +static const struct switch_dev_ops b53_switch_ops_65 = { + .attr_global = { + .attr = b53_global_ops_65, + .n_attr = ARRAY_SIZE(b53_global_ops_65), + }, + .attr_port = { + .attr = b53_port_ops, + .n_attr = ARRAY_SIZE(b53_port_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, + .set_port_link = b53_port_set_link, + .get_port_stats = b53_port_get_stats, + .phy_read16 = b53_phy_read16, + .phy_write16 = b53_phy_write16, +}; + +static const struct switch_dev_ops b53_switch_ops = { + .attr_global = { + .attr = b53_global_ops, + .n_attr = ARRAY_SIZE(b53_global_ops), + }, + .attr_port = { + .attr = b53_port_ops, + .n_attr = ARRAY_SIZE(b53_port_ops), + }, + .attr_vlan = { + .attr = b53_no_ops, + .n_attr = ARRAY_SIZE(b53_no_ops), + }, + + .get_vlan_ports = b53_vlan_get_ports, + .set_vlan_ports = b53_vlan_set_ports, + .get_port_pvid = b53_port_get_pvid, + .set_port_pvid = b53_port_set_pvid, + .apply_config = b53_global_apply_config, + .reset_switch = b53_global_reset_switch, + .get_port_link = b53_port_get_link, + .set_port_link = b53_port_set_link, + .get_port_stats = b53_port_get_stats, + .phy_read16 = b53_phy_read16, + .phy_write16 = b53_phy_write16, +}; + +struct b53_chip_data { + u32 chip_id; + const char *dev_name; + const char *alias; + u16 vlans; + u16 enabled_ports; + u8 cpu_port; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; + const struct switch_dev_ops *sw_ops; +}; + +#define B53_VTA_REGS \ + { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY } +#define B53_VTA_REGS_9798 \ + { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 } +#define B53_VTA_REGS_63XX \ + { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX } + +static const struct b53_chip_data b53_switch_chips[] = { + { + .chip_id = BCM5325_DEVICE_ID, + .dev_name = "BCM5325", + .alias = "bcm5325", + .vlans = 16, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + .sw_ops = &b53_switch_ops_25, + }, + { + .chip_id = BCM5365_DEVICE_ID, + .dev_name = "BCM5365", + .alias = "bcm5365", + .vlans = 256, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + .sw_ops = &b53_switch_ops_65, + }, + { + .chip_id = BCM5395_DEVICE_ID, + .dev_name = "BCM5395", + .alias = "bcm5395", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM5397_DEVICE_ID, + .dev_name = "BCM5397", + .alias = "bcm5397", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM5398_DEVICE_ID, + .dev_name = "BCM5398", + .alias = "bcm5398", + .vlans = 4096, + .enabled_ports = 0x7f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53115_DEVICE_ID, + .dev_name = "BCM53115", + .alias = "bcm53115", + .vlans = 4096, + .enabled_ports = 0x1f, + .vta_regs = B53_VTA_REGS, + .cpu_port = B53_CPU_PORT, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53125_DEVICE_ID, + .dev_name = "BCM53125", + .alias = "bcm53125", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53128_DEVICE_ID, + .dev_name = "BCM53128", + .alias = "bcm53128", + .vlans = 4096, + .enabled_ports = 0x1ff, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM63XX_DEVICE_ID, + .dev_name = "BCM63xx", + .alias = "bcm63xx", + .vlans = 4096, + .enabled_ports = 0, /* pdata must provide them */ + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_63XX, + .duplex_reg = B53_DUPLEX_STAT_63XX, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53010_DEVICE_ID, + .dev_name = "BCM53010", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53011_DEVICE_ID, + .dev_name = "BCM53011", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53012_DEVICE_ID, + .dev_name = "BCM53012", + .alias = "bcm53011", + .vlans = 4096, + .enabled_ports = 0x1bf, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53018_DEVICE_ID, + .dev_name = "BCM53018", + .alias = "bcm53018", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, + { + .chip_id = BCM53019_DEVICE_ID, + .dev_name = "BCM53019", + .alias = "bcm53019", + .vlans = 4096, + .enabled_ports = 0x1f, + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + .sw_ops = &b53_switch_ops, + }, +}; + +static int b53_switch_init_of(struct b53_device *dev) +{ + struct device_node *dn, *pn; + const char *alias; + u32 port_num; + u16 ports = 0; + + dn = of_get_child_by_name(dev_of_node(dev->dev), "ports"); + if (!dn) + return -EINVAL; + + for_each_available_child_of_node(dn, pn) { + const char *label; + int len; + + if (of_property_read_u32(pn, "reg", &port_num)) + continue; + + if (port_num > B53_CPU_PORT) + continue; + + ports |= BIT(port_num); + + label = of_get_property(pn, "label", &len); + if (label && !strcmp(label, "cpu")) + dev->sw_dev.cpu_port = port_num; + } + + dev->enabled_ports = ports; + + if (!of_property_read_string(dev_of_node(dev->dev), "lede,alias", + &alias)) + dev->sw_dev.alias = devm_kstrdup(dev->dev, alias, GFP_KERNEL); + + return 0; +} + +static int b53_switch_init(struct b53_device *dev) +{ + struct switch_dev *sw_dev = &dev->sw_dev; + unsigned i; + int ret; + + for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { + const struct b53_chip_data *chip = &b53_switch_chips[i]; + + if (chip->chip_id == dev->chip_id) { + sw_dev->name = chip->dev_name; + if (!sw_dev->alias) + sw_dev->alias = chip->alias; + if (!dev->enabled_ports) + dev->enabled_ports = chip->enabled_ports; + dev->duplex_reg = chip->duplex_reg; + dev->vta_regs[0] = chip->vta_regs[0]; + dev->vta_regs[1] = chip->vta_regs[1]; + dev->vta_regs[2] = chip->vta_regs[2]; + dev->jumbo_pm_reg = chip->jumbo_pm_reg; + sw_dev->ops = chip->sw_ops; + sw_dev->cpu_port = chip->cpu_port; + sw_dev->vlans = chip->vlans; + break; + } + } + + if (!sw_dev->name) + return -EINVAL; + + /* check which BCM5325x version we have */ + if (is5325(dev)) { + u8 vc4; + + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); + + /* check reserved bits */ + switch (vc4 & 3) { + case 1: + /* BCM5325E */ + break; + case 3: + /* BCM5325F - do not use port 4 */ + dev->enabled_ports &= ~BIT(4); + break; + default: +/* On the BCM47XX SoCs this is the supported internal switch.*/ +#ifndef CONFIG_BCM47XX + /* BCM5325M */ + return -EINVAL; +#else + break; +#endif + } + } else if (dev->chip_id == BCM53115_DEVICE_ID) { + u64 strap_value; + + b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); + /* use second IMP port if GMII is enabled */ + if (strap_value & SV_GMII_CTRL_115) + sw_dev->cpu_port = 5; + } + + if (dev_of_node(dev->dev)) { + ret = b53_switch_init_of(dev); + if (ret) + return ret; + } + + dev->enabled_ports |= BIT(sw_dev->cpu_port); + sw_dev->ports = fls(dev->enabled_ports); + + dev->ports = devm_kzalloc(dev->dev, + sizeof(struct b53_port) * sw_dev->ports, + GFP_KERNEL); + if (!dev->ports) + return -ENOMEM; + + dev->vlans = devm_kzalloc(dev->dev, + sizeof(struct b53_vlan) * sw_dev->vlans, + GFP_KERNEL); + if (!dev->vlans) + return -ENOMEM; + + dev->buf = devm_kzalloc(dev->dev, B53_BUF_SIZE, GFP_KERNEL); + if (!dev->buf) + return -ENOMEM; + + dev->reset_gpio = b53_switch_get_reset_gpio(dev); + if (dev->reset_gpio >= 0) { + ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, + GPIOF_OUT_INIT_HIGH, "robo_reset"); + if (ret) + return ret; + } + + return b53_switch_reset(dev); +} + +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv) +{ + struct b53_device *dev; + + dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->dev = base; + dev->ops = ops; + dev->priv = priv; + mutex_init(&dev->reg_mutex); + + return dev; +} +EXPORT_SYMBOL(b53_switch_alloc); + +int b53_switch_detect(struct b53_device *dev) +{ + u32 id32; + u16 tmp; + u8 id8; + int ret; + + ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8); + if (ret) + return ret; + + switch (id8) { + case 0: + /* + * BCM5325 and BCM5365 do not have this register so reads + * return 0. But the read operation did succeed, so assume + * this is one of them. + * + * Next check if we can write to the 5325's VTA register; for + * 5365 it is read only. + */ + + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); + b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); + + if (tmp == 0xf) + dev->chip_id = BCM5325_DEVICE_ID; + else + dev->chip_id = BCM5365_DEVICE_ID; + break; + case BCM5395_DEVICE_ID: + case BCM5397_DEVICE_ID: + case BCM5398_DEVICE_ID: + dev->chip_id = id8; + break; + default: + ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32); + if (ret) + return ret; + + switch (id32) { + case BCM53115_DEVICE_ID: + case BCM53125_DEVICE_ID: + case BCM53128_DEVICE_ID: + case BCM53010_DEVICE_ID: + case BCM53011_DEVICE_ID: + case BCM53012_DEVICE_ID: + case BCM53018_DEVICE_ID: + case BCM53019_DEVICE_ID: + dev->chip_id = id32; + break; + default: + pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", + id8, id32); + return -ENODEV; + } + } + + if (dev->chip_id == BCM5325_DEVICE_ID) + return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25, + &dev->core_rev); + else + return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, + &dev->core_rev); +} +EXPORT_SYMBOL(b53_switch_detect); + +int b53_switch_register(struct b53_device *dev) +{ + int ret; + + if (dev->pdata) { + dev->chip_id = dev->pdata->chip_id; + dev->enabled_ports = dev->pdata->enabled_ports; + dev->sw_dev.alias = dev->pdata->alias; + } + + if (!dev->chip_id && b53_switch_detect(dev)) + return -EINVAL; + + ret = b53_switch_init(dev); + if (ret) + return ret; + + pr_info("found switch: %s, rev %i\n", dev->sw_dev.name, dev->core_rev); + + return register_switch(&dev->sw_dev, NULL); +} +EXPORT_SYMBOL(b53_switch_register); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 switch library"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_mdio.c b/ipq806x/files-5.4/drivers/net/phy/b53/b53_mdio.c new file mode 100644 index 0000000..98cdbff --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_mdio.c @@ -0,0 +1,468 @@ +/* + * B53 register access through MII registers + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "b53_priv.h" + +#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ + +/* MII registers */ +#define REG_MII_PAGE 0x10 /* MII Page register */ +#define REG_MII_ADDR 0x11 /* MII Address register */ +#define REG_MII_DATA0 0x18 /* MII Data register 0 */ +#define REG_MII_DATA1 0x19 /* MII Data register 1 */ +#define REG_MII_DATA2 0x1a /* MII Data register 2 */ +#define REG_MII_DATA3 0x1b /* MII Data register 3 */ + +#define REG_MII_PAGE_ENABLE BIT(0) +#define REG_MII_ADDR_WRITE BIT(0) +#define REG_MII_ADDR_READ BIT(1) + +static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op) +{ + int i; + u16 v; + int ret; + struct mii_bus *bus = dev->priv; + + if (dev->current_page != page) { + /* set page number */ + v = (page << 8) | REG_MII_PAGE_ENABLE; + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v); + if (ret) + return ret; + dev->current_page = page; + } + + /* set register address */ + v = (reg << 8) | op; + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v); + if (ret) + return ret; + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR); + if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff; + + return 0; +} + +static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); + + return 0; +} + +static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0); + *val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16; + + return 0; +} + +static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 2; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + struct mii_bus *bus = dev->priv; + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 3; i >= 0; i--) { + temp <<= 16; + temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + struct mii_bus *bus = dev->priv; + int ret; + + ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + struct mii_bus *bus = dev->priv; + unsigned int i; + u32 temp = value; + + for (i = 0; i < 2; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); + +} + +static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned i; + u64 temp = value; + + for (i = 0; i < 3; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); + +} + +static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + struct mii_bus *bus = dev->priv; + unsigned i; + u64 temp = value; + + for (i = 0; i < 4; i++) { + int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i, + temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_phy_read16(struct b53_device *dev, int addr, u8 reg, + u16 *value) +{ + struct mii_bus *bus = dev->priv; + + *value = mdiobus_read(bus, addr, reg); + + return 0; +} + +static int b53_mdio_phy_write16(struct b53_device *dev, int addr, u8 reg, + u16 value) +{ + struct mii_bus *bus = dev->priv; + + return mdiobus_write(bus, addr, reg, value); +} + +static struct b53_io_ops b53_mdio_ops = { + .read8 = b53_mdio_read8, + .read16 = b53_mdio_read16, + .read32 = b53_mdio_read32, + .read48 = b53_mdio_read48, + .read64 = b53_mdio_read64, + .write8 = b53_mdio_write8, + .write16 = b53_mdio_write16, + .write32 = b53_mdio_write32, + .write48 = b53_mdio_write48, + .write64 = b53_mdio_write64, + .phy_read16 = b53_mdio_phy_read16, + .phy_write16 = b53_mdio_phy_write16, +}; + +static int b53_phy_probe(struct phy_device *phydev) +{ + struct b53_device *dev; + int ret; + + /* allow the generic phy driver to take over */ + if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0) + return -ENODEV; + + dev = b53_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus); + if (!dev) + return -ENOMEM; + + dev->current_page = 0xff; + dev->priv = phydev->mdio.bus; + dev->ops = &b53_mdio_ops; + dev->pdata = NULL; + mutex_init(&dev->reg_mutex); + + ret = b53_switch_detect(dev); + if (ret) + return ret; + + linkmode_zero(phydev->supported); + if (is5325(dev) || is5365(dev)) + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported); + else + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported); + + linkmode_copy(phydev->advertising, phydev->supported); + + ret = b53_switch_register(dev); + if (ret) { + dev_err(dev->dev, "failed to register switch: %i\n", ret); + return ret; + } + + phydev->priv = dev; + + return 0; +} + +static int b53_phy_config_init(struct phy_device *phydev) +{ + struct b53_device *dev = phydev->priv; + + /* we don't use page 0xff, so force a page set */ + dev->current_page = 0xff; + /* force the ethX as alias */ + dev->sw_dev.alias = phydev->attached_dev->name; + + return 0; +} + +static void b53_phy_remove(struct phy_device *phydev) +{ + struct b53_device *priv = phydev->priv; + + if (!priv) + return; + + b53_switch_remove(priv); + + phydev->priv = NULL; +} + +static int b53_phy_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int b53_phy_read_status(struct phy_device *phydev) +{ + struct b53_device *priv = phydev->priv; + + if (is5325(priv) || is5365(priv)) + phydev->speed = 100; + else + phydev->speed = 1000; + + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + phydev->state = PHY_RUNNING; + + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +static const struct of_device_id b53_of_match_1[] = { + { .compatible = "brcm,bcm5325" }, + { .compatible = "brcm,bcm5395" }, + { .compatible = "brcm,bcm5397" }, + { .compatible = "brcm,bcm5398" }, + { /* sentinel */ }, +}; + +static const struct of_device_id b53_of_match_2[] = { + { .compatible = "brcm,bcm53115" }, + { .compatible = "brcm,bcm53125" }, + { .compatible = "brcm,bcm53128" }, + { /* sentinel */ }, +}; + +static const struct of_device_id b53_of_match_3[] = { + { .compatible = "brcm,bcm5365" }, + { /* sentinel */ }, +}; + +/* BCM5325, BCM539x */ +static struct phy_driver b53_phy_driver_id1 = { + .phy_id = 0x0143bc00, + .name = "Broadcom B53 (1)", + .phy_id_mask = 0x1ffffc00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, + .mdiodrv.driver = { + .name = "bcm539x", + .of_match_table = b53_of_match_1, + }, +}; + +/* BCM53125, BCM53128 */ +static struct phy_driver b53_phy_driver_id2 = { + .phy_id = 0x03625c00, + .name = "Broadcom B53 (2)", + .phy_id_mask = 0x1ffffc00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, + .mdiodrv.driver = { + .name = "bcm531xx", + .of_match_table = b53_of_match_2, + }, +}; + +/* BCM5365 */ +static struct phy_driver b53_phy_driver_id3 = { + .phy_id = 0x00406300, + .name = "Broadcom B53 (3)", + .phy_id_mask = 0x1fffff00, + .features = 0, + .probe = b53_phy_probe, + .remove = b53_phy_remove, + .config_aneg = b53_phy_config_aneg, + .config_init = b53_phy_config_init, + .read_status = b53_phy_read_status, + .mdiodrv.driver = { + .name = "bcm5365", + .of_match_table = b53_of_match_3, + }, +}; + +int __init b53_phy_driver_register(void) +{ + int ret; + + ret = phy_driver_register(&b53_phy_driver_id1, THIS_MODULE); + if (ret) + return ret; + + ret = phy_driver_register(&b53_phy_driver_id2, THIS_MODULE); + if (ret) + goto err1; + + ret = phy_driver_register(&b53_phy_driver_id3, THIS_MODULE); + if (!ret) + return 0; + + phy_driver_unregister(&b53_phy_driver_id2); +err1: + phy_driver_unregister(&b53_phy_driver_id1); + return ret; +} + +void __exit b53_phy_driver_unregister(void) +{ + phy_driver_unregister(&b53_phy_driver_id3); + phy_driver_unregister(&b53_phy_driver_id2); + phy_driver_unregister(&b53_phy_driver_id1); +} + +module_init(b53_phy_driver_register); +module_exit(b53_phy_driver_unregister); + +MODULE_DESCRIPTION("B53 MDIO access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_mmap.c b/ipq806x/files-5.4/drivers/net/phy/b53/b53_mmap.c new file mode 100644 index 0000000..ab1895e --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_mmap.c @@ -0,0 +1,241 @@ +/* + * B53 register access through memory mapped registers + * + * Copyright (C) 2012-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "b53_priv.h" + +static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + u8 __iomem *regs = dev->priv; + + *val = readb(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + *val = readw_be(regs + (page << 8) + reg); + else + *val = readw(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + *val = readl_be(regs + (page << 8) + reg); + else + *val = readl(regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u16 lo; + u32 hi; + + b53_mmap_read16(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 2, &hi); + + *val = ((u64)hi << 16) | lo; + } else { + u32 lo; + u16 hi; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read16(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + } + + return 0; +} + +static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u32 hi, lo; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_read32(dev, page, reg, &lo); + b53_mmap_read32(dev, page, reg + 4, &hi); + + *val = ((u64)hi << 32) | lo; + + return 0; +} + +static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + u8 __iomem *regs = dev->priv; + + writeb(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + writew_be(value, regs + (page << 8) + reg); + else + writew(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + u8 __iomem *regs = dev->priv; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + if (dev->pdata && dev->pdata->big_endian) + writel_be(value, regs + (page << 8) + reg); + else + writel(value, regs + (page << 8) + reg); + + return 0; +} + +static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + if (WARN_ON(reg % 2)) + return -EINVAL; + + if (reg % 4) { + u32 hi = (u32)(value >> 16); + u16 lo = (u16)value; + + b53_mmap_write16(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 2, hi); + } else { + u16 hi = (u16)(value >> 32); + u32 lo = (u32)value; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write16(dev, page, reg + 4, hi); + } + + return 0; +} + +static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u32 hi, lo; + + hi = (u32)(value >> 32); + lo = (u32)value; + + if (WARN_ON(reg % 4)) + return -EINVAL; + + b53_mmap_write32(dev, page, reg, lo); + b53_mmap_write32(dev, page, reg + 4, hi); + + return 0; +} + +static struct b53_io_ops b53_mmap_ops = { + .read8 = b53_mmap_read8, + .read16 = b53_mmap_read16, + .read32 = b53_mmap_read32, + .read48 = b53_mmap_read48, + .read64 = b53_mmap_read64, + .write8 = b53_mmap_write8, + .write16 = b53_mmap_write16, + .write32 = b53_mmap_write32, + .write48 = b53_mmap_write48, + .write64 = b53_mmap_write64, +}; + +static int b53_mmap_probe(struct platform_device *pdev) +{ + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_device *dev; + + if (!pdata) + return -EINVAL; + + dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); + if (!dev) + return -ENOMEM; + + if (pdata) + dev->pdata = pdata; + + platform_set_drvdata(pdev, dev); + + return b53_switch_register(dev); +} + +static int b53_mmap_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static struct platform_driver b53_mmap_driver = { + .probe = b53_mmap_probe, + .remove = b53_mmap_remove, + .driver = { + .name = "b53-switch", + }, +}; + +module_platform_driver(b53_mmap_driver); +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 MMAP access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_phy_fixup.c b/ipq806x/files-5.4/drivers/net/phy/b53/b53_phy_fixup.c new file mode 100644 index 0000000..a19ecce --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_phy_fixup.c @@ -0,0 +1,55 @@ +/* + * B53 PHY Fixup call + * + * Copyright (C) 2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */ + +#define B53_BRCM_OUI_1 0x0143bc00 +#define B53_BRCM_OUI_2 0x03625c00 +#define B53_BRCM_OUI_3 0x00406300 + +static int b53_phy_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u32 phy_id; + + if (dev->mdio.addr != B53_PSEUDO_PHY) + return 0; + + /* read the first port's id */ + phy_id = mdiobus_read(bus, 0, 2) << 16; + phy_id |= mdiobus_read(bus, 0, 3); + + if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 || + (phy_id & 0xfffffc00) == B53_BRCM_OUI_2 || + (phy_id & 0xffffff00) == B53_BRCM_OUI_3) { + dev->phy_id = phy_id; + } + + return 0; +} + +int __init b53_phy_fixup_register(void) +{ + return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup); +} + +subsys_initcall(b53_phy_fixup_register); diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_priv.h b/ipq806x/files-5.4/drivers/net/phy/b53/b53_priv.h new file mode 100644 index 0000000..37c17ae --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_priv.h @@ -0,0 +1,336 @@ +/* + * B53 common definitions + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_PRIV_H +#define __B53_PRIV_H + +#include +#include +#include + +struct b53_device; + +struct b53_io_ops { + int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value); + int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value); + int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value); + int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value); + int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value); + int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value); + int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value); + int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value); + int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value); + int (*phy_read16)(struct b53_device *dev, int addr, u8 reg, u16 *value); + int (*phy_write16)(struct b53_device *dev, int addr, u8 reg, u16 value); +}; + +enum { + BCM5325_DEVICE_ID = 0x25, + BCM5365_DEVICE_ID = 0x65, + BCM5395_DEVICE_ID = 0x95, + BCM5397_DEVICE_ID = 0x97, + BCM5398_DEVICE_ID = 0x98, + BCM53115_DEVICE_ID = 0x53115, + BCM53125_DEVICE_ID = 0x53125, + BCM53128_DEVICE_ID = 0x53128, + BCM63XX_DEVICE_ID = 0x6300, + BCM53010_DEVICE_ID = 0x53010, + BCM53011_DEVICE_ID = 0x53011, + BCM53012_DEVICE_ID = 0x53012, + BCM53018_DEVICE_ID = 0x53018, + BCM53019_DEVICE_ID = 0x53019, +}; + +#define B53_N_PORTS 9 +#define B53_N_PORTS_25 6 + +struct b53_vlan { + unsigned int members:B53_N_PORTS; + unsigned int untag:B53_N_PORTS; +}; + +struct b53_port { + unsigned int pvid:12; +}; + +struct b53_device { + struct switch_dev sw_dev; + struct b53_platform_data *pdata; + + struct mutex reg_mutex; + const struct b53_io_ops *ops; + + /* chip specific data */ + u32 chip_id; + u8 core_rev; + u8 vta_regs[3]; + u8 duplex_reg; + u8 jumbo_pm_reg; + u8 jumbo_size_reg; + int reset_gpio; + + /* used ports mask */ + u16 enabled_ports; + + /* connect specific data */ + u8 current_page; + struct device *dev; + void *priv; + + /* run time configuration */ + unsigned enable_vlan:1; + unsigned enable_jumbo:1; + unsigned allow_vid_4095:1; + + struct b53_port *ports; + struct b53_vlan *vlans; + + char *buf; +}; + +#define b53_for_each_port(dev, i) \ + for (i = 0; i < B53_N_PORTS; i++) \ + if (dev->enabled_ports & BIT(i)) + + + +static inline int is5325(struct b53_device *dev) +{ + return dev->chip_id == BCM5325_DEVICE_ID; +} + +static inline int is5365(struct b53_device *dev) +{ +#ifdef CONFIG_BCM47XX + return dev->chip_id == BCM5365_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5397_98(struct b53_device *dev) +{ + return dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is539x(struct b53_device *dev) +{ + return dev->chip_id == BCM5395_DEVICE_ID || + dev->chip_id == BCM5397_DEVICE_ID || + dev->chip_id == BCM5398_DEVICE_ID; +} + +static inline int is531x5(struct b53_device *dev) +{ + return dev->chip_id == BCM53115_DEVICE_ID || + dev->chip_id == BCM53125_DEVICE_ID || + dev->chip_id == BCM53128_DEVICE_ID; +} + +static inline int is63xx(struct b53_device *dev) +{ +#ifdef CONFIG_BCM63XX + return dev->chip_id == BCM63XX_DEVICE_ID; +#else + return 0; +#endif +} + +static inline int is5301x(struct b53_device *dev) +{ + return dev->chip_id == BCM53010_DEVICE_ID || + dev->chip_id == BCM53011_DEVICE_ID || + dev->chip_id == BCM53012_DEVICE_ID || + dev->chip_id == BCM53018_DEVICE_ID || + dev->chip_id == BCM53019_DEVICE_ID; +} + +#define B53_CPU_PORT_25 5 +#define B53_CPU_PORT 8 + +static inline int is_cpu_port(struct b53_device *dev, int port) +{ + return dev->sw_dev.cpu_port == port; +} + +static inline int is_imp_port(struct b53_device *dev, int port) +{ + if (is5325(dev) || is5365(dev)) + return port == B53_CPU_PORT_25; + else + return port == B53_CPU_PORT; +} + +static inline struct b53_device *sw_to_b53(struct switch_dev *sw) +{ + return container_of(sw, struct b53_device, sw_dev); +} + +struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, + void *priv); + +int b53_switch_detect(struct b53_device *dev); + +int b53_switch_register(struct b53_device *dev); + +static inline void b53_switch_remove(struct b53_device *dev) +{ + unregister_switch(&dev->sw_dev); +} + +static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read8(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read16(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read32(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read48(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->read64(dev, page, reg, val); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write8(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write16(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write32(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write48(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + int ret; + + mutex_lock(&dev->reg_mutex); + ret = dev->ops->write64(dev, page, reg, value); + mutex_unlock(&dev->reg_mutex); + + return ret; +} + +#ifdef CONFIG_BCM47XX +#include +#endif + +#include +#include + +static inline int b53_switch_get_reset_gpio(struct b53_device *dev) +{ +#ifdef CONFIG_BCM47XX + enum bcm47xx_board board = bcm47xx_board_get(); + + switch (board) { + case BCM47XX_BOARD_LINKSYS_WRT300NV11: + case BCM47XX_BOARD_LINKSYS_WRT310NV1: + return 8; + default: + break; + } +#endif + + return bcm47xx_nvram_gpio_pin("robo_reset"); +} + +#endif diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_regs.h b/ipq806x/files-5.4/drivers/net/phy/b53/b53_regs.h new file mode 100644 index 0000000..f0bf674 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_regs.h @@ -0,0 +1,348 @@ +/* + * B53 register definitions + * + * Copyright (C) 2004 Broadcom Corporation + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __B53_REGS_H +#define __B53_REGS_H + +/* Management Port (SMP) Page offsets */ +#define B53_CTRL_PAGE 0x00 /* Control */ +#define B53_STAT_PAGE 0x01 /* Status */ +#define B53_MGMT_PAGE 0x02 /* Management Mode */ +#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */ +#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */ +#define B53_ARLIO_PAGE 0x05 /* ARL Access */ +#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ +#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ + +/* PHY Registers */ +#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ +#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */ +#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */ + +/* MIB registers */ +#define B53_MIB_PAGE(i) (0x20 + (i)) + +/* Quality of Service (QoS) Registers */ +#define B53_QOS_PAGE 0x30 + +/* Port VLAN Page */ +#define B53_PVLAN_PAGE 0x31 + +/* VLAN Registers */ +#define B53_VLAN_PAGE 0x34 + +/* Jumbo Frame Registers */ +#define B53_JUMBO_PAGE 0x40 + +/* CFP Configuration Registers Page */ +#define B53_CFP_PAGE 0xa1 + +/************************************************************************* + * Control Page registers + *************************************************************************/ + +/* Port Control Register (8 bit) */ +#define B53_PORT_CTRL(i) (0x00 + (i)) +#define PORT_CTRL_RX_DISABLE BIT(0) +#define PORT_CTRL_TX_DISABLE BIT(1) +#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */ +#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */ +#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */ +#define PORT_CTRL_STP_STATE_S 5 +#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S) + +/* SMP Control Register (8 bit) */ +#define B53_SMP_CTRL 0x0a + +/* Switch Mode Control Register (8 bit) */ +#define B53_SWITCH_MODE 0x0b +#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */ +#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */ + +/* IMP Port state override register (8 bit) */ +#define B53_PORT_OVERRIDE_CTRL 0x0e +#define PORT_OVERRIDE_LINK BIT(0) +#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define PORT_OVERRIDE_SPEED_S 2 +#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */ +#define PORT_OVERRIDE_RX_FLOW BIT(4) +#define PORT_OVERRIDE_TX_FLOW BIT(5) +#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */ +#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */ + +/* Power-down mode control */ +#define B53_PD_MODE_CTRL_25 0x0f + +/* IP Multicast control (8 bit) */ +#define B53_IP_MULTICAST_CTRL 0x21 +#define B53_IPMC_FWD_EN BIT(1) +#define B53_UC_FWD_EN BIT(6) +#define B53_MC_FWD_EN BIT(7) + +/* (16 bit) */ +#define B53_UC_FLOOD_MASK 0x32 +#define B53_MC_FLOOD_MASK 0x34 +#define B53_IPMC_FLOOD_MASK 0x36 + +/* + * Override Ports 0-7 State on devices with xMII interfaces (8 bit) + * + * For port 8 still use B53_PORT_OVERRIDE_CTRL + * Please note that not all ports are available on every hardware, e.g. BCM5301X + * don't include overriding port 6, BCM63xx also have some limitations. + */ +#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i)) +#define GMII_PO_LINK BIT(0) +#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define GMII_PO_SPEED_S 2 +#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S) +#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S) +#define GMII_PO_RX_FLOW BIT(4) +#define GMII_PO_TX_FLOW BIT(5) +#define GMII_PO_EN BIT(6) /* Use the register contents */ +#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */ + +/* Software reset register (8 bit) */ +#define B53_SOFTRESET 0x79 + +/* Fast Aging Control register (8 bit) */ +#define B53_FAST_AGE_CTRL 0x88 +#define FAST_AGE_STATIC BIT(0) +#define FAST_AGE_DYNAMIC BIT(1) +#define FAST_AGE_PORT BIT(2) +#define FAST_AGE_VLAN BIT(3) +#define FAST_AGE_STP BIT(4) +#define FAST_AGE_MC BIT(5) +#define FAST_AGE_DONE BIT(7) + +/************************************************************************* + * Status Page registers + *************************************************************************/ + +/* Link Status Summary Register (16bit) */ +#define B53_LINK_STAT 0x00 + +/* Link Status Change Register (16 bit) */ +#define B53_LINK_STAT_CHANGE 0x02 + +/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ +#define B53_SPEED_STAT 0x04 +#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) +#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) +#define SPEED_STAT_10M 0 +#define SPEED_STAT_100M 1 +#define SPEED_STAT_1000M 2 + +/* Duplex Status Summary (16 bit) */ +#define B53_DUPLEX_STAT_FE 0x06 +#define B53_DUPLEX_STAT_GE 0x08 +#define B53_DUPLEX_STAT_63XX 0x0c + +/* Revision ID register for BCM5325 */ +#define B53_REV_ID_25 0x50 + +/* Strap Value (48 bit) */ +#define B53_STRAP_VALUE 0x70 +#define SV_GMII_CTRL_115 BIT(27) + +/************************************************************************* + * Management Mode Page Registers + *************************************************************************/ + +/* Global Management Config Register (8 bit) */ +#define B53_GLOBAL_CONFIG 0x00 +#define GC_RESET_MIB 0x01 +#define GC_RX_BPDU_EN 0x02 +#define GC_MIB_AC_HDR_EN 0x10 +#define GC_MIB_AC_EN 0x20 +#define GC_FRM_MGMT_PORT_M 0xC0 +#define GC_FRM_MGMT_PORT_04 0x00 +#define GC_FRM_MGMT_PORT_MII 0x80 + +/* Broadcom Header control register (8 bit) */ +#define B53_BRCM_HDR 0x03 +#define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */ +#define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */ + +/* Device ID register (8 or 32 bit) */ +#define B53_DEVICE_ID 0x30 + +/* Revision ID register (8 bit) */ +#define B53_REV_ID 0x40 + +/************************************************************************* + * ARL Access Page Registers + *************************************************************************/ + +/* VLAN Table Access Register (8 bit) */ +#define B53_VT_ACCESS 0x80 +#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */ +#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */ +#define VTA_CMD_WRITE 0 +#define VTA_CMD_READ 1 +#define VTA_CMD_CLEAR 2 +#define VTA_START_CMD BIT(7) + +/* VLAN Table Index Register (16 bit) */ +#define B53_VT_INDEX 0x81 +#define B53_VT_INDEX_9798 0x61 +#define B53_VT_INDEX_63XX 0x62 + +/* VLAN Table Entry Register (32 bit) */ +#define B53_VT_ENTRY 0x83 +#define B53_VT_ENTRY_9798 0x63 +#define B53_VT_ENTRY_63XX 0x64 +#define VTE_MEMBERS 0x1ff +#define VTE_UNTAG_S 9 +#define VTE_UNTAG (0x1ff << 9) + +/************************************************************************* + * Port VLAN Registers + *************************************************************************/ + +/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */ +#define B53_PVLAN_PORT_MASK(i) ((i) * 2) + +/************************************************************************* + * 802.1Q Page Registers + *************************************************************************/ + +/* Global QoS Control (8 bit) */ +#define B53_QOS_GLOBAL_CTL 0x00 + +/* Enable 802.1Q for individual Ports (16 bit) */ +#define B53_802_1P_EN 0x04 + +/************************************************************************* + * VLAN Page Registers + *************************************************************************/ + +/* VLAN Control 0 (8 bit) */ +#define B53_VLAN_CTRL0 0x00 +#define VC0_8021PF_CTRL_MASK 0x3 +#define VC0_8021PF_CTRL_NONE 0x0 +#define VC0_8021PF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021PF_CTRL_CHANGE_VID 0x2 +#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3 +#define VC0_8021QF_CTRL_MASK 0xc +#define VC0_8021QF_CTRL_CHANGE_PRI 0x1 +#define VC0_8021QF_CTRL_CHANGE_VID 0x2 +#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3 +#define VC0_RESERVED_1 BIT(1) +#define VC0_DROP_VID_MISS BIT(4) +#define VC0_VID_HASH_VID BIT(5) +#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */ +#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */ + +/* VLAN Control 1 (8 bit) */ +#define B53_VLAN_CTRL1 0x01 +#define VC1_RX_MCST_TAG_EN BIT(1) +#define VC1_RX_MCST_FWD_EN BIT(2) +#define VC1_RX_MCST_UNTAG_EN BIT(3) + +/* VLAN Control 2 (8 bit) */ +#define B53_VLAN_CTRL2 0x02 + +/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */ +#define B53_VLAN_CTRL3 0x03 +#define B53_VLAN_CTRL3_63XX 0x04 +#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */ +#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */ + +/* VLAN Control 4 (8 bit) */ +#define B53_VLAN_CTRL4 0x05 +#define B53_VLAN_CTRL4_25 0x04 +#define B53_VLAN_CTRL4_63XX 0x06 +#define VC4_ING_VID_CHECK_S 6 +#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S) +#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */ +#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */ +#define VC4_NO_ING_VID_CHK 2 /* do not check */ +#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */ + +/* VLAN Control 5 (8 bit) */ +#define B53_VLAN_CTRL5 0x06 +#define B53_VLAN_CTRL5_25 0x05 +#define B53_VLAN_CTRL5_63XX 0x07 +#define VC5_VID_FFF_EN BIT(2) +#define VC5_DROP_VTABLE_MISS BIT(3) + +/* VLAN Control 6 (8 bit) */ +#define B53_VLAN_CTRL6 0x07 +#define B53_VLAN_CTRL6_63XX 0x08 + +/* VLAN Table Access Register (16 bit) */ +#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */ +#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */ +#define VTA_VID_LOW_MASK_25 0xf +#define VTA_VID_LOW_MASK_65 0xff +#define VTA_VID_HIGH_S_25 4 +#define VTA_VID_HIGH_S_65 8 +#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E) +#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65) +#define VTA_RW_STATE BIT(12) +#define VTA_RW_STATE_RD 0 +#define VTA_RW_STATE_WR BIT(12) +#define VTA_RW_OP_EN BIT(13) + +/* VLAN Read/Write Registers for (16/32 bit) */ +#define B53_VLAN_WRITE_25 0x08 +#define B53_VLAN_WRITE_65 0x0a +#define B53_VLAN_READ 0x0c +#define VA_MEMBER_MASK 0x3f +#define VA_UNTAG_S_25 6 +#define VA_UNTAG_MASK_25 0x3f +#define VA_UNTAG_S_65 7 +#define VA_UNTAG_MASK_65 0x1f +#define VA_VID_HIGH_S 12 +#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S) +#define VA_VALID_25 BIT(20) +#define VA_VALID_25_R4 BIT(24) +#define VA_VALID_65 BIT(14) + +/* VLAN Port Default Tag (16 bit) */ +#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i)) + +/************************************************************************* + * Jumbo Frame Page Registers + *************************************************************************/ + +/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */ +#define B53_JUMBO_PORT_MASK 0x01 +#define B53_JUMBO_PORT_MASK_63XX 0x04 +#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */ + +/* Good Frame Max Size without 802.1Q TAG (16 bit) */ +#define B53_JUMBO_MAX_SIZE 0x05 +#define B53_JUMBO_MAX_SIZE_63XX 0x08 +#define JMS_MIN_SIZE 1518 +#define JMS_MAX_SIZE 9724 + +/************************************************************************* + * CFP Configuration Page Registers + *************************************************************************/ + +/* CFP Control Register with ports map (8 bit) */ +#define B53_CFP_CTRL 0x00 + +#endif /* !__B53_REGS_H */ diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_spi.c b/ipq806x/files-5.4/drivers/net/phy/b53/b53_spi.c new file mode 100644 index 0000000..efc8f7e --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_spi.c @@ -0,0 +1,344 @@ +/* + * B53 register access through SPI + * + * Copyright (C) 2011-2013 Jonas Gorski + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "b53_priv.h" + +#define B53_SPI_DATA 0xf0 + +#define B53_SPI_STATUS 0xfe +#define B53_SPI_CMD_SPIF BIT(7) +#define B53_SPI_CMD_RACK BIT(5) + +#define B53_SPI_CMD_READ 0x00 +#define B53_SPI_CMD_WRITE 0x01 +#define B53_SPI_CMD_NORMAL 0x60 +#define B53_SPI_CMD_FAST 0x10 + +#define B53_SPI_PAGE_SELECT 0xff + +static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val, + unsigned len) +{ + u8 txbuf[2]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ; + txbuf[1] = reg; + + return spi_write_then_read(spi, txbuf, 2, val, len); +} + +static inline int b53_spi_clear_status(struct spi_device *spi) +{ + unsigned int i; + u8 rxbuf; + int ret; + + for (i = 0; i < 10; i++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (!(rxbuf & B53_SPI_CMD_SPIF)) + break; + + mdelay(1); + } + + if (i == 10) + return -EIO; + + return 0; +} + +static inline int b53_spi_set_page(struct spi_device *spi, u8 page) +{ + u8 txbuf[3]; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = B53_SPI_PAGE_SELECT; + txbuf[2] = page; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page) +{ + int ret = b53_spi_clear_status(spi); + + if (ret) + return ret; + + return b53_spi_set_page(spi, page); +} + +static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg) +{ + u8 rxbuf; + int retry_count; + int ret; + + ret = b53_spi_read_reg(spi, reg, &rxbuf, 1); + if (ret) + return ret; + + for (retry_count = 0; retry_count < 10; retry_count++) { + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); + if (ret) + return ret; + + if (rxbuf & B53_SPI_CMD_RACK) + break; + + mdelay(1); + } + + if (retry_count == 10) + return -EIO; + + return 0; +} + +static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data, + unsigned len) +{ + struct spi_device *spi = dev->priv; + int ret; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + ret = b53_spi_prepare_reg_read(spi, reg); + if (ret) + return ret; + + return b53_spi_read_reg(spi, B53_SPI_DATA, data, len); +} + +static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + return b53_spi_read(dev, page, reg, val, 1); +} + +static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2); + + if (!ret) + *val = le16_to_cpu(*val); + + return ret; +} + +static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4); + + if (!ret) + *val = le32_to_cpu(*val); + + return ret; +} + +static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret; + + *val = 0; + ret = b53_spi_read(dev, page, reg, (u8 *)val, 6); + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8); + + if (!ret) + *val = le64_to_cpu(*val); + + return ret; +} + +static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[3]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + txbuf[2] = value; + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[4]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le16(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[6]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le32(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf) - 2); +} + +static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value) +{ + struct spi_device *spi = dev->priv; + int ret; + u8 txbuf[10]; + + ret = b53_prepare_reg_access(spi, page); + if (ret) + return ret; + + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; + txbuf[1] = reg; + put_unaligned_le64(value, &txbuf[2]); + + return spi_write(spi, txbuf, sizeof(txbuf)); +} + +static struct b53_io_ops b53_spi_ops = { + .read8 = b53_spi_read8, + .read16 = b53_spi_read16, + .read32 = b53_spi_read32, + .read48 = b53_spi_read48, + .read64 = b53_spi_read64, + .write8 = b53_spi_write8, + .write16 = b53_spi_write16, + .write32 = b53_spi_write32, + .write48 = b53_spi_write48, + .write64 = b53_spi_write64, +}; + +static int b53_spi_probe(struct spi_device *spi) +{ + struct b53_device *dev; + int ret; + + dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi); + if (!dev) + return -ENOMEM; + + if (spi->dev.platform_data) + dev->pdata = spi->dev.platform_data; + + ret = b53_switch_register(dev); + if (ret) + return ret; + + spi_set_drvdata(spi, dev); + + return 0; +} + +static int b53_spi_remove(struct spi_device *spi) +{ + struct b53_device *dev = spi_get_drvdata(spi); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static const struct of_device_id b53_of_match[] = { + { .compatible = "brcm,bcm5325" }, + { .compatible = "brcm,bcm53115" }, + { .compatible = "brcm,bcm53125" }, + { .compatible = "brcm,bcm53128" }, + { .compatible = "brcm,bcm5365" }, + { .compatible = "brcm,bcm5395" }, + { .compatible = "brcm,bcm5397" }, + { .compatible = "brcm,bcm5398" }, + { /* sentinel */ }, +}; + +static struct spi_driver b53_spi_driver = { + .driver = { + .name = "b53-switch", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + .of_match_table = b53_of_match, + }, + .probe = b53_spi_probe, + .remove = b53_spi_remove, +}; + +module_spi_driver(b53_spi_driver); + +MODULE_AUTHOR("Jonas Gorski "); +MODULE_DESCRIPTION("B53 SPI access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/b53/b53_srab.c b/ipq806x/files-5.4/drivers/net/phy/b53/b53_srab.c new file mode 100644 index 0000000..012daa3 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/b53/b53_srab.c @@ -0,0 +1,378 @@ +/* + * B53 register access through Switch Register Access Bridge Registers + * + * Copyright (C) 2013 Hauke Mehrtens + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "b53_priv.h" + +/* command and status register of the SRAB */ +#define B53_SRAB_CMDSTAT 0x2c +#define B53_SRAB_CMDSTAT_RST BIT(2) +#define B53_SRAB_CMDSTAT_WRITE BIT(1) +#define B53_SRAB_CMDSTAT_GORDYN BIT(0) +#define B53_SRAB_CMDSTAT_PAGE 24 +#define B53_SRAB_CMDSTAT_REG 16 + +/* high order word of write data to switch registe */ +#define B53_SRAB_WD_H 0x30 + +/* low order word of write data to switch registe */ +#define B53_SRAB_WD_L 0x34 + +/* high order word of read data from switch register */ +#define B53_SRAB_RD_H 0x38 + +/* low order word of read data from switch register */ +#define B53_SRAB_RD_L 0x3c + +/* command and status register of the SRAB */ +#define B53_SRAB_CTRLS 0x40 +#define B53_SRAB_CTRLS_RCAREQ BIT(3) +#define B53_SRAB_CTRLS_RCAGNT BIT(4) +#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) + +/* the register captures interrupt pulses from the switch */ +#define B53_SRAB_INTR 0x44 + +static int b53_srab_request_grant(struct b53_device *dev) +{ + u8 __iomem *regs = dev->priv; + u32 ctrls; + int i; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls |= B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); + + for (i = 0; i < 20; i++) { + ctrls = readl(regs + B53_SRAB_CTRLS); + if (ctrls & B53_SRAB_CTRLS_RCAGNT) + break; + usleep_range(10, 100); + } + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static void b53_srab_release_grant(struct b53_device *dev) +{ + u8 __iomem *regs = dev->priv; + u32 ctrls; + + ctrls = readl(regs + B53_SRAB_CTRLS); + ctrls &= ~B53_SRAB_CTRLS_RCAREQ; + writel(ctrls, regs + B53_SRAB_CTRLS); +} + +static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op) +{ + int i; + u32 cmdstat; + u8 __iomem *regs = dev->priv; + + /* set register address */ + cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) | + (reg << B53_SRAB_CMDSTAT_REG) | + B53_SRAB_CMDSTAT_GORDYN | + op; + writel(cmdstat, regs + B53_SRAB_CMDSTAT); + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + cmdstat = readl(regs + B53_SRAB_CMDSTAT); + if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN)) + break; + usleep_range(10, 100); + } + + if (WARN_ON(i == 5)) + return -EIO; + + return 0; +} + +static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L) & 0xffff; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + ret = b53_srab_op(dev, page, reg, 0); + if (ret) + goto err; + + *val = readl(regs + B53_SRAB_RD_L); + *val += (u64)readl(regs + B53_SRAB_RD_H) << 32; + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg, + u16 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg, + u32 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel(value, regs + B53_SRAB_WD_L); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; + +} + +static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u16)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; + +} + +static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg, + u64 value) +{ + u8 __iomem *regs = dev->priv; + int ret = 0; + + ret = b53_srab_request_grant(dev); + if (ret) + goto err; + + writel((u32)value, regs + B53_SRAB_WD_L); + writel((u32)(value >> 32), regs + B53_SRAB_WD_H); + + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); + +err: + b53_srab_release_grant(dev); + + return ret; +} + +static struct b53_io_ops b53_srab_ops = { + .read8 = b53_srab_read8, + .read16 = b53_srab_read16, + .read32 = b53_srab_read32, + .read48 = b53_srab_read48, + .read64 = b53_srab_read64, + .write8 = b53_srab_write8, + .write16 = b53_srab_write16, + .write32 = b53_srab_write32, + .write48 = b53_srab_write48, + .write64 = b53_srab_write64, +}; + +static int b53_srab_probe(struct platform_device *pdev) +{ + struct b53_platform_data *pdata = pdev->dev.platform_data; + struct b53_device *dev; + + if (!pdata) + return -EINVAL; + + dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs); + if (!dev) + return -ENOMEM; + + if (pdata) + dev->pdata = pdata; + + platform_set_drvdata(pdev, dev); + + return b53_switch_register(dev); +} + +static int b53_srab_remove(struct platform_device *pdev) +{ + struct b53_device *dev = platform_get_drvdata(pdev); + + if (dev) + b53_switch_remove(dev); + + return 0; +} + +static struct platform_driver b53_srab_driver = { + .probe = b53_srab_probe, + .remove = b53_srab_remove, + .driver = { + .name = "b53-srab-switch", + }, +}; + +module_platform_driver(b53_srab_driver); +MODULE_AUTHOR("Hauke Mehrtens "); +MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/ip17xx.c b/ipq806x/files-5.4/drivers/net/phy/ip17xx.c new file mode 100644 index 0000000..c369803 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/ip17xx.c @@ -0,0 +1,1370 @@ +/* + * ip17xx.c: Swconfig configuration for IC+ IP17xx switch family + * + * Copyright (C) 2008 Patrick Horn + * Copyright (C) 2008, 2010 Martin Mares + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_VLANS 16 +#define MAX_PORTS 9 +#undef DUMP_MII_IO + +typedef struct ip17xx_reg { + u16 p; // phy + u16 m; // mii +} reg; +typedef char bitnum; + +#define NOTSUPPORTED {-1,-1} + +#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) + +struct ip17xx_state; + +/*********** CONSTANTS ***********/ +struct register_mappings { + char *NAME; + u16 MODEL_NO; // Compare to bits 4-9 of MII register 0,3. + bitnum NUM_PORTS; + bitnum CPU_PORT; + +/* The default VLAN for each port. + Default: 0x0001 for Ports 0,1,2,3 + 0x0002 for Ports 4,5 */ + reg VLAN_DEFAULT_TAG_REG[MAX_PORTS]; + +/* These ports are tagged. + Default: 0x00 */ + reg ADD_TAG_REG; + reg REMOVE_TAG_REG; + bitnum ADD_TAG_BIT[MAX_PORTS]; +/* These ports are untagged. + Default: 0x00 (i.e. do not alter any VLAN tags...) + Maybe set to 0 if user disables VLANs. */ + bitnum REMOVE_TAG_BIT[MAX_PORTS]; + +/* Port M and Port N are on the same VLAN. + Default: All ports on all VLANs. */ +// Use register {29, 19+N/2} + reg VLAN_LOOKUP_REG; +// Port 5 uses register {30, 18} but same as odd bits. + reg VLAN_LOOKUP_REG_5; // in a different register on IP175C. + bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS]; + bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS]; + +/* This VLAN corresponds to which ports. + Default: 0x2f,0x30,0x3f,0x3f... */ + reg TAG_VLAN_MASK_REG; + bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS]; + bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS]; + + int RESET_VAL; + reg RESET_REG; + + reg MODE_REG; + int MODE_VAL; + +/* General flags */ + reg ROUTER_CONTROL_REG; + reg VLAN_CONTROL_REG; + bitnum TAG_VLAN_BIT; + bitnum ROUTER_EN_BIT; + bitnum NUMLAN_GROUPS_MAX; + bitnum NUMLAN_GROUPS_BIT; + + reg MII_REGISTER_EN; + bitnum MII_REGISTER_EN_BIT; + + // set to 1 for 178C, 0 for 175C. + bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one. + + // Pointers to functions which manipulate hardware state + int (*update_state)(struct ip17xx_state *state); + int (*set_vlan_mode)(struct ip17xx_state *state); + int (*reset)(struct ip17xx_state *state); +}; + +static int ip175c_update_state(struct ip17xx_state *state); +static int ip175c_set_vlan_mode(struct ip17xx_state *state); +static int ip175c_reset(struct ip17xx_state *state); + +static const struct register_mappings IP178C = { + .NAME = "IP178C", + .MODEL_NO = 0x18, + .VLAN_DEFAULT_TAG_REG = { + {30,3},{30,4},{30,5},{30,6},{30,7},{30,8}, + {30,9},{30,10},{30,11}, + }, + + .ADD_TAG_REG = {30,12}, + .ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8}, + .REMOVE_TAG_REG = {30,13}, + .REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12}, + + .SIMPLE_VLAN_REGISTERS = 1, + + .VLAN_LOOKUP_REG = {31,0},// +N + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS + .VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8}, + + .TAG_VLAN_MASK_REG = {30,14}, // +N + .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, + .TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8}, + + .RESET_VAL = 0x55AA, + .RESET_REG = {30,0}, + .MODE_VAL = 0, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = {30,30}, + .ROUTER_EN_BIT = 11, + .NUMLAN_GROUPS_MAX = 8, + .NUMLAN_GROUPS_BIT = 8, // {0-2} + + .VLAN_CONTROL_REG = {30,13}, + .TAG_VLAN_BIT = 3, + + .CPU_PORT = 8, + .NUM_PORTS = 9, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + +static const struct register_mappings IP175C = { + .NAME = "IP175C", + .MODEL_NO = 0x18, + .VLAN_DEFAULT_TAG_REG = { + {29,24},{29,25},{29,26},{29,27},{29,28},{29,30}, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED + }, + + .ADD_TAG_REG = {29,23}, + .REMOVE_TAG_REG = {29,23}, + .ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1}, + .REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1}, + + .SIMPLE_VLAN_REGISTERS = 0, + + .VLAN_LOOKUP_REG = {29,19},// +N/2 + .VLAN_LOOKUP_REG_5 = {30,18}, + .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1}, + + .TAG_VLAN_MASK_REG = {30,1}, // +N/2 + .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1}, + .TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1}, + + .RESET_VAL = 0x175C, + .RESET_REG = {30,0}, + .MODE_VAL = 0x175C, + .MODE_REG = {29,31}, + + .ROUTER_CONTROL_REG = {30,9}, + .ROUTER_EN_BIT = 3, + .NUMLAN_GROUPS_MAX = 8, + .NUMLAN_GROUPS_BIT = 0, // {0-2} + + .VLAN_CONTROL_REG = {30,9}, + .TAG_VLAN_BIT = 7, + + .NUM_PORTS = 6, + .CPU_PORT = 5, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + +static const struct register_mappings IP175A = { + .NAME = "IP175A", + .MODEL_NO = 0x05, + .VLAN_DEFAULT_TAG_REG = { + {0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED + }, + + .ADD_TAG_REG = {0,23}, + .REMOVE_TAG_REG = {0,23}, + .ADD_TAG_BIT = {11,12,13,14,15,-1,-1,-1,-1}, + .REMOVE_TAG_BIT = {6,7,8,9,10,-1,-1,-1,-1}, + + .SIMPLE_VLAN_REGISTERS = 0, + + // Only programmable via EEPROM + .VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2 + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, + .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1}, + .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1}, + + .TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2, + .TAG_VLAN_MASK_EVEN_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, + .TAG_VLAN_MASK_ODD_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, + + .RESET_VAL = -1, + .RESET_REG = NOTSUPPORTED, + .MODE_VAL = 0, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = NOTSUPPORTED, + .VLAN_CONTROL_REG = NOTSUPPORTED, + .TAG_VLAN_BIT = -1, + .ROUTER_EN_BIT = -1, + .NUMLAN_GROUPS_MAX = -1, + .NUMLAN_GROUPS_BIT = -1, // {0-2} + + .NUM_PORTS = 5, + .CPU_PORT = 4, + + .MII_REGISTER_EN = {0, 18}, + .MII_REGISTER_EN_BIT = 7, + + .update_state = ip175c_update_state, + .set_vlan_mode = ip175c_set_vlan_mode, + .reset = ip175c_reset, +}; + + +static int ip175d_update_state(struct ip17xx_state *state); +static int ip175d_set_vlan_mode(struct ip17xx_state *state); +static int ip175d_reset(struct ip17xx_state *state); + +static const struct register_mappings IP175D = { + .NAME = "IP175D", + .MODEL_NO = 0x18, + + // The IP175D has a completely different interface, so we leave most + // of the registers undefined and switch to different code paths. + + .VLAN_DEFAULT_TAG_REG = { + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, + }, + + .ADD_TAG_REG = NOTSUPPORTED, + .REMOVE_TAG_REG = NOTSUPPORTED, + + .SIMPLE_VLAN_REGISTERS = 0, + + .VLAN_LOOKUP_REG = NOTSUPPORTED, + .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, + .TAG_VLAN_MASK_REG = NOTSUPPORTED, + + .RESET_VAL = 0x175D, + .RESET_REG = {20,2}, + .MODE_REG = NOTSUPPORTED, + + .ROUTER_CONTROL_REG = NOTSUPPORTED, + .ROUTER_EN_BIT = -1, + .NUMLAN_GROUPS_BIT = -1, + + .VLAN_CONTROL_REG = NOTSUPPORTED, + .TAG_VLAN_BIT = -1, + + .NUM_PORTS = 6, + .CPU_PORT = 5, + + .MII_REGISTER_EN = NOTSUPPORTED, + + .update_state = ip175d_update_state, + .set_vlan_mode = ip175d_set_vlan_mode, + .reset = ip175d_reset, +}; + +struct ip17xx_state { + struct switch_dev dev; + struct mii_bus *mii_bus; + bool registered; + + int router_mode; // ROUTER_EN + int vlan_enabled; // TAG_VLAN_EN + struct port_state { + u16 pvid; + unsigned int shareports; + } ports[MAX_PORTS]; + unsigned int add_tag; + unsigned int remove_tag; + int num_vlans; + struct vlan_state { + unsigned int ports; + unsigned int tag; // VLAN tag (IP175D only) + } vlans[MAX_VLANS]; + const struct register_mappings *regs; + reg proc_mii; // phy/reg for the low level register access via swconfig + + char buf[80]; +}; + +#define get_state(_dev) container_of((_dev), struct ip17xx_state, dev) + +static int ip_phy_read(struct ip17xx_state *state, int port, int reg) +{ + int val = mdiobus_read(state->mii_bus, port, reg); + if (val < 0) + pr_warn("IP17xx: Unable to get MII register %d,%d: error %d\n", port, reg, -val); +#ifdef DUMP_MII_IO + else + pr_debug("IP17xx: Read MII(%d,%d) -> %04x\n", port, reg, val); +#endif + return val; +} + +static int ip_phy_write(struct ip17xx_state *state, int port, int reg, u16 val) +{ + int err; + +#ifdef DUMP_MII_IO + pr_debug("IP17xx: Write MII(%d,%d) <- %04x\n", port, reg, val); +#endif + err = mdiobus_write(state->mii_bus, port, reg, val); + if (err < 0) + pr_warn("IP17xx: Unable to write MII register %d,%d: error %d\n", port, reg, -err); + return err; +} + +static int ip_phy_write_masked(struct ip17xx_state *state, int port, int reg, unsigned int mask, unsigned int data) +{ + int val = ip_phy_read(state, port, reg); + if (val < 0) + return 0; + return ip_phy_write(state, port, reg, (val & ~mask) | data); +} + +static int getPhy(struct ip17xx_state *state, reg mii) +{ + if (!REG_SUPP(mii)) + return -EFAULT; + return ip_phy_read(state, mii.p, mii.m); +} + +static int setPhy(struct ip17xx_state *state, reg mii, u16 value) +{ + int err; + + if (!REG_SUPP(mii)) + return -EFAULT; + err = ip_phy_write(state, mii.p, mii.m, value); + if (err < 0) + return err; + mdelay(2); + getPhy(state, mii); + return 0; +} + + +/** + * These two macros are to simplify the mapping of logical bits to the bits in hardware. + * NOTE: these macros will return if there is an error! + */ + +#define GET_PORT_BITS(state, bits, addr, bit_lookup) \ + do { \ + int i, val = getPhy((state), (addr)); \ + if (val < 0) \ + return val; \ + (bits) = 0; \ + for (i = 0; i < MAX_PORTS; i++) { \ + if ((bit_lookup)[i] == -1) continue; \ + if (val & (1<<(bit_lookup)[i])) \ + (bits) |= (1<>i)<<(bit_lookup)[i]); \ + } \ + val = setPhy((state), (addr), val); \ + if (val < 0) \ + return val; \ + } while (0) + + +static int get_model(struct ip17xx_state *state) +{ + int id1, id2; + int oui_id, model_no, rev_no, chip_no; + + id1 = ip_phy_read(state, 0, 2); + id2 = ip_phy_read(state, 0, 3); + oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f); + model_no = (id2 >> 4) & 0x3f; + rev_no = id2 & 0xf; + pr_debug("IP17xx: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no); + + if (oui_id != 0x0090c3) // No other oui_id should have reached us anyway + return -ENODEV; + + if (model_no == IP175A.MODEL_NO) { + state->regs = &IP175A; + } else if (model_no == IP175C.MODEL_NO) { + /* + * Several models share the same model_no: + * 178C has more PHYs, so we try whether the device responds to a read from PHY5 + * 175D has a new chip ID register + * 175C has neither + */ + if (ip_phy_read(state, 5, 2) == 0x0243) { + state->regs = &IP178C; + } else { + chip_no = ip_phy_read(state, 20, 0); + pr_debug("IP17xx: Chip ID register reads %04x\n", chip_no); + if (chip_no == 0x175d) { + state->regs = &IP175D; + } else { + state->regs = &IP175C; + } + } + } else { + pr_warn("IP17xx: Found an unknown IC+ switch with model number %02x, revision %X.\n", model_no, rev_no); + return -EPERM; + } + return 0; +} + +/*** Low-level functions for the older models ***/ + +/** Only set vlan and router flags in the switch **/ +static int ip175c_set_flags(struct ip17xx_state *state) +{ + int val; + + if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { + return 0; + } + + val = getPhy(state, state->regs->ROUTER_CONTROL_REG); + if (val < 0) { + return val; + } + if (state->regs->ROUTER_EN_BIT >= 0) { + if (state->router_mode) { + val |= (1<regs->ROUTER_EN_BIT); + } else { + val &= (~(1<regs->ROUTER_EN_BIT)); + } + } + if (state->regs->TAG_VLAN_BIT >= 0) { + if (state->vlan_enabled) { + val |= (1<regs->TAG_VLAN_BIT); + } else { + val &= (~(1<regs->TAG_VLAN_BIT)); + } + } + if (state->regs->NUMLAN_GROUPS_BIT >= 0) { + val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<regs->NUMLAN_GROUPS_BIT)); + if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) { + val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT; + } else if (state->num_vlans >= 1) { + val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT; + } + } + return setPhy(state, state->regs->ROUTER_CONTROL_REG, val); +} + +/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ +static int ip175c_set_state(struct ip17xx_state *state) +{ + int j; + int i; + SET_PORT_BITS(state, state->add_tag, + state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); + SET_PORT_BITS(state, state->remove_tag, + state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); + + if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { + for (j=0; jregs->NUM_PORTS; j++) { + reg addr; + const bitnum *bit_lookup = (j%2==0)? + state->regs->VLAN_LOOKUP_EVEN_BIT: + state->regs->VLAN_LOOKUP_ODD_BIT; + + addr = state->regs->VLAN_LOOKUP_REG; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + switch (j) { + case 0: + case 1: + break; + case 2: + case 3: + addr.m+=1; + break; + case 4: + addr.m+=2; + break; + case 5: + addr = state->regs->VLAN_LOOKUP_REG_5; + break; + default: + addr.m = -1; // shouldn't get here, but... + break; + } + } + //printf("shareports for %d is %02X\n",j,state->ports[j].shareports); + if (REG_SUPP(addr)) { + SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); + } + } + } + if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { + for (j=0; jregs->TAG_VLAN_MASK_REG; + const bitnum *bit_lookup = (j%2==0)? + state->regs->TAG_VLAN_MASK_EVEN_BIT: + state->regs->TAG_VLAN_MASK_ODD_BIT; + unsigned int vlan_mask; + if (state->regs->SIMPLE_VLAN_REGISTERS) { + addr.m += j; + } else { + addr.m += j/2; + } + vlan_mask = state->vlans[j].ports; + SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); + } + } + + for (i=0; iregs->VLAN_DEFAULT_TAG_REG[i])) { + int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i], + state->ports[i].pvid); + if (err < 0) { + return err; + } + } + } + + return ip175c_set_flags(state); +} + +/** + * Uses only the VLAN port mask and the add tag mask to generate the other fields: + * which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids. + */ +static void ip175c_correct_vlan_state(struct ip17xx_state *state) +{ + int i, j; + state->num_vlans = 0; + for (i=0; ivlans[i].ports != 0) { + state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere... + } + } + + for (i=0; iregs->NUM_PORTS; i++) { + unsigned int portmask = (1<vlan_enabled) { + // Share with everybody! + state->ports[i].shareports = (1<regs->NUM_PORTS)-1; + continue; + } + state->ports[i].shareports = portmask; + for (j=0; jvlans[j].ports & portmask) + state->ports[i].shareports |= state->vlans[j].ports; + } + } +} + +static int ip175c_update_state(struct ip17xx_state *state) +{ + ip175c_correct_vlan_state(state); + return ip175c_set_state(state); +} + +static int ip175c_set_vlan_mode(struct ip17xx_state *state) +{ + return ip175c_update_state(state); +} + +static int ip175c_reset(struct ip17xx_state *state) +{ + int err; + + if (REG_SUPP(state->regs->MODE_REG)) { + err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL); + if (err < 0) + return err; + err = getPhy(state, state->regs->MODE_REG); + if (err < 0) + return err; + } + + return ip175c_update_state(state); +} + +/*** Low-level functions for IP175D ***/ + +static int ip175d_update_state(struct ip17xx_state *state) +{ + unsigned int filter_mask = 0; + unsigned int ports[16], add[16], rem[16]; + int i, j; + int err = 0; + + for (i = 0; i < 16; i++) { + ports[i] = 0; + add[i] = 0; + rem[i] = 0; + if (!state->vlan_enabled) { + err |= ip_phy_write(state, 22, 14+i, i+1); // default tags + ports[i] = 0x3f; + continue; + } + if (!state->vlans[i].tag) { + // Reset the filter + err |= ip_phy_write(state, 22, 14+i, 0); // tag + continue; + } + filter_mask |= 1 << i; + err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag); + ports[i] = state->vlans[i].ports; + for (j = 0; j < 6; j++) { + if (ports[i] & (1 << j)) { + if (state->add_tag & (1 << j)) + add[i] |= 1 << j; + if (state->remove_tag & (1 << j)) + rem[i] |= 1 << j; + } + } + } + + // Port masks, tag adds and removals + for (i = 0; i < 8; i++) { + err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8)); + err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8)); + } + err |= ip_phy_write(state, 22, 10, filter_mask); + + // Default VLAN tag for each port + for (i = 0; i < 6; i++) + err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag); + + return (err ? -EIO : 0); +} + +static int ip175d_set_vlan_mode(struct ip17xx_state *state) +{ + int i; + int err = 0; + + if (state->vlan_enabled) { + // VLAN classification rules: tag-based VLANs, use VID to classify, + // drop packets that cannot be classified. + err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f); + + // Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed, + // VID=0xfff discarded, admin both tagged and untagged, ingress + // filters enabled. + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + + // Egress rules: IGMP processing off, keep VLAN header off + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } else { + // VLAN classification rules: everything off & clear table + err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000); + + // Ingress and egress rules: set to defaults + err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); + err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); + } + + // Reset default VLAN for each port to 0 + for (i = 0; i < 6; i++) + state->ports[i].pvid = 0; + + err |= ip175d_update_state(state); + + return (err ? -EIO : 0); +} + +static int ip175d_reset(struct ip17xx_state *state) +{ + int err = 0; + + // Disable the special tagging mode + err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000); + + // Set 802.1q protocol type + err |= ip_phy_write(state, 22, 3, 0x8100); + + state->vlan_enabled = 0; + err |= ip175d_set_vlan_mode(state); + + return (err ? -EIO : 0); +} + +/*** High-level functions ***/ + +static int ip17xx_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->vlan_enabled; + return 0; +} + +static void ip17xx_reset_vlan_config(struct ip17xx_state *state) +{ + int i; + + state->remove_tag = (state->vlan_enabled ? ((1<regs->NUM_PORTS)-1) : 0x0000); + state->add_tag = 0x0000; + for (i = 0; i < MAX_VLANS; i++) { + state->vlans[i].ports = 0x0000; + state->vlans[i].tag = (i ? i : 16); + } + for (i = 0; i < MAX_PORTS; i++) + state->ports[i].pvid = 0; +} + +static int ip17xx_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int enable; + + enable = val->value.i; + if (state->vlan_enabled == enable) { + // Do not change any state. + return 0; + } + state->vlan_enabled = enable; + + // Otherwise, if we are switching state, set fields to a known default. + ip17xx_reset_vlan_config(state); + + return state->regs->set_vlan_mode(state); +} + +static int ip17xx_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int b; + int ind; + unsigned int ports; + + if (val->port_vlan >= dev->vlans || val->port_vlan < 0) + return -EINVAL; + + ports = state->vlans[val->port_vlan].ports; + b = 0; + ind = 0; + while (b < MAX_PORTS) { + if (ports&1) { + int istagged = ((state->add_tag >> b) & 1); + val->value.ports[ind].id = b; + val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED); + ind++; + } + b++; + ports >>= 1; + } + val->len = ind; + + return 0; +} + +static int ip17xx_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int i; + + if (val->port_vlan >= dev->vlans || val->port_vlan < 0) + return -EINVAL; + + state->vlans[val->port_vlan].ports = 0; + for (i = 0; i < val->len; i++) { + unsigned int bitmask = (1<value.ports[i].id); + state->vlans[val->port_vlan].ports |= bitmask; + if (val->value.ports[i].flags & (1<add_tag |= bitmask; + state->remove_tag &= (~bitmask); + } else { + state->add_tag &= (~bitmask); + state->remove_tag |= bitmask; + } + } + + return state->regs->update_state(state); +} + +static int ip17xx_apply(struct switch_dev *dev) +{ + struct ip17xx_state *state = get_state(dev); + + if (REG_SUPP(state->regs->MII_REGISTER_EN)) { + int val = getPhy(state, state->regs->MII_REGISTER_EN); + if (val < 0) { + return val; + } + val |= (1<regs->MII_REGISTER_EN_BIT); + return setPhy(state, state->regs->MII_REGISTER_EN, val); + } + return 0; +} + +static int ip17xx_reset(struct switch_dev *dev) +{ + struct ip17xx_state *state = get_state(dev); + int i, err; + + if (REG_SUPP(state->regs->RESET_REG)) { + err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL); + if (err < 0) + return err; + err = getPhy(state, state->regs->RESET_REG); + + /* + * Data sheet specifies reset period to be 2 msec. + * (I don't see any mention of the 2ms delay in the IP178C spec, only + * in IP175C, but it can't hurt.) + */ + mdelay(2); + } + + /* reset switch ports */ + for (i = 0; i < state->regs->NUM_PORTS-1; i++) { + err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + } + + state->router_mode = 0; + state->vlan_enabled = 0; + ip17xx_reset_vlan_config(state); + + return state->regs->reset(state); +} + +static int ip17xx_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + if (state->add_tag & (1<port_vlan)) { + if (state->remove_tag & (1<port_vlan)) + val->value.i = 3; // shouldn't ever happen. + else + val->value.i = 1; + } else { + if (state->remove_tag & (1<port_vlan)) + val->value.i = 0; + else + val->value.i = 2; + } + return 0; +} + +static int ip17xx_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + state->add_tag &= ~(1<port_vlan); + state->remove_tag &= ~(1<port_vlan); + + if (val->value.i == 0) + state->remove_tag |= (1<port_vlan); + if (val->value.i == 1) + state->add_tag |= (1<port_vlan); + + return state->regs->update_state(state); +} + +/** Get the current phy address */ +static int ip17xx_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->proc_mii.p; + return 0; +} + +/** Set a new phy address for low level access to registers */ +static int ip17xx_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int new_reg = val->value.i; + + if (new_reg < 0 || new_reg > 31) + state->proc_mii.p = (u16)-1; + else + state->proc_mii.p = (u16)new_reg; + return 0; +} + +/** Get the current register number */ +static int ip17xx_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + + val->value.i = state->proc_mii.m; + return 0; +} + +/** Set a new register address for low level access to registers */ +static int ip17xx_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int new_reg = val->value.i; + + if (new_reg < 0 || new_reg > 31) + state->proc_mii.m = (u16)-1; + else + state->proc_mii.m = (u16)new_reg; + return 0; +} + +/** Get the register content of state->proc_mii */ +static int ip17xx_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int retval = -EINVAL; + if (REG_SUPP(state->proc_mii)) + retval = getPhy(state, state->proc_mii); + + if (retval < 0) { + return retval; + } else { + val->value.i = retval; + return 0; + } +} + +/** Write a value to the register defined by phy/reg above */ +static int ip17xx_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int myval, err = -EINVAL; + + myval = val->value.i; + if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) { + err = setPhy(state, state->proc_mii, (u16)myval); + } + return err; +} + +static int ip17xx_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig. + return 0; +} + +static int ip17xx_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int vlan = val->port_vlan; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + val->value.i = state->vlans[vlan].tag; + return 0; +} + +static int ip17xx_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int vlan = val->port_vlan; + int tag = val->value.i; + + if (vlan < 0 || vlan >= MAX_VLANS) + return -EINVAL; + + if (tag < 0 || tag > 4095) + return -EINVAL; + + state->vlans[vlan].tag = tag; + return state->regs->update_state(state); +} + +static int ip17xx_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int nr = val->port_vlan; + int ctrl; + int autoneg; + int speed; + if (val->value.i == 100) { + speed = 1; + autoneg = 0; + } else if (val->value.i == 10) { + speed = 0; + autoneg = 0; + } else { + autoneg = 1; + speed = 1; + } + + /* Can't set speed for cpu port */ + if (nr == state->regs->CPU_PORT) + return -EINVAL; + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + ctrl = ip_phy_read(state, nr, 0); + if (ctrl < 0) + return -EIO; + + ctrl &= (~(1<<12)); + ctrl &= (~(1<<13)); + ctrl |= (autoneg<<12); + ctrl |= (speed<<13); + + return ip_phy_write(state, nr, 0, ctrl); +} + +static int ip17xx_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int nr = val->port_vlan; + int speed, status; + + if (nr == state->regs->CPU_PORT) { + val->value.i = 100; + return 0; + } + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + status = ip_phy_read(state, nr, 1); + speed = ip_phy_read(state, nr, 18); + if (status < 0 || speed < 0) + return -EIO; + + if (status & 4) + val->value.i = ((speed & (1<<11)) ? 100 : 10); + else + val->value.i = 0; + + return 0; +} + +static int ip17xx_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct ip17xx_state *state = get_state(dev); + int ctrl, speed, status; + int nr = val->port_vlan; + int len; + char *buf = state->buf; // fixed-length at 80. + + if (nr == state->regs->CPU_PORT) { + sprintf(buf, "up, 100 Mbps, cpu port"); + val->value.s = buf; + return 0; + } + + if (nr >= dev->ports || nr < 0) + return -EINVAL; + + ctrl = ip_phy_read(state, nr, 0); + status = ip_phy_read(state, nr, 1); + speed = ip_phy_read(state, nr, 18); + if (ctrl < 0 || status < 0 || speed < 0) + return -EIO; + + if (status & 4) + len = sprintf(buf, "up, %d Mbps, %s duplex", + ((speed & (1<<11)) ? 100 : 10), + ((speed & (1<<10)) ? "full" : "half")); + else + len = sprintf(buf, "down"); + + if (ctrl & (1<<12)) { + len += sprintf(buf+len, ", auto-negotiate"); + if (!(status & (1<<5))) + len += sprintf(buf+len, " (in progress)"); + } else { + len += sprintf(buf+len, ", fixed speed (%d)", + ((ctrl & (1<<13)) ? 100 : 10)); + } + + buf[len] = '\0'; + val->value.s = buf; + return 0; +} + +static int ip17xx_get_pvid(struct switch_dev *dev, int port, int *val) +{ + struct ip17xx_state *state = get_state(dev); + + *val = state->ports[port].pvid; + return 0; +} + +static int ip17xx_set_pvid(struct switch_dev *dev, int port, int val) +{ + struct ip17xx_state *state = get_state(dev); + + if (val < 0 || val >= MAX_VLANS) + return -EINVAL; + + state->ports[port].pvid = val; + return state->regs->update_state(state); +} + + +enum Ports { + IP17XX_PORT_STATUS, + IP17XX_PORT_LINK, + IP17XX_PORT_TAGGED, + IP17XX_PORT_PVID, +}; + +enum Globals { + IP17XX_ENABLE_VLAN, + IP17XX_GET_NAME, + IP17XX_REGISTER_PHY, + IP17XX_REGISTER_MII, + IP17XX_REGISTER_VALUE, + IP17XX_REGISTER_ERRNO, +}; + +enum Vlans { + IP17XX_VLAN_TAG, +}; + +static const struct switch_attr ip17xx_global[] = { + [IP17XX_ENABLE_VLAN] = { + .id = IP17XX_ENABLE_VLAN, + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Flag to enable or disable VLANs and tagging", + .get = ip17xx_get_enable_vlan, + .set = ip17xx_set_enable_vlan, + }, + [IP17XX_GET_NAME] = { + .id = IP17XX_GET_NAME, + .type = SWITCH_TYPE_STRING, + .description = "Returns the type of IC+ chip.", + .name = "name", + .get = ip17xx_read_name, + .set = NULL, + }, + /* jal: added for low level debugging etc. */ + [IP17XX_REGISTER_PHY] = { + .id = IP17XX_REGISTER_PHY, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: set PHY (0-4, or 29,30,31)", + .name = "phy", + .get = ip17xx_get_phy, + .set = ip17xx_set_phy, + }, + [IP17XX_REGISTER_MII] = { + .id = IP17XX_REGISTER_MII, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: set MII register number (0-31)", + .name = "reg", + .get = ip17xx_get_reg, + .set = ip17xx_set_reg, + }, + [IP17XX_REGISTER_VALUE] = { + .id = IP17XX_REGISTER_VALUE, + .type = SWITCH_TYPE_INT, + .description = "Direct register access: read/write to register (0-65535)", + .name = "val", + .get = ip17xx_get_val, + .set = ip17xx_set_val, + }, +}; + +static const struct switch_attr ip17xx_vlan[] = { + [IP17XX_VLAN_TAG] = { + .id = IP17XX_VLAN_TAG, + .type = SWITCH_TYPE_INT, + .description = "VLAN ID (0-4095) [IP175D only]", + .name = "vid", + .get = ip17xx_get_tag, + .set = ip17xx_set_tag, + } +}; + +static const struct switch_attr ip17xx_port[] = { + [IP17XX_PORT_STATUS] = { + .id = IP17XX_PORT_STATUS, + .type = SWITCH_TYPE_STRING, + .description = "Returns Detailed port status", + .name = "status", + .get = ip17xx_get_port_status, + .set = NULL, + }, + [IP17XX_PORT_LINK] = { + .id = IP17XX_PORT_LINK, + .type = SWITCH_TYPE_INT, + .description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100", + .name = "link", + .get = ip17xx_get_port_speed, + .set = ip17xx_set_port_speed, + }, + [IP17XX_PORT_TAGGED] = { + .id = IP17XX_PORT_LINK, + .type = SWITCH_TYPE_INT, + .description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)", + .name = "tagged", + .get = ip17xx_get_tagged, + .set = ip17xx_set_tagged, + }, +}; + +static const struct switch_dev_ops ip17xx_ops = { + .attr_global = { + .attr = ip17xx_global, + .n_attr = ARRAY_SIZE(ip17xx_global), + }, + .attr_port = { + .attr = ip17xx_port, + .n_attr = ARRAY_SIZE(ip17xx_port), + }, + .attr_vlan = { + .attr = ip17xx_vlan, + .n_attr = ARRAY_SIZE(ip17xx_vlan), + }, + + .get_port_pvid = ip17xx_get_pvid, + .set_port_pvid = ip17xx_set_pvid, + .get_vlan_ports = ip17xx_get_ports, + .set_vlan_ports = ip17xx_set_ports, + .apply_config = ip17xx_apply, + .reset_switch = ip17xx_reset, +}; + +static int ip17xx_probe(struct phy_device *pdev) +{ + struct ip17xx_state *state; + struct switch_dev *dev; + int err; + + /* We only attach to PHY 0, but use all available PHYs */ + if (pdev->mdio.addr != 0) + return -ENODEV; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + dev = &state->dev; + + pdev->priv = state; + state->mii_bus = pdev->mdio.bus; + + err = get_model(state); + if (err < 0) + goto error; + + dev->vlans = MAX_VLANS; + dev->cpu_port = state->regs->CPU_PORT; + dev->ports = state->regs->NUM_PORTS; + dev->name = state->regs->NAME; + dev->ops = &ip17xx_ops; + + pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->mdio.dev)); + return 0; + +error: + kfree(state); + return err; +} + +static int ip17xx_config_init(struct phy_device *pdev) +{ + struct ip17xx_state *state = pdev->priv; + struct net_device *dev = pdev->attached_dev; + int err; + + err = register_switch(&state->dev, dev); + if (err < 0) + return err; + + state->registered = true; + ip17xx_reset(&state->dev); + return 0; +} + +static void ip17xx_remove(struct phy_device *pdev) +{ + struct ip17xx_state *state = pdev->priv; + + if (state->registered) + unregister_switch(&state->dev); + kfree(state); +} + +static int ip17xx_config_aneg(struct phy_device *pdev) +{ + return 0; +} + +static int ip17xx_aneg_done(struct phy_device *pdev) +{ + return 1; /* Return any positive value */ +} + +static int ip17xx_read_status(struct phy_device *pdev) +{ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->pause = pdev->asym_pause = 0; + pdev->link = 1; + + return 0; +} + +static struct phy_driver ip17xx_driver[] = { + { + .name = "IC+ IP17xx", + .phy_id = 0x02430c00, + .phy_id_mask = 0x0ffffc00, + .features = PHY_BASIC_FEATURES, + .probe = ip17xx_probe, + .remove = ip17xx_remove, + .config_init = ip17xx_config_init, + .config_aneg = ip17xx_config_aneg, + .aneg_done = ip17xx_aneg_done, + .read_status = ip17xx_read_status, + } +}; + +module_phy_driver(ip17xx_driver); + +MODULE_AUTHOR("Patrick Horn "); +MODULE_AUTHOR("Felix Fietkau "); +MODULE_AUTHOR("Martin Mares "); +MODULE_LICENSE("GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/mvswitch.c b/ipq806x/files-5.4/drivers/net/phy/mvswitch.c new file mode 100644 index 0000000..bd3b9e1 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/mvswitch.c @@ -0,0 +1,446 @@ +/* + * Marvell 88E6060 switch driver + * Copyright (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "mvswitch.h" + +/* Undefine this to use trailer mode instead. + * I don't know if header mode works with all chips */ +#define HEADER_MODE 1 + +MODULE_DESCRIPTION("Marvell 88E6060 Switch driver"); +MODULE_AUTHOR("Felix Fietkau"); +MODULE_LICENSE("GPL"); + +#define MVSWITCH_MAGIC 0x88E6060 + +struct mvswitch_priv { + netdev_features_t orig_features; + u8 vlans[16]; +}; + +#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv) + +static inline u16 +r16(struct phy_device *phydev, int addr, int reg) +{ + struct mii_bus *bus = phydev->mdio.bus; + + return bus->read(bus, addr, reg); +} + +static inline void +w16(struct phy_device *phydev, int addr, int reg, u16 val) +{ + struct mii_bus *bus = phydev->mdio.bus; + + bus->write(bus, addr, reg, val); +} + + +static struct sk_buff * +mvswitch_mangle_tx(struct net_device *dev, struct sk_buff *skb) +{ + struct mvswitch_priv *priv; + char *buf = NULL; + u16 vid; + + priv = dev->phy_ptr; + if (unlikely(!priv)) + goto error; + + if (unlikely(skb->len < 16)) + goto error; + +#ifdef HEADER_MODE + if (__vlan_hwaccel_get_tag(skb, &vid)) + goto error; + + if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) { + if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC)) + goto error_expand; + if (skb->len < 62) + skb->len = 62; + } + buf = skb_push(skb, MV_HEADER_SIZE); +#else + if (__vlan_get_tag(skb, &vid)) + goto error; + + if (unlikely((vid > 15 || !priv->vlans[vid]))) + goto error; + + if (skb->len <= 64) { + if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC)) + goto error_expand; + + buf = skb->data + 64; + skb->len = 64 + MV_TRAILER_SIZE; + } else { + if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) { + if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC)) + goto error_expand; + } + buf = skb_put(skb, 4); + } + + /* move the ethernet header 4 bytes forward, overwriting the vlan tag */ + memmove(skb->data + 4, skb->data, 12); + skb->data += 4; + skb->len -= 4; + skb->mac_header += 4; +#endif + + if (!buf) + goto error; + + +#ifdef HEADER_MODE + /* prepend the tag */ + *((__be16 *) buf) = cpu_to_be16( + ((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) | + ((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M) + ); +#else + /* append the tag */ + *((__be32 *) buf) = cpu_to_be32(( + (MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) | + ((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S) + )); +#endif + + return skb; + +error_expand: + if (net_ratelimit()) + printk("%s: failed to expand/update skb for the switch\n", dev->name); + +error: + /* any errors? drop the packet! */ + dev_kfree_skb_any(skb); + return NULL; +} + +static void +mvswitch_mangle_rx(struct net_device *dev, struct sk_buff *skb) +{ + struct mvswitch_priv *priv; + unsigned char *buf; + int vlan = -1; + int i; + + priv = dev->phy_ptr; + if (WARN_ON_ONCE(!priv)) + return; + +#ifdef HEADER_MODE + buf = skb->data; + skb_pull(skb, MV_HEADER_SIZE); +#else + buf = skb->data + skb->len - MV_TRAILER_SIZE; + if (buf[0] != 0x80) + return; +#endif + + /* look for the vlan matching the incoming port */ + for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) { + if ((1 << buf[1]) & priv->vlans[i]) + vlan = i; + } + + if (vlan == -1) + return; + + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan); +} + + +static int +mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val) +{ + int i = 100; + u16 r; + + do { + r = r16(pdev, addr, reg) & mask; + if (r == val) + return 0; + } while(--i > 0); + return -ETIMEDOUT; +} + +static int +mvswitch_config_init(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + struct net_device *dev = pdev->attached_dev; + u8 vlmap = 0; + int i; + + if (!dev) + return -EINVAL; + + printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name); + linkmode_zero(pdev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); + linkmode_copy(pdev->advertising, pdev->supported); + dev->phy_ptr = priv; + pdev->irq = PHY_POLL; +#ifdef HEADER_MODE + dev->flags |= IFF_PROMISC; +#endif + + /* initialize default vlans */ + for (i = 0; i < MV_PORTS; i++) + priv->vlans[(i == MV_WANPORT ? 2 : 1)] |= (1 << i); + + /* before entering reset, disable all ports */ + for (i = 0; i < MV_PORTS; i++) + w16(pdev, MV_PORTREG(CONTROL, i), 0x00); + + msleep(2); /* wait for the status change to settle in */ + + /* put the ATU in reset */ + w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET); + + i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0); + if (i < 0) { + printk("%s: Timeout waiting for the switch to reset.\n", dev->name); + return i; + } + + /* set the ATU flags */ + w16(pdev, MV_SWITCHREG(ATU_CTRL), + MV_ATUCTL_NO_LEARN | + MV_ATUCTL_ATU_1K | + MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */ + ); + + /* initialize the cpu port */ + w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT), +#ifdef HEADER_MODE + MV_PORTCTRL_HEADER | +#else + MV_PORTCTRL_RXTR | + MV_PORTCTRL_TXTR | +#endif + MV_PORTCTRL_ENABLED + ); + /* wait for the phy change to settle in */ + msleep(2); + for (i = 0; i < MV_PORTS; i++) { + u8 pvid = 0; + int j; + + vlmap = 0; + + /* look for the matching vlan */ + for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) { + if (priv->vlans[j] & (1 << i)) { + vlmap = priv->vlans[j]; + pvid = j; + } + } + /* leave port unconfigured if it's not part of a vlan */ + if (!vlmap) + continue; + + /* add the cpu port to the allowed destinations list */ + vlmap |= (1 << MV_CPUPORT); + + /* take port out of its own vlan destination map */ + vlmap &= ~(1 << i); + + /* apply vlan settings */ + w16(pdev, MV_PORTREG(VLANMAP, i), + MV_PORTVLAN_PORTS(vlmap) | + MV_PORTVLAN_ID(i) + ); + + /* re-enable port */ + w16(pdev, MV_PORTREG(CONTROL, i), + MV_PORTCTRL_ENABLED + ); + } + + w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT), + MV_PORTVLAN_ID(MV_CPUPORT) + ); + + /* set the port association vector */ + for (i = 0; i <= MV_PORTS; i++) { + w16(pdev, MV_PORTREG(ASSOC, i), + MV_PORTASSOC_PORTS(1 << i) + ); + } + + /* init switch control */ + w16(pdev, MV_SWITCHREG(CTRL), + MV_SWITCHCTL_MSIZE | + MV_SWITCHCTL_DROP + ); + + dev->eth_mangle_rx = mvswitch_mangle_rx; + dev->eth_mangle_tx = mvswitch_mangle_tx; + priv->orig_features = dev->features; + +#ifdef HEADER_MODE + dev->priv_flags |= IFF_NO_IP_ALIGN; + dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; +#else + dev->features |= NETIF_F_HW_VLAN_CTAG_RX; +#endif + + return 0; +} + +static int +mvswitch_read_status(struct phy_device *pdev) +{ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->link = 1; + + /* XXX ugly workaround: we can't force the switch + * to gracefully handle hosts moving from one port to another, + * so we have to regularly clear the ATU database */ + + /* wait for the ATU to become available */ + mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); + + /* flush the ATU */ + w16(pdev, MV_SWITCHREG(ATU_OP), + MV_ATUOP_INPROGRESS | + MV_ATUOP_FLUSH_ALL + ); + + /* wait for operation to complete */ + mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); + + return 0; +} + +static int +mvswitch_aneg_done(struct phy_device *phydev) +{ + return 1; /* Return any positive value */ +} + +static int +mvswitch_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static void +mvswitch_detach(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + struct net_device *dev = pdev->attached_dev; + + if (!dev) + return; + + dev->phy_ptr = NULL; + dev->eth_mangle_rx = NULL; + dev->eth_mangle_tx = NULL; + dev->features = priv->orig_features; + dev->priv_flags &= ~IFF_NO_IP_ALIGN; +} + +static void +mvswitch_remove(struct phy_device *pdev) +{ + struct mvswitch_priv *priv = to_mvsw(pdev); + + kfree(priv); +} + +static int +mvswitch_probe(struct phy_device *pdev) +{ + struct mvswitch_priv *priv; + + priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + pdev->priv = priv; + + return 0; +} + +static int +mvswitch_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u16 reg; + + if (dev->mdio.addr != 0x10) + return 0; + + reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK; + if (reg != MV_IDENT_VALUE) + return 0; + + dev->phy_id = MVSWITCH_MAGIC; + return 0; +} + + +static struct phy_driver mvswitch_driver = { + .name = "Marvell 88E6060", + .phy_id = MVSWITCH_MAGIC, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = &mvswitch_probe, + .remove = &mvswitch_remove, + .detach = &mvswitch_detach, + .config_init = &mvswitch_config_init, + .config_aneg = &mvswitch_config_aneg, + .aneg_done = &mvswitch_aneg_done, + .read_status = &mvswitch_read_status, +}; + +static int __init +mvswitch_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup); + return phy_driver_register(&mvswitch_driver, THIS_MODULE); +} + +static void __exit +mvswitch_exit(void) +{ + phy_driver_unregister(&mvswitch_driver); +} + +module_init(mvswitch_init); +module_exit(mvswitch_exit); diff --git a/ipq806x/files-5.4/drivers/net/phy/mvswitch.h b/ipq806x/files-5.4/drivers/net/phy/mvswitch.h new file mode 100644 index 0000000..ab2a1a1 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/mvswitch.h @@ -0,0 +1,145 @@ +/* + * Marvell 88E6060 switch driver + * Copyright (c) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ +#ifndef __MVSWITCH_H +#define __MVSWITCH_H + +#define MV_HEADER_SIZE 2 +#define MV_HEADER_PORTS_M 0x001f +#define MV_HEADER_PORTS_S 0 +#define MV_HEADER_VLAN_M 0xf000 +#define MV_HEADER_VLAN_S 12 + +#define MV_TRAILER_SIZE 4 +#define MV_TRAILER_PORTS_M 0x1f +#define MV_TRAILER_PORTS_S 16 +#define MV_TRAILER_FLAGS_S 24 +#define MV_TRAILER_OVERRIDE 0x80 + + +#define MV_PORTS 5 +#define MV_WANPORT 4 +#define MV_CPUPORT 5 + +#define MV_BASE 0x10 + +#define MV_PHYPORT_BASE (MV_BASE + 0x0) +#define MV_PHYPORT(_n) (MV_PHYPORT_BASE + (_n)) +#define MV_SWITCHPORT_BASE (MV_BASE + 0x8) +#define MV_SWITCHPORT(_n) (MV_SWITCHPORT_BASE + (_n)) +#define MV_SWITCHREGS (MV_BASE + 0xf) + +enum { + MV_PHY_CONTROL = 0x00, + MV_PHY_STATUS = 0x01, + MV_PHY_IDENT0 = 0x02, + MV_PHY_IDENT1 = 0x03, + MV_PHY_ANEG = 0x04, + MV_PHY_LINK_ABILITY = 0x05, + MV_PHY_ANEG_EXPAND = 0x06, + MV_PHY_XMIT_NEXTP = 0x07, + MV_PHY_LINK_NEXTP = 0x08, + MV_PHY_CONTROL1 = 0x10, + MV_PHY_STATUS1 = 0x11, + MV_PHY_INTR_EN = 0x12, + MV_PHY_INTR_STATUS = 0x13, + MV_PHY_INTR_PORT = 0x14, + MV_PHY_RECV_COUNTER = 0x16, + MV_PHY_LED_PARALLEL = 0x16, + MV_PHY_LED_STREAM = 0x17, + MV_PHY_LED_CTRL = 0x18, + MV_PHY_LED_OVERRIDE = 0x19, + MV_PHY_VCT_CTRL = 0x1a, + MV_PHY_VCT_STATUS = 0x1b, + MV_PHY_CONTROL2 = 0x1e +}; +#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type + +enum { + MV_PORT_STATUS = 0x00, + MV_PORT_IDENT = 0x03, + MV_PORT_CONTROL = 0x04, + MV_PORT_VLANMAP = 0x06, + MV_PORT_ASSOC = 0x0b, + MV_PORT_RXCOUNT = 0x10, + MV_PORT_TXCOUNT = 0x11, +}; +#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type + +enum { + MV_PORTCTRL_BLOCK = (1 << 0), + MV_PORTCTRL_LEARN = (2 << 0), + MV_PORTCTRL_ENABLED = (3 << 0), + MV_PORTCTRL_VLANTUN = (1 << 7), /* Enforce VLANs on packets */ + MV_PORTCTRL_RXTR = (1 << 8), /* Enable Marvell packet trailer for ingress */ + MV_PORTCTRL_HEADER = (1 << 11), /* Enable Marvell packet header mode for port */ + MV_PORTCTRL_TXTR = (1 << 14), /* Enable Marvell packet trailer for egress */ + MV_PORTCTRL_FORCEFL = (1 << 15), /* force flow control */ +}; + +#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12) +#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f) + +#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f) +#define MV_PORTASSOC_MONITOR (1 << 15) + +enum { + MV_SWITCH_MAC0 = 0x01, + MV_SWITCH_MAC1 = 0x02, + MV_SWITCH_MAC2 = 0x03, + MV_SWITCH_CTRL = 0x04, + MV_SWITCH_ATU_CTRL = 0x0a, + MV_SWITCH_ATU_OP = 0x0b, + MV_SWITCH_ATU_DATA = 0x0c, + MV_SWITCH_ATU_MAC0 = 0x0d, + MV_SWITCH_ATU_MAC1 = 0x0e, + MV_SWITCH_ATU_MAC2 = 0x0f, +}; +#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type + +enum { + MV_SWITCHCTL_EEIE = (1 << 0), /* EEPROM interrupt enable */ + MV_SWITCHCTL_PHYIE = (1 << 1), /* PHY interrupt enable */ + MV_SWITCHCTL_ATUDONE= (1 << 2), /* ATU done interrupt enable */ + MV_SWITCHCTL_ATUIE = (1 << 3), /* ATU interrupt enable */ + MV_SWITCHCTL_CTRMODE= (1 << 8), /* statistics for rx and tx errors */ + MV_SWITCHCTL_RELOAD = (1 << 9), /* reload registers from eeprom */ + MV_SWITCHCTL_MSIZE = (1 << 10), /* increase maximum frame size */ + MV_SWITCHCTL_DROP = (1 << 13), /* discard frames with excessive collisions */ +}; + +enum { +#define MV_ATUCTL_AGETIME_MIN 16 +#define MV_ATUCTL_AGETIME_MAX 4080 +#define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4) + MV_ATUCTL_ATU_256 = (0 << 12), + MV_ATUCTL_ATU_512 = (1 << 12), + MV_ATUCTL_ATU_1K = (2 << 12), + MV_ATUCTL_ATUMASK = (3 << 12), + MV_ATUCTL_NO_LEARN = (1 << 14), + MV_ATUCTL_RESET = (1 << 15), +}; + +enum { +#define MV_ATUOP_DBNUM(_n) ((_n) & 0x0f) + + MV_ATUOP_NOOP = (0 << 12), + MV_ATUOP_FLUSH_ALL = (1 << 12), + MV_ATUOP_FLUSH_U = (2 << 12), + MV_ATUOP_LOAD_DB = (3 << 12), + MV_ATUOP_GET_NEXT = (4 << 12), + MV_ATUOP_FLUSH_DB = (5 << 12), + MV_ATUOP_FLUSH_DB_UU= (6 << 12), + + MV_ATUOP_INPROGRESS = (1 << 15), +}; + +#define MV_IDENT_MASK 0xfff0 +#define MV_IDENT_VALUE 0x0600 + +#endif diff --git a/ipq806x/files-5.4/drivers/net/phy/psb6970.c b/ipq806x/files-5.4/drivers/net/phy/psb6970.c new file mode 100644 index 0000000..6cee757 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/psb6970.c @@ -0,0 +1,444 @@ +/* + * Lantiq PSB6970 (Tantos) Switch driver + * + * Copyright (c) 2009,2010 Team Embedded. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation. + * + * The switch programming done in this driver follows the + * "Ethernet Traffic Separation using VLAN" Application Note as + * published by Lantiq. + */ + +#include +#include +#include +#include +#include + +#define PSB6970_MAX_VLANS 16 +#define PSB6970_NUM_PORTS 7 +#define PSB6970_DEFAULT_PORT_CPU 6 +#define PSB6970_IS_CPU_PORT(x) ((x) > 4) + +#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) + +/* --- Identification --- */ +#define PSB6970_CI0 0x0100 +#define PSB6970_CI0_MASK 0x000f +#define PSB6970_CI1 0x0101 +#define PSB6970_CI1_VAL 0x2599 +#define PSB6970_CI1_MASK 0xffff + +/* --- VLAN filter table --- */ +#define PSB6970_VFxL(i) ((i)*2+0x10) /* VLAN Filter Low */ +#define PSB6970_VFxL_VV (1 << 15) /* VLAN_Valid */ + +#define PSB6970_VFxH(i) ((i)*2+0x11) /* VLAN Filter High */ +#define PSB6970_VFxH_TM_SHIFT 7 /* Tagged Member */ + +/* --- Port registers --- */ +#define PSB6970_EC(p) ((p)*0x20+2) /* Extended Control */ +#define PSB6970_EC_IFNTE (1 << 1) /* Input Force No Tag Enable */ + +#define PSB6970_PBVM(p) ((p)*0x20+3) /* Port Base VLAN Map */ +#define PSB6970_PBVM_VMCE (1 << 8) +#define PSB6970_PBVM_AOVTP (1 << 9) +#define PSB6970_PBVM_VSD (1 << 10) +#define PSB6970_PBVM_VC (1 << 11) /* VID Check with VID table */ +#define PSB6970_PBVM_TBVE (1 << 13) /* Tag-Based VLAN enable */ + +#define PSB6970_DVID(p) ((p)*0x20+4) /* Default VLAN ID & Priority */ + +struct psb6970_priv { + struct switch_dev dev; + struct phy_device *phy; + u16 (*read) (struct phy_device* phydev, int reg); + void (*write) (struct phy_device* phydev, int reg, u16 val); + struct mutex reg_mutex; + + /* all fields below are cleared on reset */ + bool vlan; + u16 vlan_id[PSB6970_MAX_VLANS]; + u8 vlan_table[PSB6970_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[PSB6970_NUM_PORTS]; +}; + +#define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev) + +static u16 psb6970_mii_read(struct phy_device *phydev, int reg) +{ + struct mii_bus *bus = phydev->mdio.bus; + + return bus->read(bus, PHYADDR(reg)); +} + +static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val) +{ + struct mii_bus *bus = phydev->mdio.bus; + + bus->write(bus, PHYADDR(reg), val); +} + +static int +psb6970_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + priv->vlan = !!val->value.i; + return 0; +} + +static int +psb6970_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + val->value.i = priv->vlan; + return 0; +} + +static int psb6970_set_pvid(struct switch_dev *dev, int port, int vlan) +{ + struct psb6970_priv *priv = to_psb6970(dev); + + /* make sure no invalid PVIDs get set */ + if (vlan >= dev->vlans) + return -EINVAL; + + priv->pvid[port] = vlan; + return 0; +} + +static int psb6970_get_pvid(struct switch_dev *dev, int port, int *vlan) +{ + struct psb6970_priv *priv = to_psb6970(dev); + *vlan = priv->pvid[port]; + return 0; +} + +static int +psb6970_set_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + priv->vlan_id[val->port_vlan] = val->value.i; + return 0; +} + +static int +psb6970_get_vid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + val->value.i = priv->vlan_id[val->port_vlan]; + return 0; +} + +static struct switch_attr psb6970_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = psb6970_set_vlan, + .get = psb6970_get_vlan, + .max = 1}, +}; + +static struct switch_attr psb6970_port[] = { +}; + +static struct switch_attr psb6970_vlan[] = { + { + .type = SWITCH_TYPE_INT, + .name = "vid", + .description = "VLAN ID (0-4094)", + .set = psb6970_set_vid, + .get = psb6970_get_vid, + .max = 4094, + }, +}; + +static int psb6970_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + u8 ports = priv->vlan_table[val->port_vlan]; + int i; + + val->len = 0; + for (i = 0; i < PSB6970_NUM_PORTS; i++) { + struct switch_port *p; + + if (!(ports & (1 << i))) + continue; + + p = &val->value.ports[val->len++]; + p->id = i; + if (priv->vlan_tagged & (1 << i)) + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + else + p->flags = 0; + } + return 0; +} + +static int psb6970_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct psb6970_priv *priv = to_psb6970(dev); + u8 *vt = &priv->vlan_table[val->port_vlan]; + int i, j; + + *vt = 0; + for (i = 0; i < val->len; i++) { + struct switch_port *p = &val->value.ports[i]; + + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) + priv->vlan_tagged |= (1 << p->id); + else { + priv->vlan_tagged &= ~(1 << p->id); + priv->pvid[p->id] = val->port_vlan; + + /* make sure that an untagged port does not + * appear in other vlans */ + for (j = 0; j < PSB6970_MAX_VLANS; j++) { + if (j == val->port_vlan) + continue; + priv->vlan_table[j] &= ~(1 << p->id); + } + } + + *vt |= 1 << p->id; + } + return 0; +} + +static int psb6970_hw_apply(struct switch_dev *dev) +{ + struct psb6970_priv *priv = to_psb6970(dev); + int i, j; + + mutex_lock(&priv->reg_mutex); + + if (priv->vlan) { + /* into the vlan translation unit */ + for (j = 0; j < PSB6970_MAX_VLANS; j++) { + u8 vp = priv->vlan_table[j]; + + if (vp) { + priv->write(priv->phy, PSB6970_VFxL(j), + PSB6970_VFxL_VV | priv->vlan_id[j]); + priv->write(priv->phy, PSB6970_VFxH(j), + ((vp & priv-> + vlan_tagged) << + PSB6970_VFxH_TM_SHIFT) | vp); + } else /* clear VLAN Valid flag for unused vlans */ + priv->write(priv->phy, PSB6970_VFxL(j), 0); + + } + } + + /* update the port destination mask registers and tag settings */ + for (i = 0; i < PSB6970_NUM_PORTS; i++) { + int dvid = 1, pbvm = 0x7f | PSB6970_PBVM_VSD, ec = 0; + + if (priv->vlan) { + ec = PSB6970_EC_IFNTE; + dvid = priv->vlan_id[priv->pvid[i]]; + pbvm |= PSB6970_PBVM_TBVE | PSB6970_PBVM_VMCE; + + if ((i << 1) & priv->vlan_tagged) + pbvm |= PSB6970_PBVM_AOVTP | PSB6970_PBVM_VC; + } + + priv->write(priv->phy, PSB6970_PBVM(i), pbvm); + + if (!PSB6970_IS_CPU_PORT(i)) { + priv->write(priv->phy, PSB6970_EC(i), ec); + priv->write(priv->phy, PSB6970_DVID(i), dvid); + } + } + + mutex_unlock(&priv->reg_mutex); + return 0; +} + +static int psb6970_reset_switch(struct switch_dev *dev) +{ + struct psb6970_priv *priv = to_psb6970(dev); + int i; + + mutex_lock(&priv->reg_mutex); + + memset(&priv->vlan, 0, sizeof(struct psb6970_priv) - + offsetof(struct psb6970_priv, vlan)); + + for (i = 0; i < PSB6970_MAX_VLANS; i++) + priv->vlan_id[i] = i; + + mutex_unlock(&priv->reg_mutex); + + return psb6970_hw_apply(dev); +} + +static const struct switch_dev_ops psb6970_ops = { + .attr_global = { + .attr = psb6970_globals, + .n_attr = ARRAY_SIZE(psb6970_globals), + }, + .attr_port = { + .attr = psb6970_port, + .n_attr = ARRAY_SIZE(psb6970_port), + }, + .attr_vlan = { + .attr = psb6970_vlan, + .n_attr = ARRAY_SIZE(psb6970_vlan), + }, + .get_port_pvid = psb6970_get_pvid, + .set_port_pvid = psb6970_set_pvid, + .get_vlan_ports = psb6970_get_ports, + .set_vlan_ports = psb6970_set_ports, + .apply_config = psb6970_hw_apply, + .reset_switch = psb6970_reset_switch, +}; + +static int psb6970_config_init(struct phy_device *pdev) +{ + struct psb6970_priv *priv; + struct net_device *dev = pdev->attached_dev; + struct switch_dev *swdev; + int ret; + + priv = kzalloc(sizeof(struct psb6970_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->phy = pdev; + + if (pdev->mdio.addr == 0) + printk(KERN_INFO "%s: psb6970 switch driver attached.\n", + pdev->attached_dev->name); + + if (pdev->mdio.addr != 0) { + kfree(priv); + return 0; + } + + linkmode_zero(pdev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported); + linkmode_copy(pdev->advertising, pdev->supported); + + mutex_init(&priv->reg_mutex); + priv->read = psb6970_mii_read; + priv->write = psb6970_mii_write; + + pdev->priv = priv; + + swdev = &priv->dev; + swdev->cpu_port = PSB6970_DEFAULT_PORT_CPU; + swdev->ops = &psb6970_ops; + + swdev->name = "Lantiq PSB6970"; + swdev->vlans = PSB6970_MAX_VLANS; + swdev->ports = PSB6970_NUM_PORTS; + + if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) { + kfree(priv); + goto done; + } + + ret = psb6970_reset_switch(&priv->dev); + if (ret) { + kfree(priv); + goto done; + } + + dev->phy_ptr = priv; + +done: + return ret; +} + +static int psb6970_read_status(struct phy_device *phydev) +{ + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + phydev->link = 1; + + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + + return 0; +} + +static int psb6970_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int psb6970_probe(struct phy_device *pdev) +{ + return 0; +} + +static void psb6970_remove(struct phy_device *pdev) +{ + struct psb6970_priv *priv = pdev->priv; + + if (!priv) + return; + + if (pdev->mdio.addr == 0) + unregister_switch(&priv->dev); + kfree(priv); +} + +static int psb6970_fixup(struct phy_device *dev) +{ + struct mii_bus *bus = dev->mdio.bus; + u16 reg; + + /* look for the switch on the bus */ + reg = bus->read(bus, PHYADDR(PSB6970_CI1)) & PSB6970_CI1_MASK; + if (reg != PSB6970_CI1_VAL) + return 0; + + dev->phy_id = (reg << 16); + dev->phy_id |= bus->read(bus, PHYADDR(PSB6970_CI0)) & PSB6970_CI0_MASK; + + return 0; +} + +static struct phy_driver psb6970_driver = { + .name = "Lantiq PSB6970", + .phy_id = PSB6970_CI1_VAL << 16, + .phy_id_mask = 0xffff0000, + .features = PHY_BASIC_FEATURES, + .probe = psb6970_probe, + .remove = psb6970_remove, + .config_init = &psb6970_config_init, + .config_aneg = &psb6970_config_aneg, + .read_status = &psb6970_read_status, +}; + +int __init psb6970_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup); + return phy_driver_register(&psb6970_driver, THIS_MODULE); +} + +module_init(psb6970_init); + +void __exit psb6970_exit(void) +{ + phy_driver_unregister(&psb6970_driver); +} + +module_exit(psb6970_exit); + +MODULE_DESCRIPTION("Lantiq PSB6970 Switch"); +MODULE_AUTHOR("Ithamar R. Adema "); +MODULE_LICENSE("GPL"); diff --git a/ipq806x/files-5.4/drivers/net/phy/rtl8306.c b/ipq806x/files-5.4/drivers/net/phy/rtl8306.c new file mode 100644 index 0000000..31bc758 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/rtl8306.c @@ -0,0 +1,1063 @@ +/* + * rtl8306.c: RTL8306S switch driver + * + * Copyright (C) 2009 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG 1 + +/* Global (PHY0) */ +#define RTL8306_REG_PAGE 16 +#define RTL8306_REG_PAGE_LO (1 << 15) +#define RTL8306_REG_PAGE_HI (1 << 1) /* inverted */ + +#define RTL8306_NUM_VLANS 16 +#define RTL8306_NUM_PORTS 6 +#define RTL8306_PORT_CPU 5 +#define RTL8306_NUM_PAGES 4 +#define RTL8306_NUM_REGS 32 + +#define RTL_NAME_S "RTL8306S" +#define RTL_NAME_SD "RTL8306SD" +#define RTL_NAME_SDM "RTL8306SDM" +#define RTL_NAME_UNKNOWN "RTL8306(unknown)" + +#define RTL8306_MAGIC 0x8306 + +static LIST_HEAD(phydevs); + +struct rtl_priv { + struct list_head list; + struct switch_dev dev; + int page; + int type; + int do_cpu; + struct mii_bus *bus; + char hwname[sizeof(RTL_NAME_UNKNOWN)]; + bool fixup; +}; + +struct rtl_phyregs { + int nway; + int speed; + int duplex; +}; + +#define to_rtl(_dev) container_of(_dev, struct rtl_priv, dev) + +enum { + RTL_TYPE_S, + RTL_TYPE_SD, + RTL_TYPE_SDM, +}; + +struct rtl_reg { + int page; + int phy; + int reg; + int bits; + int shift; + int inverted; +}; + +#define RTL_VLAN_REGOFS(name) \ + (RTL_REG_VLAN1_##name - RTL_REG_VLAN0_##name) + +#define RTL_PORT_REGOFS(name) \ + (RTL_REG_PORT1_##name - RTL_REG_PORT0_##name) + +#define RTL_PORT_REG(id, reg) \ + (RTL_REG_PORT0_##reg + (id * RTL_PORT_REGOFS(reg))) + +#define RTL_VLAN_REG(id, reg) \ + (RTL_REG_VLAN0_##reg + (id * RTL_VLAN_REGOFS(reg))) + +#define RTL_GLOBAL_REGATTR(reg) \ + .id = RTL_REG_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = 0, \ + .set = rtl_attr_set_int, \ + .get = rtl_attr_get_int + +#define RTL_PORT_REGATTR(reg) \ + .id = RTL_REG_PORT0_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = RTL_PORT_REGOFS(reg), \ + .set = rtl_attr_set_port_int, \ + .get = rtl_attr_get_port_int + +#define RTL_VLAN_REGATTR(reg) \ + .id = RTL_REG_VLAN0_##reg, \ + .type = SWITCH_TYPE_INT, \ + .ofs = RTL_VLAN_REGOFS(reg), \ + .set = rtl_attr_set_vlan_int, \ + .get = rtl_attr_get_vlan_int + +enum rtl_regidx { + RTL_REG_CHIPID, + RTL_REG_CHIPVER, + RTL_REG_CHIPTYPE, + RTL_REG_CPUPORT, + + RTL_REG_EN_CPUPORT, + RTL_REG_EN_TAG_OUT, + RTL_REG_EN_TAG_CLR, + RTL_REG_EN_TAG_IN, + RTL_REG_TRAP_CPU, + RTL_REG_CPU_LINKUP, + RTL_REG_TRUNK_PORTSEL, + RTL_REG_EN_TRUNK, + RTL_REG_RESET, + + RTL_REG_VLAN_ENABLE, + RTL_REG_VLAN_FILTER, + RTL_REG_VLAN_TAG_ONLY, + RTL_REG_VLAN_TAG_AWARE, +#define RTL_VLAN_ENUM(id) \ + RTL_REG_VLAN##id##_VID, \ + RTL_REG_VLAN##id##_PORTMASK + RTL_VLAN_ENUM(0), + RTL_VLAN_ENUM(1), + RTL_VLAN_ENUM(2), + RTL_VLAN_ENUM(3), + RTL_VLAN_ENUM(4), + RTL_VLAN_ENUM(5), + RTL_VLAN_ENUM(6), + RTL_VLAN_ENUM(7), + RTL_VLAN_ENUM(8), + RTL_VLAN_ENUM(9), + RTL_VLAN_ENUM(10), + RTL_VLAN_ENUM(11), + RTL_VLAN_ENUM(12), + RTL_VLAN_ENUM(13), + RTL_VLAN_ENUM(14), + RTL_VLAN_ENUM(15), +#define RTL_PORT_ENUM(id) \ + RTL_REG_PORT##id##_PVID, \ + RTL_REG_PORT##id##_NULL_VID_REPLACE, \ + RTL_REG_PORT##id##_NON_PVID_DISCARD, \ + RTL_REG_PORT##id##_VID_INSERT, \ + RTL_REG_PORT##id##_TAG_INSERT, \ + RTL_REG_PORT##id##_LINK, \ + RTL_REG_PORT##id##_SPEED, \ + RTL_REG_PORT##id##_NWAY, \ + RTL_REG_PORT##id##_NRESTART, \ + RTL_REG_PORT##id##_DUPLEX, \ + RTL_REG_PORT##id##_RXEN, \ + RTL_REG_PORT##id##_TXEN + RTL_PORT_ENUM(0), + RTL_PORT_ENUM(1), + RTL_PORT_ENUM(2), + RTL_PORT_ENUM(3), + RTL_PORT_ENUM(4), + RTL_PORT_ENUM(5), +}; + +static const struct rtl_reg rtl_regs[] = { + [RTL_REG_CHIPID] = { 0, 4, 30, 16, 0, 0 }, + [RTL_REG_CHIPVER] = { 0, 4, 31, 8, 0, 0 }, + [RTL_REG_CHIPTYPE] = { 0, 4, 31, 2, 8, 0 }, + + /* CPU port number */ + [RTL_REG_CPUPORT] = { 2, 4, 21, 3, 0, 0 }, + /* Enable CPU port function */ + [RTL_REG_EN_CPUPORT] = { 3, 2, 21, 1, 15, 1 }, + /* Enable CPU port tag insertion */ + [RTL_REG_EN_TAG_OUT] = { 3, 2, 21, 1, 12, 0 }, + /* Enable CPU port tag removal */ + [RTL_REG_EN_TAG_CLR] = { 3, 2, 21, 1, 11, 0 }, + /* Enable CPU port tag checking */ + [RTL_REG_EN_TAG_IN] = { 0, 4, 21, 1, 7, 0 }, + [RTL_REG_EN_TRUNK] = { 0, 0, 19, 1, 11, 1 }, + [RTL_REG_TRUNK_PORTSEL] = { 0, 0, 16, 1, 6, 1 }, + [RTL_REG_RESET] = { 0, 0, 16, 1, 12, 0 }, + + [RTL_REG_TRAP_CPU] = { 3, 2, 22, 1, 6, 0 }, + [RTL_REG_CPU_LINKUP] = { 0, 6, 22, 1, 15, 0 }, + + [RTL_REG_VLAN_TAG_ONLY] = { 0, 0, 16, 1, 8, 1 }, + [RTL_REG_VLAN_FILTER] = { 0, 0, 16, 1, 9, 1 }, + [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16, 1, 10, 1 }, + [RTL_REG_VLAN_ENABLE] = { 0, 0, 18, 1, 8, 1 }, + +#define RTL_VLAN_REGS(id, phy, page, regofs) \ + [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \ + [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 } + RTL_VLAN_REGS( 0, 0, 0, 0), + RTL_VLAN_REGS( 1, 1, 0, 0), + RTL_VLAN_REGS( 2, 2, 0, 0), + RTL_VLAN_REGS( 3, 3, 0, 0), + RTL_VLAN_REGS( 4, 4, 0, 0), + RTL_VLAN_REGS( 5, 0, 1, 2), + RTL_VLAN_REGS( 6, 1, 1, 2), + RTL_VLAN_REGS( 7, 2, 1, 2), + RTL_VLAN_REGS( 8, 3, 1, 2), + RTL_VLAN_REGS( 9, 4, 1, 2), + RTL_VLAN_REGS(10, 0, 1, 4), + RTL_VLAN_REGS(11, 1, 1, 4), + RTL_VLAN_REGS(12, 2, 1, 4), + RTL_VLAN_REGS(13, 3, 1, 4), + RTL_VLAN_REGS(14, 4, 1, 4), + RTL_VLAN_REGS(15, 0, 1, 6), + +#define REG_PORT_SETTING(port, phy) \ + [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \ + [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \ + [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \ + [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \ + [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \ + [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \ + [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \ + [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \ + [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \ + [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \ + [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 } + + REG_PORT_SETTING(0, 0), + REG_PORT_SETTING(1, 1), + REG_PORT_SETTING(2, 2), + REG_PORT_SETTING(3, 3), + REG_PORT_SETTING(4, 4), + REG_PORT_SETTING(5, 6), + +#define REG_PORT_PVID(phy, page, regofs) \ + { page, phy, 24 + regofs, 4, 12, 0 } + [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0), + [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0), + [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0), + [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0), + [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0), + [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2), +}; + + +static inline void +rtl_set_page(struct rtl_priv *priv, unsigned int page) +{ + struct mii_bus *bus = priv->bus; + u16 pgsel; + + if (priv->fixup) + return; + + if (priv->page == page) + return; + + BUG_ON(page > RTL8306_NUM_PAGES); + pgsel = bus->read(bus, 0, RTL8306_REG_PAGE); + pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI); + if (page & (1 << 0)) + pgsel |= RTL8306_REG_PAGE_LO; + if (!(page & (1 << 1))) /* bit is inverted */ + pgsel |= RTL8306_REG_PAGE_HI; + bus->write(bus, 0, RTL8306_REG_PAGE, pgsel); +} + +static inline int +rtl_w16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + + rtl_set_page(priv, page); + bus->write(bus, phy, reg, val); + bus->read(bus, phy, reg); /* flush */ + return 0; +} + +static inline int +rtl_r16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + + rtl_set_page(priv, page); + return bus->read(bus, phy, reg); +} + +static inline u16 +rtl_rmw(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 mask, u16 val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct mii_bus *bus = priv->bus; + u16 r; + + rtl_set_page(priv, page); + r = bus->read(bus, phy, reg); + r &= ~mask; + r |= val; + bus->write(bus, phy, reg, r); + return bus->read(bus, phy, reg); /* flush */ +} + + +static inline int +rtl_get(struct switch_dev *dev, enum rtl_regidx s) +{ + const struct rtl_reg *r = &rtl_regs[s]; + u16 val; + + BUG_ON(s >= ARRAY_SIZE(rtl_regs)); + if (r->bits == 0) /* unimplemented */ + return 0; + + val = rtl_r16(dev, r->page, r->phy, r->reg); + + if (r->shift > 0) + val >>= r->shift; + + if (r->inverted) + val = ~val; + + val &= (1 << r->bits) - 1; + + return val; +} + +static int +rtl_set(struct switch_dev *dev, enum rtl_regidx s, unsigned int val) +{ + const struct rtl_reg *r = &rtl_regs[s]; + u16 mask = 0xffff; + + BUG_ON(s >= ARRAY_SIZE(rtl_regs)); + + if (r->bits == 0) /* unimplemented */ + return 0; + + if (r->shift > 0) + val <<= r->shift; + + if (r->inverted) + val = ~val; + + if (r->bits != 16) { + mask = (1 << r->bits) - 1; + mask <<= r->shift; + } + val &= mask; + return rtl_rmw(dev, r->page, r->phy, r->reg, mask, val); +} + +static void +rtl_phy_save(struct switch_dev *dev, int port, struct rtl_phyregs *regs) +{ + regs->nway = rtl_get(dev, RTL_PORT_REG(port, NWAY)); + regs->speed = rtl_get(dev, RTL_PORT_REG(port, SPEED)); + regs->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); +} + +static void +rtl_phy_restore(struct switch_dev *dev, int port, struct rtl_phyregs *regs) +{ + rtl_set(dev, RTL_PORT_REG(port, NWAY), regs->nway); + rtl_set(dev, RTL_PORT_REG(port, SPEED), regs->speed); + rtl_set(dev, RTL_PORT_REG(port, DUPLEX), regs->duplex); +} + +static void +rtl_port_set_enable(struct switch_dev *dev, int port, int enabled) +{ + rtl_set(dev, RTL_PORT_REG(port, RXEN), enabled); + rtl_set(dev, RTL_PORT_REG(port, TXEN), enabled); + + if ((port >= 5) || !enabled) + return; + + /* restart autonegotiation if enabled */ + rtl_set(dev, RTL_PORT_REG(port, NRESTART), 1); +} + +static int +rtl_hw_apply(struct switch_dev *dev) +{ + int i; + int trunk_en, trunk_psel; + struct rtl_phyregs port5; + + rtl_phy_save(dev, 5, &port5); + + /* disable rx/tx from PHYs */ + for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { + rtl_port_set_enable(dev, i, 0); + } + + /* save trunking status */ + trunk_en = rtl_get(dev, RTL_REG_EN_TRUNK); + trunk_psel = rtl_get(dev, RTL_REG_TRUNK_PORTSEL); + + /* trunk port 3 and 4 + * XXX: Big WTF, but RealTek seems to do it */ + rtl_set(dev, RTL_REG_EN_TRUNK, 1); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 1); + + /* execute the software reset */ + rtl_set(dev, RTL_REG_RESET, 1); + + /* wait for the reset to complete, + * but don't wait for too long */ + for (i = 0; i < 10; i++) { + if (rtl_get(dev, RTL_REG_RESET) == 0) + break; + + msleep(1); + } + + /* enable rx/tx from PHYs */ + for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { + rtl_port_set_enable(dev, i, 1); + } + + /* restore trunking settings */ + rtl_set(dev, RTL_REG_EN_TRUNK, trunk_en); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, trunk_psel); + rtl_phy_restore(dev, 5, &port5); + + rtl_set(dev, RTL_REG_CPU_LINKUP, 1); + + return 0; +} + +static void +rtl_hw_init(struct switch_dev *dev) +{ + struct rtl_priv *priv = to_rtl(dev); + int cpu_mask = 1 << dev->cpu_port; + int i; + + rtl_set(dev, RTL_REG_VLAN_ENABLE, 0); + rtl_set(dev, RTL_REG_VLAN_FILTER, 0); + rtl_set(dev, RTL_REG_EN_TRUNK, 0); + rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 0); + + /* initialize cpu port settings */ + if (priv->do_cpu) { + rtl_set(dev, RTL_REG_CPUPORT, dev->cpu_port); + rtl_set(dev, RTL_REG_EN_CPUPORT, 1); + } else { + rtl_set(dev, RTL_REG_CPUPORT, 7); + rtl_set(dev, RTL_REG_EN_CPUPORT, 0); + } + rtl_set(dev, RTL_REG_EN_TAG_OUT, 0); + rtl_set(dev, RTL_REG_EN_TAG_IN, 0); + rtl_set(dev, RTL_REG_EN_TAG_CLR, 0); + + /* reset all vlans */ + for (i = 0; i < RTL8306_NUM_VLANS; i++) { + rtl_set(dev, RTL_VLAN_REG(i, VID), i); + rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), 0); + } + + /* default to port isolation */ + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + unsigned long mask; + + if ((1 << i) == cpu_mask) + mask = ((1 << RTL8306_NUM_PORTS) - 1) & ~cpu_mask; /* all bits set */ + else + mask = cpu_mask | (1 << i); + + rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), mask); + rtl_set(dev, RTL_PORT_REG(i, PVID), i); + rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); + rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), 1); + rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), 3); + } + rtl_hw_apply(dev); +} + +#ifdef DEBUG +static int +rtl_set_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + priv->do_cpu = val->value.i; + rtl_hw_init(dev); + return 0; +} + +static int +rtl_get_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + val->value.i = priv->do_cpu; + return 0; +} + +static int +rtl_set_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + dev->cpu_port = val->value.i; + rtl_hw_init(dev); + return 0; +} + +static int +rtl_get_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + val->value.i = dev->cpu_port; + return 0; +} +#endif + +static int +rtl_reset(struct switch_dev *dev) +{ + rtl_hw_init(dev); + return 0; +} + +static int +rtl_attr_set_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + int idx = attr->id + (val->port_vlan * attr->ofs); + struct rtl_phyregs port; + + if (attr->id >= ARRAY_SIZE(rtl_regs)) + return -EINVAL; + + if ((attr->max > 0) && (val->value.i > attr->max)) + return -EINVAL; + + /* access to phy register 22 on port 4/5 + * needs phy status save/restore */ + if ((val->port_vlan > 3) && + (rtl_regs[idx].reg == 22) && + (rtl_regs[idx].page == 0)) { + + rtl_phy_save(dev, val->port_vlan, &port); + rtl_set(dev, idx, val->value.i); + rtl_phy_restore(dev, val->port_vlan, &port); + } else { + rtl_set(dev, idx, val->value.i); + } + + return 0; +} + +static int +rtl_attr_get_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + int idx = attr->id + (val->port_vlan * attr->ofs); + + if (idx >= ARRAY_SIZE(rtl_regs)) + return -EINVAL; + + val->value.i = rtl_get(dev, idx); + return 0; +} + +static int +rtl_attr_set_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= RTL8306_NUM_PORTS) + return -EINVAL; + + return rtl_attr_set_int(dev, attr, val); +} + +static int +rtl_attr_get_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= RTL8306_NUM_PORTS) + return -EINVAL; + return rtl_attr_get_int(dev, attr, val); +} + +static int +rtl_get_port_link(struct switch_dev *dev, int port, struct switch_port_link *link) +{ + if (port >= RTL8306_NUM_PORTS) + return -EINVAL; + + /* in case the link changes from down to up, the register is only updated on read */ + link->link = rtl_get(dev, RTL_PORT_REG(port, LINK)); + if (!link->link) + link->link = rtl_get(dev, RTL_PORT_REG(port, LINK)); + + if (!link->link) + return 0; + + link->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); + link->aneg = rtl_get(dev, RTL_PORT_REG(port, NWAY)); + + if (rtl_get(dev, RTL_PORT_REG(port, SPEED))) + link->speed = SWITCH_PORT_SPEED_100; + else + link->speed = SWITCH_PORT_SPEED_10; + + return 0; +} + +static int +rtl_attr_set_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + return rtl_attr_set_int(dev, attr, val); +} + +static int +rtl_attr_get_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + return rtl_attr_get_int(dev, attr, val); +} + +static int +rtl_get_ports(struct switch_dev *dev, struct switch_val *val) +{ + unsigned int i, mask; + + mask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + struct switch_port *port; + + if (!(mask & (1 << i))) + continue; + + port = &val->value.ports[val->len]; + port->id = i; + if (rtl_get(dev, RTL_PORT_REG(i, TAG_INSERT)) == 2 || i == dev->cpu_port) + port->flags = (1 << SWITCH_PORT_FLAG_TAGGED); + val->len++; + } + + return 0; +} + +static int +rtl_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + struct rtl_priv *priv = to_rtl(dev); + struct rtl_phyregs port; + int en = val->value.i; + int i; + + rtl_set(dev, RTL_REG_EN_TAG_OUT, en && priv->do_cpu); + rtl_set(dev, RTL_REG_EN_TAG_IN, en && priv->do_cpu); + rtl_set(dev, RTL_REG_EN_TAG_CLR, en && priv->do_cpu); + rtl_set(dev, RTL_REG_VLAN_TAG_AWARE, en); + if (en) + rtl_set(dev, RTL_REG_VLAN_FILTER, en); + + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + if (i > 3) + rtl_phy_save(dev, val->port_vlan, &port); + rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); + rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), (en ? (i == dev->cpu_port ? 0 : 1) : 1)); + rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), (en ? (i == dev->cpu_port ? 2 : 1) : 3)); + if (i > 3) + rtl_phy_restore(dev, val->port_vlan, &port); + } + rtl_set(dev, RTL_REG_VLAN_ENABLE, en); + + return 0; +} + +static int +rtl_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) +{ + val->value.i = rtl_get(dev, RTL_REG_VLAN_ENABLE); + return 0; +} + +static int +rtl_set_ports(struct switch_dev *dev, struct switch_val *val) +{ + unsigned int mask = 0; + unsigned int oldmask; + int i; + + for(i = 0; i < val->len; i++) + { + struct switch_port *port = &val->value.ports[i]; + bool tagged = false; + + mask |= (1 << port->id); + + if (port->id == dev->cpu_port) + continue; + + if ((i == dev->cpu_port) || + (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))) + tagged = true; + + /* fix up PVIDs for added ports */ + if (!tagged) + rtl_set(dev, RTL_PORT_REG(port->id, PVID), val->port_vlan); + + rtl_set(dev, RTL_PORT_REG(port->id, NON_PVID_DISCARD), (tagged ? 0 : 1)); + rtl_set(dev, RTL_PORT_REG(port->id, VID_INSERT), (tagged ? 0 : 1)); + rtl_set(dev, RTL_PORT_REG(port->id, TAG_INSERT), (tagged ? 2 : 1)); + } + + oldmask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); + rtl_set(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK), mask); + + /* fix up PVIDs for removed ports, default to last vlan */ + oldmask &= ~mask; + for (i = 0; i < RTL8306_NUM_PORTS; i++) { + if (!(oldmask & (1 << i))) + continue; + + if (i == dev->cpu_port) + continue; + + if (rtl_get(dev, RTL_PORT_REG(i, PVID)) == val->port_vlan) + rtl_set(dev, RTL_PORT_REG(i, PVID), dev->vlans - 1); + } + + return 0; +} + +static struct switch_attr rtl_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .max = 1, + .set = rtl_set_vlan, + .get = rtl_get_vlan, + }, + { + RTL_GLOBAL_REGATTR(EN_TRUNK), + .name = "trunk", + .description = "Enable port trunking", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(TRUNK_PORTSEL), + .name = "trunk_sel", + .description = "Select ports for trunking (0: 0,1 - 1: 3,4)", + .max = 1, + }, +#ifdef DEBUG + { + RTL_GLOBAL_REGATTR(VLAN_FILTER), + .name = "vlan_filter", + .description = "Filter incoming packets for allowed VLANS", + .max = 1, + }, + { + .type = SWITCH_TYPE_INT, + .name = "cpuport", + .description = "CPU Port", + .set = rtl_set_cpuport, + .get = rtl_get_cpuport, + .max = RTL8306_NUM_PORTS, + }, + { + .type = SWITCH_TYPE_INT, + .name = "use_cpuport", + .description = "CPU Port handling flag", + .set = rtl_set_use_cpuport, + .get = rtl_get_use_cpuport, + .max = RTL8306_NUM_PORTS, + }, + { + RTL_GLOBAL_REGATTR(TRAP_CPU), + .name = "trap_cpu", + .description = "VLAN trap to CPU", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(VLAN_TAG_AWARE), + .name = "vlan_tag_aware", + .description = "Enable VLAN tag awareness", + .max = 1, + }, + { + RTL_GLOBAL_REGATTR(VLAN_TAG_ONLY), + .name = "tag_only", + .description = "Only accept tagged packets", + .max = 1, + }, +#endif +}; +static struct switch_attr rtl_port[] = { + { + RTL_PORT_REGATTR(PVID), + .name = "pvid", + .description = "Port VLAN ID", + .max = RTL8306_NUM_VLANS - 1, + }, +#ifdef DEBUG + { + RTL_PORT_REGATTR(NULL_VID_REPLACE), + .name = "null_vid", + .description = "NULL VID gets replaced by port default vid", + .max = 1, + }, + { + RTL_PORT_REGATTR(NON_PVID_DISCARD), + .name = "non_pvid_discard", + .description = "discard packets with VID != PVID", + .max = 1, + }, + { + RTL_PORT_REGATTR(VID_INSERT), + .name = "vid_insert_remove", + .description = "how should the switch insert and remove vids ?", + .max = 3, + }, + { + RTL_PORT_REGATTR(TAG_INSERT), + .name = "tag_insert", + .description = "tag insertion handling", + .max = 3, + }, +#endif +}; + +static struct switch_attr rtl_vlan[] = { + { + RTL_VLAN_REGATTR(VID), + .name = "vid", + .description = "VLAN ID (1-4095)", + .max = 4095, + }, +}; + +static const struct switch_dev_ops rtl8306_ops = { + .attr_global = { + .attr = rtl_globals, + .n_attr = ARRAY_SIZE(rtl_globals), + }, + .attr_port = { + .attr = rtl_port, + .n_attr = ARRAY_SIZE(rtl_port), + }, + .attr_vlan = { + .attr = rtl_vlan, + .n_attr = ARRAY_SIZE(rtl_vlan), + }, + + .get_vlan_ports = rtl_get_ports, + .set_vlan_ports = rtl_set_ports, + .apply_config = rtl_hw_apply, + .reset_switch = rtl_reset, + .get_port_link = rtl_get_port_link, +}; + +static int +rtl8306_config_init(struct phy_device *pdev) +{ + struct net_device *netdev = pdev->attached_dev; + struct rtl_priv *priv = pdev->priv; + struct switch_dev *dev = &priv->dev; + struct switch_val val; + unsigned int chipid, chipver, chiptype; + int err; + + /* Only init the switch for the primary PHY */ + if (pdev->mdio.addr != 0) + return 0; + + val.value.i = 1; + priv->dev.cpu_port = RTL8306_PORT_CPU; + priv->dev.ports = RTL8306_NUM_PORTS; + priv->dev.vlans = RTL8306_NUM_VLANS; + priv->dev.ops = &rtl8306_ops; + priv->do_cpu = 0; + priv->page = -1; + priv->bus = pdev->mdio.bus; + + chipid = rtl_get(dev, RTL_REG_CHIPID); + chipver = rtl_get(dev, RTL_REG_CHIPVER); + chiptype = rtl_get(dev, RTL_REG_CHIPTYPE); + switch(chiptype) { + case 0: + case 2: + strncpy(priv->hwname, RTL_NAME_S, sizeof(priv->hwname)); + priv->type = RTL_TYPE_S; + break; + case 1: + strncpy(priv->hwname, RTL_NAME_SD, sizeof(priv->hwname)); + priv->type = RTL_TYPE_SD; + break; + case 3: + strncpy(priv->hwname, RTL_NAME_SDM, sizeof(priv->hwname)); + priv->type = RTL_TYPE_SDM; + break; + default: + strncpy(priv->hwname, RTL_NAME_UNKNOWN, sizeof(priv->hwname)); + break; + } + + dev->name = priv->hwname; + rtl_hw_init(dev); + + printk(KERN_INFO "Registering %s switch with Chip ID: 0x%04x, version: 0x%04x\n", priv->hwname, chipid, chipver); + + err = register_switch(dev, netdev); + if (err < 0) { + kfree(priv); + return err; + } + + return 0; +} + + +static int +rtl8306_fixup(struct phy_device *pdev) +{ + struct rtl_priv priv; + u16 chipid; + + /* Attach to primary LAN port and WAN port */ + if (pdev->mdio.addr != 0 && pdev->mdio.addr != 4) + return 0; + + memset(&priv, 0, sizeof(priv)); + priv.fixup = true; + priv.page = -1; + priv.bus = pdev->mdio.bus; + chipid = rtl_get(&priv.dev, RTL_REG_CHIPID); + if (chipid == 0x5988) + pdev->phy_id = RTL8306_MAGIC; + + return 0; +} + +static int +rtl8306_probe(struct phy_device *pdev) +{ + struct rtl_priv *priv; + + list_for_each_entry(priv, &phydevs, list) { + /* + * share one rtl_priv instance between virtual phy + * devices on the same bus + */ + if (priv->bus == pdev->mdio.bus) + goto found; + } + priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->bus = pdev->mdio.bus; + +found: + pdev->priv = priv; + return 0; +} + +static void +rtl8306_remove(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + unregister_switch(&priv->dev); + kfree(priv); +} + +static int +rtl8306_config_aneg(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + + /* Only for WAN */ + if (pdev->mdio.addr == 0) + return 0; + + /* Restart autonegotiation */ + rtl_set(&priv->dev, RTL_PORT_REG(4, NWAY), 1); + rtl_set(&priv->dev, RTL_PORT_REG(4, NRESTART), 1); + + return 0; +} + +static int +rtl8306_read_status(struct phy_device *pdev) +{ + struct rtl_priv *priv = pdev->priv; + struct switch_dev *dev = &priv->dev; + + if (pdev->mdio.addr == 4) { + /* WAN */ + pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10; + pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF; + pdev->link = !!rtl_get(dev, RTL_PORT_REG(4, LINK)); + } else { + /* LAN */ + pdev->speed = SPEED_100; + pdev->duplex = DUPLEX_FULL; + pdev->link = 1; + } + + /* + * Bypass generic PHY status read, + * it doesn't work with this switch + */ + if (pdev->link) { + pdev->state = PHY_RUNNING; + netif_carrier_on(pdev->attached_dev); + pdev->adjust_link(pdev->attached_dev); + } else { + pdev->state = PHY_NOLINK; + netif_carrier_off(pdev->attached_dev); + pdev->adjust_link(pdev->attached_dev); + } + + return 0; +} + + +static struct phy_driver rtl8306_driver = { + .name = "Realtek RTL8306S", + .phy_id = RTL8306_MAGIC, + .phy_id_mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .probe = &rtl8306_probe, + .remove = &rtl8306_remove, + .config_init = &rtl8306_config_init, + .config_aneg = &rtl8306_config_aneg, + .read_status = &rtl8306_read_status, +}; + + +static int __init +rtl_init(void) +{ + phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup); + return phy_driver_register(&rtl8306_driver, THIS_MODULE); +} + +static void __exit +rtl_exit(void) +{ + phy_driver_unregister(&rtl8306_driver); +} + +module_init(rtl_init); +module_exit(rtl_exit); +MODULE_LICENSE("GPL"); + diff --git a/ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.c b/ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.c new file mode 100644 index 0000000..e8375e5 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.c @@ -0,0 +1,1624 @@ +/* + * Realtek RTL8366 SMI interface driver + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +#include +#endif + +#include "rtl8366_smi.h" + +#define RTL8366_SMI_ACK_RETRY_COUNT 5 + +#define RTL8366_SMI_HW_STOP_DELAY 25 /* msecs */ +#define RTL8366_SMI_HW_START_DELAY 100 /* msecs */ + +static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi) +{ + ndelay(smi->clk_delay); +} + +static void rtl8366_smi_start(struct rtl8366_smi *smi) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + /* + * Set GPIO pins to output mode, with initial state: + * SCK = 0, SDA = 1 + */ + gpio_direction_output(sck, 0); + gpio_direction_output(sda, 1); + rtl8366_smi_clk_delay(smi); + + /* CLK 1: 0 -> 1, 1 -> 0 */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + + /* CLK 2: */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 1); +} + +static void rtl8366_smi_stop(struct rtl8366_smi *smi) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 0); + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sda, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + + /* add a click */ + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 1); + + /* set GPIO pins to input mode */ + gpio_direction_input(sda); + gpio_direction_input(sck); +} + +static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + for (; len > 0; len--) { + rtl8366_smi_clk_delay(smi); + + /* prepare data */ + gpio_set_value(sda, !!(data & ( 1 << (len - 1)))); + rtl8366_smi_clk_delay(smi); + + /* clocking */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + gpio_set_value(sck, 0); + } +} + +static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data) +{ + unsigned int sda = smi->gpio_sda; + unsigned int sck = smi->gpio_sck; + + gpio_direction_input(sda); + + for (*data = 0; len > 0; len--) { + u32 u; + + rtl8366_smi_clk_delay(smi); + + /* clocking */ + gpio_set_value(sck, 1); + rtl8366_smi_clk_delay(smi); + u = !!gpio_get_value(sda); + gpio_set_value(sck, 0); + + *data |= (u << (len - 1)); + } + + gpio_direction_output(sda, 0); +} + +static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi) +{ + int retry_cnt; + + retry_cnt = 0; + do { + u32 ack; + + rtl8366_smi_read_bits(smi, 1, &ack); + if (ack == 0) + break; + + if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) { + dev_err(smi->parent, "ACK timeout\n"); + return -ETIMEDOUT; + } + } while (1); + + return 0; +} + +static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data) +{ + rtl8366_smi_write_bits(smi, data, 8); + return rtl8366_smi_wait_for_ack(smi); +} + +static int rtl8366_smi_write_byte_noack(struct rtl8366_smi *smi, u8 data) +{ + rtl8366_smi_write_bits(smi, data, 8); + return 0; +} + +static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data) +{ + u32 t; + + /* read data */ + rtl8366_smi_read_bits(smi, 8, &t); + *data = (t & 0xff); + + /* send an ACK */ + rtl8366_smi_write_bits(smi, 0x00, 1); + + return 0; +} + +static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data) +{ + u32 t; + + /* read data */ + rtl8366_smi_read_bits(smi, 8, &t); + *data = (t & 0xff); + + /* send an ACK */ + rtl8366_smi_write_bits(smi, 0x01, 1); + + return 0; +} + +static int __rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) +{ + unsigned long flags; + u8 lo = 0; + u8 hi = 0; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + rtl8366_smi_start(smi); + + /* send READ command */ + ret = rtl8366_smi_write_byte(smi, smi->cmd_read); + if (ret) + goto out; + + /* set ADDR[7:0] */ + ret = rtl8366_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* set ADDR[15:8] */ + ret = rtl8366_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* read DATA[7:0] */ + rtl8366_smi_read_byte0(smi, &lo); + /* read DATA[15:8] */ + rtl8366_smi_read_byte1(smi, &hi); + + *data = ((u32) lo) | (((u32) hi) << 8); + + ret = 0; + + out: + rtl8366_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} +/* Read/write via mdiobus */ +#define MDC_MDIO_CTRL0_REG 31 +#define MDC_MDIO_START_REG 29 +#define MDC_MDIO_CTRL1_REG 21 +#define MDC_MDIO_ADDRESS_REG 23 +#define MDC_MDIO_DATA_WRITE_REG 24 +#define MDC_MDIO_DATA_READ_REG 25 + +#define MDC_MDIO_START_OP 0xFFFF +#define MDC_MDIO_ADDR_OP 0x000E +#define MDC_MDIO_READ_OP 0x0001 +#define MDC_MDIO_WRITE_OP 0x0003 +#define MDC_REALTEK_PHY_ADDR 0x0 + +int __rtl8366_mdio_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) +{ + u32 phy_id = MDC_REALTEK_PHY_ADDR; + struct mii_bus *mbus = smi->ext_mbus; + + BUG_ON(in_interrupt()); + + mutex_lock(&mbus->mdio_lock); + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address control code to register 31 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address to register 23 */ + mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write read control code to register 21 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP); + + /* Write Start command to register 29 */ + mbus->write(smi->ext_mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Read data from register 25 */ + *data = mbus->read(mbus, phy_id, MDC_MDIO_DATA_READ_REG); + + mutex_unlock(&mbus->mdio_lock); + + return 0; +} + +static int __rtl8366_mdio_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + u32 phy_id = MDC_REALTEK_PHY_ADDR; + struct mii_bus *mbus = smi->ext_mbus; + + BUG_ON(in_interrupt()); + + mutex_lock(&mbus->mdio_lock); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address control code to register 31 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write address to register 23 */ + mbus->write(mbus, phy_id, MDC_MDIO_ADDRESS_REG, addr); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write data to register 24 */ + mbus->write(mbus, phy_id, MDC_MDIO_DATA_WRITE_REG, data); + + /* Write Start command to register 29 */ + mbus->write(mbus, phy_id, MDC_MDIO_START_REG, MDC_MDIO_START_OP); + + /* Write data control code to register 21 */ + mbus->write(mbus, phy_id, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP); + + mutex_unlock(&mbus->mdio_lock); + return 0; +} + +int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) +{ + if (smi->ext_mbus) + return __rtl8366_mdio_read_reg(smi, addr, data); + else + return __rtl8366_smi_read_reg(smi, addr, data); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg); + +static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi, + u32 addr, u32 data, bool ack) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&smi->lock, flags); + + rtl8366_smi_start(smi); + + /* send WRITE command */ + ret = rtl8366_smi_write_byte(smi, smi->cmd_write); + if (ret) + goto out; + + /* set ADDR[7:0] */ + ret = rtl8366_smi_write_byte(smi, addr & 0xff); + if (ret) + goto out; + + /* set ADDR[15:8] */ + ret = rtl8366_smi_write_byte(smi, addr >> 8); + if (ret) + goto out; + + /* write DATA[7:0] */ + ret = rtl8366_smi_write_byte(smi, data & 0xff); + if (ret) + goto out; + + /* write DATA[15:8] */ + if (ack) + ret = rtl8366_smi_write_byte(smi, data >> 8); + else + ret = rtl8366_smi_write_byte_noack(smi, data >> 8); + if (ret) + goto out; + + ret = 0; + + out: + rtl8366_smi_stop(smi); + spin_unlock_irqrestore(&smi->lock, flags); + + return ret; +} + +int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + if (smi->ext_mbus) + return __rtl8366_mdio_write_reg(smi, addr, data); + else + return __rtl8366_smi_write_reg(smi, addr, data, true); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg); + +int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + return __rtl8366_smi_write_reg(smi, addr, data, false); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg_noack); + +int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data) +{ + u32 t; + int err; + + err = rtl8366_smi_read_reg(smi, addr, &t); + if (err) + return err; + + err = rtl8366_smi_write_reg(smi, addr, (t & ~mask) | data); + return err; + +} +EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr); + +static int rtl8366_reset(struct rtl8366_smi *smi) +{ + if (smi->hw_reset) { + smi->hw_reset(smi, true); + msleep(RTL8366_SMI_HW_STOP_DELAY); + smi->hw_reset(smi, false); + msleep(RTL8366_SMI_HW_START_DELAY); + return 0; + } + + return smi->ops->reset_chip(smi); +} + +static int rtl8366_mc_is_used(struct rtl8366_smi *smi, int mc_index, int *used) +{ + int err; + int i; + + *used = 0; + for (i = 0; i < smi->num_ports; i++) { + int index = 0; + + err = smi->ops->get_mc_index(smi, i, &index); + if (err) + return err; + + if (mc_index == index) { + *used = 1; + break; + } + } + + return 0; +} + +static int rtl8366_set_vlan(struct rtl8366_smi *smi, int vid, u32 member, + u32 untag, u32 fid) +{ + struct rtl8366_vlan_4k vlan4k; + int err; + int i; + + /* Update the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlan4k.member = member; + vlan4k.untag = untag; + vlan4k.fid = fid; + err = smi->ops->set_vlan_4k(smi, &vlan4k); + if (err) + return err; + + /* Try to find an existing MC entry for this VID */ + for (i = 0; i < smi->num_vlan_mc; i++) { + struct rtl8366_vlan_mc vlanmc; + + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vid == vlanmc.vid) { + /* update the MC entry */ + vlanmc.member = member; + vlanmc.untag = untag; + vlanmc.fid = fid; + + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + break; + } + } + + return err; +} + +static int rtl8366_get_pvid(struct rtl8366_smi *smi, int port, int *val) +{ + struct rtl8366_vlan_mc vlanmc; + int err; + int index; + + err = smi->ops->get_mc_index(smi, port, &index); + if (err) + return err; + + err = smi->ops->get_vlan_mc(smi, index, &vlanmc); + if (err) + return err; + + *val = vlanmc.vid; + return 0; +} + +static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port, + unsigned vid) +{ + struct rtl8366_vlan_mc vlanmc; + struct rtl8366_vlan_4k vlan4k; + int err; + int i; + + /* Try to find an existing MC entry for this VID */ + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vid == vlanmc.vid) { + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + /* We have no MC entry for this VID, try to find an empty one */ + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->get_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + if (vlanmc.vid == 0 && vlanmc.member == 0) { + /* Update the entry from the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlanmc.vid = vid; + vlanmc.member = vlan4k.member; + vlanmc.untag = vlan4k.untag; + vlanmc.fid = vlan4k.fid; + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + /* MC table is full, try to find an unused entry and replace it */ + for (i = 0; i < smi->num_vlan_mc; i++) { + int used; + + err = rtl8366_mc_is_used(smi, i, &used); + if (err) + return err; + + if (!used) { + /* Update the entry from the 4K table */ + err = smi->ops->get_vlan_4k(smi, vid, &vlan4k); + if (err) + return err; + + vlanmc.vid = vid; + vlanmc.member = vlan4k.member; + vlanmc.untag = vlan4k.untag; + vlanmc.fid = vlan4k.fid; + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + + err = smi->ops->set_mc_index(smi, port, i); + return err; + } + } + + dev_err(smi->parent, + "all VLAN member configurations are in use\n"); + + return -ENOSPC; +} + +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + int err; + + err = smi->ops->enable_vlan(smi, enable); + if (err) + return err; + + smi->vlan_enabled = enable; + + if (!enable) { + smi->vlan4k_enabled = 0; + err = smi->ops->enable_vlan4k(smi, enable); + } + + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); + +static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + int err; + + if (enable) { + err = smi->ops->enable_vlan(smi, enable); + if (err) + return err; + + smi->vlan_enabled = enable; + } + + err = smi->ops->enable_vlan4k(smi, enable); + if (err) + return err; + + smi->vlan4k_enabled = enable; + return 0; +} + +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable) +{ + int port; + int err; + + for (port = 0; port < smi->num_ports; port++) { + err = smi->ops->enable_port(smi, port, enable); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_all_ports); + +int rtl8366_reset_vlan(struct rtl8366_smi *smi) +{ + struct rtl8366_vlan_mc vlanmc; + int err; + int i; + + rtl8366_enable_vlan(smi, 0); + rtl8366_enable_vlan4k(smi, 0); + + /* clear VLAN member configurations */ + vlanmc.vid = 0; + vlanmc.priority = 0; + vlanmc.member = 0; + vlanmc.untag = 0; + vlanmc.fid = 0; + for (i = 0; i < smi->num_vlan_mc; i++) { + err = smi->ops->set_vlan_mc(smi, i, &vlanmc); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); + +static int rtl8366_init_vlan(struct rtl8366_smi *smi) +{ + int port; + int err; + + err = rtl8366_reset_vlan(smi); + if (err) + return err; + + for (port = 0; port < smi->num_ports; port++) { + u32 mask; + + if (port == smi->cpu_port) + mask = (1 << smi->num_ports) - 1; + else + mask = (1 << port) | (1 << smi->cpu_port); + + err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); + if (err) + return err; + + err = rtl8366_set_pvid(smi, port, (port + 1)); + if (err) + return err; + } + + return rtl8366_enable_vlan(smi, 1); +} + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +int rtl8366_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_debugfs_open); + +static ssize_t rtl8366_read_debugfs_vlan_mc(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + int i, len = 0; + char *buf = smi->buf; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%2s %6s %4s %6s %6s %3s\n", + "id", "vid","prio", "member", "untag", "fid"); + + for (i = 0; i < smi->num_vlan_mc; ++i) { + struct rtl8366_vlan_mc vlanmc; + + smi->ops->get_vlan_mc(smi, i, &vlanmc); + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%2d %6d %4d 0x%04x 0x%04x %3d\n", + i, vlanmc.vid, vlanmc.priority, + vlanmc.member, vlanmc.untag, vlanmc.fid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +#define RTL8366_VLAN4K_PAGE_SIZE 64 +#define RTL8366_VLAN4K_NUM_PAGES (4096 / RTL8366_VLAN4K_PAGE_SIZE) + +static ssize_t rtl8366_read_debugfs_vlan_4k(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + int i, len = 0; + int offset; + char *buf = smi->buf; + + if (smi->dbg_vlan_4k_page >= RTL8366_VLAN4K_NUM_PAGES) { + len += snprintf(buf + len, sizeof(smi->buf) - len, + "invalid page: %u\n", smi->dbg_vlan_4k_page); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4s %6s %6s %3s\n", + "vid", "member", "untag", "fid"); + + offset = RTL8366_VLAN4K_PAGE_SIZE * smi->dbg_vlan_4k_page; + for (i = 0; i < RTL8366_VLAN4K_PAGE_SIZE; i++) { + struct rtl8366_vlan_4k vlan4k; + + smi->ops->get_vlan_4k(smi, offset + i, &vlan4k); + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d 0x%04x 0x%04x %3d\n", + vlan4k.vid, vlan4k.member, + vlan4k.untag, vlan4k.fid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_read_debugfs_pvid(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + char *buf = smi->buf; + int len = 0; + int i; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%4s %4s\n", + "port", "pvid"); + + for (i = 0; i < smi->num_ports; i++) { + int pvid; + int err; + + err = rtl8366_get_pvid(smi, i, &pvid); + if (err) + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d error\n", i); + else + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d %4d\n", i, pvid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_read_debugfs_reg(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + u32 t, reg = smi->dbg_reg; + int err, len = 0; + char *buf = smi->buf; + + memset(buf, '\0', sizeof(smi->buf)); + + err = rtl8366_smi_read_reg(smi, reg, &t); + if (err) { + len += snprintf(buf, sizeof(smi->buf), + "Read failed (reg: 0x%04x)\n", reg); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf, sizeof(smi->buf), "reg = 0x%04x, val = 0x%04x\n", + reg, t); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t rtl8366_write_debugfs_reg(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + unsigned long data; + u32 reg = smi->dbg_reg; + int err; + size_t len; + char *buf = smi->buf; + + len = min(count, sizeof(smi->buf) - 1); + if (copy_from_user(buf, user_buf, len)) { + dev_err(smi->parent, "copy from user failed\n"); + return -EFAULT; + } + + buf[len] = '\0'; + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + + if (kstrtoul(buf, 16, &data)) { + dev_err(smi->parent, "Invalid reg value %s\n", buf); + } else { + err = rtl8366_smi_write_reg(smi, reg, data); + if (err) { + dev_err(smi->parent, + "writing reg 0x%04x val 0x%04lx failed\n", + reg, data); + } + } + + return count; +} + +static ssize_t rtl8366_read_debugfs_mibs(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = file->private_data; + int i, j, len = 0; + char *buf = smi->buf; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s", + "Counter"); + + for (i = 0; i < smi->num_ports; i++) { + char port_buf[10]; + + snprintf(port_buf, sizeof(port_buf), "Port %d", i); + len += snprintf(buf + len, sizeof(smi->buf) - len, " %12s", + port_buf); + } + len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); + + for (i = 0; i < smi->num_mib_counters; i++) { + len += snprintf(buf + len, sizeof(smi->buf) - len, "%-36s ", + smi->mib_counters[i].name); + for (j = 0; j < smi->num_ports; j++) { + unsigned long long counter = 0; + + if (!smi->ops->get_mib_counter(smi, i, j, &counter)) + len += snprintf(buf + len, + sizeof(smi->buf) - len, + "%12llu ", counter); + else + len += snprintf(buf + len, + sizeof(smi->buf) - len, + "%12s ", "error"); + } + len += snprintf(buf + len, sizeof(smi->buf) - len, "\n"); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_rtl8366_regs = { + .read = rtl8366_read_debugfs_reg, + .write = rtl8366_write_debugfs_reg, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_vlan_mc = { + .read = rtl8366_read_debugfs_vlan_mc, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_vlan_4k = { + .read = rtl8366_read_debugfs_vlan_4k, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_pvid = { + .read = rtl8366_read_debugfs_pvid, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static const struct file_operations fops_rtl8366_mibs = { + .read = rtl8366_read_debugfs_mibs, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + +static void rtl8366_debugfs_init(struct rtl8366_smi *smi) +{ + struct dentry *node; + struct dentry *root; + + if (!smi->debugfs_root) + smi->debugfs_root = debugfs_create_dir(dev_name(smi->parent), + NULL); + + if (!smi->debugfs_root) { + dev_err(smi->parent, "Unable to create debugfs dir\n"); + return; + } + root = smi->debugfs_root; + + node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root, + &smi->dbg_reg); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "reg"); + return; + } + + node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, smi, + &fops_rtl8366_regs); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "val"); + return; + } + + node = debugfs_create_file("vlan_mc", S_IRUSR, root, smi, + &fops_rtl8366_vlan_mc); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_mc"); + return; + } + + node = debugfs_create_u8("vlan_4k_page", S_IRUGO | S_IWUSR, root, + &smi->dbg_vlan_4k_page); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k_page"); + return; + } + + node = debugfs_create_file("vlan_4k", S_IRUSR, root, smi, + &fops_rtl8366_vlan_4k); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k"); + return; + } + + node = debugfs_create_file("pvid", S_IRUSR, root, smi, + &fops_rtl8366_pvid); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "pvid"); + return; + } + + node = debugfs_create_file("mibs", S_IRUSR, smi->debugfs_root, smi, + &fops_rtl8366_mibs); + if (!node) + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "mibs"); +} + +static void rtl8366_debugfs_remove(struct rtl8366_smi *smi) +{ + if (smi->debugfs_root) { + debugfs_remove_recursive(smi->debugfs_root); + smi->debugfs_root = NULL; + } +} +#else +static inline void rtl8366_debugfs_init(struct rtl8366_smi *smi) {} +static inline void rtl8366_debugfs_remove(struct rtl8366_smi *smi) {} +#endif /* CONFIG_RTL8366_SMI_DEBUG_FS */ + +static int rtl8366_smi_mii_init(struct rtl8366_smi *smi) +{ + int ret; + +#ifdef CONFIG_OF + struct device_node *np = NULL; + + np = of_get_child_by_name(smi->parent->of_node, "mdio-bus"); +#endif + + smi->mii_bus = mdiobus_alloc(); + if (smi->mii_bus == NULL) { + ret = -ENOMEM; + goto err; + } + + smi->mii_bus->priv = (void *) smi; + smi->mii_bus->name = dev_name(smi->parent); + smi->mii_bus->read = smi->ops->mii_read; + smi->mii_bus->write = smi->ops->mii_write; + snprintf(smi->mii_bus->id, MII_BUS_ID_SIZE, "%s", + dev_name(smi->parent)); + smi->mii_bus->parent = smi->parent; + smi->mii_bus->phy_mask = ~(0x1f); + +#ifdef CONFIG_OF + if (np) + ret = of_mdiobus_register(smi->mii_bus, np); + else +#endif + ret = mdiobus_register(smi->mii_bus); + + if (ret) + goto err_free; + + return 0; + + err_free: + mdiobus_free(smi->mii_bus); + err: + return ret; +} + +static void rtl8366_smi_mii_cleanup(struct rtl8366_smi *smi) +{ + mdiobus_unregister(smi->mii_bus); + mdiobus_free(smi->mii_bus); +} + +int rtl8366_sw_reset_switch(struct switch_dev *dev) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + err = rtl8366_reset(smi); + if (err) + return err; + + err = smi->ops->setup(smi); + if (err) + return err; + + err = rtl8366_reset_vlan(smi); + if (err) + return err; + + err = rtl8366_enable_vlan(smi, 1); + if (err) + return err; + + return rtl8366_enable_all_ports(smi, 1); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_reset_switch); + +int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366_get_pvid(smi, port, val); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_pvid); + +int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366_set_pvid(smi, port, val); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_port_pvid); + +int rtl8366_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int i, len = 0; + unsigned long long counter = 0; + char *buf = smi->buf; + + if (val->port_vlan >= smi->num_ports) + return -EINVAL; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "Port %d MIB counters\n", + val->port_vlan); + + for (i = 0; i < smi->num_mib_counters; ++i) { + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%-36s: ", smi->mib_counters[i].name); + if (!smi->ops->get_mib_counter(smi, i, val->port_vlan, + &counter)) + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%llu\n", counter); + else + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%s\n", "error"); + } + + val->value.s = buf; + val->len = len; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_mib); + +int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats, + int txb_id, int rxb_id) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + unsigned long long counter = 0; + int ret; + + if (port >= smi->num_ports) + return -EINVAL; + + ret = smi->ops->get_mib_counter(smi, txb_id, port, &counter); + if (ret) + return ret; + + stats->tx_bytes = counter; + + ret = smi->ops->get_mib_counter(smi, rxb_id, port, &counter); + if (ret) + return ret; + + stats->rx_bytes = counter; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_port_stats); + +int rtl8366_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + int i; + u32 len = 0; + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + char *buf = smi->buf; + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + memset(buf, '\0', sizeof(smi->buf)); + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "VLAN %d: Ports: '", vlan4k.vid); + + for (i = 0; i < smi->num_ports; i++) { + if (!(vlan4k.member & (1 << i))) + continue; + + len += snprintf(buf + len, sizeof(smi->buf) - len, "%d%s", i, + (vlan4k.untag & (1 << i)) ? "" : "t"); + } + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "', members=%04x, untag=%04x, fid=%u", + vlan4k.member, vlan4k.untag, vlan4k.fid); + + val->value.s = buf; + val->len = len; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_info); + +int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + struct switch_port *port; + struct rtl8366_vlan_4k vlan4k; + int i; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + + port = &val->value.ports[0]; + val->len = 0; + for (i = 0; i < smi->num_ports; i++) { + if (!(vlan4k.member & BIT(i))) + continue; + + port->id = i; + port->flags = (vlan4k.untag & BIT(i)) ? + 0 : BIT(SWITCH_PORT_FLAG_TAGGED); + val->len++; + port++; + } + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_ports); + +int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + struct switch_port *port; + u32 member = 0; + u32 untag = 0; + int err; + int i; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + port = &val->value.ports[0]; + for (i = 0; i < val->len; i++, port++) { + int pvid = 0; + member |= BIT(port->id); + + if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) + untag |= BIT(port->id); + + /* + * To ensure that we have a valid MC entry for this VLAN, + * initialize the port VLAN ID here. + */ + err = rtl8366_get_pvid(smi, port->id, &pvid); + if (err < 0) + return err; + if (pvid == 0) { + err = rtl8366_set_pvid(smi, port->id, val->port_vlan); + if (err < 0) + return err; + } + } + + return rtl8366_set_vlan(smi, val->port_vlan, member, untag, 0); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_ports); + +int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + val->value.i = vlan4k.fid; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_fid); + +int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + if (val->value.i < 0 || val->value.i > attr->max) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + return rtl8366_set_vlan(smi, val->port_vlan, + vlan4k.member, + vlan4k.untag, + val->value.i); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_fid); + +int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (attr->ofs > 2) + return -EINVAL; + + if (attr->ofs == 1) + val->value.i = smi->vlan_enabled; + else + val->value.i = smi->vlan4k_enabled; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_enable); + +int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (attr->ofs > 2) + return -EINVAL; + + if (attr->ofs == 1) + err = rtl8366_enable_vlan(smi, val->value.i); + else + err = rtl8366_enable_vlan4k(smi, val->value.i); + + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_enable); + +struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent) +{ + struct rtl8366_smi *smi; + + BUG_ON(!parent); + + smi = kzalloc(sizeof(*smi), GFP_KERNEL); + if (!smi) { + dev_err(parent, "no memory for private data\n"); + return NULL; + } + + smi->parent = parent; + return smi; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_alloc); + +static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name) +{ + int err; + + if (!smi->ext_mbus) { + err = gpio_request(smi->gpio_sda, name); + if (err) { + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", + smi->gpio_sda, err); + goto err_out; + } + + err = gpio_request(smi->gpio_sck, name); + if (err) { + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", + smi->gpio_sck, err); + goto err_free_sda; + } + } + + spin_lock_init(&smi->lock); + + /* start the switch */ + if (smi->hw_reset) { + smi->hw_reset(smi, false); + msleep(RTL8366_SMI_HW_START_DELAY); + } + + return 0; + + err_free_sda: + gpio_free(smi->gpio_sda); + err_out: + return err; +} + +static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi) +{ + if (smi->hw_reset) + smi->hw_reset(smi, true); + + if (!smi->ext_mbus) { + gpio_free(smi->gpio_sck); + gpio_free(smi->gpio_sda); + } +} + +enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata) +{ + static struct rtl8366_smi smi; + enum rtl8366_type type = RTL8366_TYPE_UNKNOWN; + u32 reg = 0; + + memset(&smi, 0, sizeof(smi)); + smi.gpio_sda = pdata->gpio_sda; + smi.gpio_sck = pdata->gpio_sck; + smi.clk_delay = 10; + smi.cmd_read = 0xa9; + smi.cmd_write = 0xa8; + + if (__rtl8366_smi_init(&smi, "rtl8366")) + goto out; + + if (rtl8366_smi_read_reg(&smi, 0x5c, ®)) + goto cleanup; + + switch(reg) { + case 0x6027: + printk("Found an RTL8366S switch\n"); + type = RTL8366_TYPE_S; + break; + case 0x5937: + printk("Found an RTL8366RB switch\n"); + type = RTL8366_TYPE_RB; + break; + default: + printk("Found an Unknown RTL8366 switch (id=0x%04x)\n", reg); + break; + } + +cleanup: + __rtl8366_smi_cleanup(&smi); +out: + return type; +} + +int rtl8366_smi_init(struct rtl8366_smi *smi) +{ + int err; + + if (!smi->ops) + return -EINVAL; + + err = __rtl8366_smi_init(smi, dev_name(smi->parent)); + if (err) + goto err_out; + + if (!smi->ext_mbus) + dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n", + smi->gpio_sda, smi->gpio_sck); + else + dev_info(smi->parent, "using MDIO bus '%s'\n", smi->ext_mbus->name); + + err = smi->ops->detect(smi); + if (err) { + dev_err(smi->parent, "chip detection failed, err=%d\n", err); + goto err_free_sck; + } + + err = rtl8366_reset(smi); + if (err) + goto err_free_sck; + + err = smi->ops->setup(smi); + if (err) { + dev_err(smi->parent, "chip setup failed, err=%d\n", err); + goto err_free_sck; + } + + err = rtl8366_init_vlan(smi); + if (err) { + dev_err(smi->parent, "VLAN initialization failed, err=%d\n", + err); + goto err_free_sck; + } + + err = rtl8366_enable_all_ports(smi, 1); + if (err) + goto err_free_sck; + + err = rtl8366_smi_mii_init(smi); + if (err) + goto err_free_sck; + + rtl8366_debugfs_init(smi); + + return 0; + + err_free_sck: + __rtl8366_smi_cleanup(smi); + err_out: + return err; +} +EXPORT_SYMBOL_GPL(rtl8366_smi_init); + +void rtl8366_smi_cleanup(struct rtl8366_smi *smi) +{ + rtl8366_debugfs_remove(smi); + rtl8366_smi_mii_cleanup(smi); + __rtl8366_smi_cleanup(smi); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup); + +#ifdef CONFIG_OF +static void rtl8366_smi_reset(struct rtl8366_smi *smi, bool active) +{ + if (active) + reset_control_assert(smi->reset); + else + reset_control_deassert(smi->reset); +} + +int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + int sck = of_get_named_gpio(pdev->dev.of_node, "gpio-sck", 0); + int sda = of_get_named_gpio(pdev->dev.of_node, "gpio-sda", 0); + struct device_node *np = pdev->dev.of_node; + struct device_node *mdio_node; + + mdio_node = of_parse_phandle(np, "mii-bus", 0); + if (!mdio_node) { + dev_err(&pdev->dev, "cannot find mdio node phandle"); + goto try_gpio; + } + + smi->ext_mbus = of_mdio_find_bus(mdio_node); + if (!smi->ext_mbus) { + dev_info(&pdev->dev, + "cannot find mdio bus from bus handle (yet)"); + goto try_gpio; + } + + return 0; + +try_gpio: + if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) { + if (!mdio_node) { + dev_err(&pdev->dev, "gpios missing in devictree\n"); + return -EINVAL; + } else { + return -EPROBE_DEFER; + } + } + + smi->gpio_sda = sda; + smi->gpio_sck = sck; + smi->reset = devm_reset_control_get(&pdev->dev, "switch"); + if (!IS_ERR(smi->reset)) + smi->hw_reset = rtl8366_smi_reset; + + return 0; +} +#else +static inline int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + return -ENODEV; +} +#endif + +int rtl8366_smi_probe_plat(struct platform_device *pdev, struct rtl8366_smi *smi) +{ + struct rtl8366_platform_data *pdata = pdev->dev.platform_data; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data specified\n"); + return -EINVAL; + } + + smi->gpio_sda = pdata->gpio_sda; + smi->gpio_sck = pdata->gpio_sck; + smi->hw_reset = pdata->hw_reset; + + return 0; +} + + +struct rtl8366_smi *rtl8366_smi_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_alloc(&pdev->dev); + if (!smi) + return NULL; + + if (pdev->dev.of_node) + err = rtl8366_smi_probe_of(pdev, smi); + else + err = rtl8366_smi_probe_plat(pdev, smi); + + if (err) + goto free_smi; + + return smi; + +free_smi: + kfree(smi); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_probe); + +MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); diff --git a/ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.h b/ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.h new file mode 100644 index 0000000..d1d988a --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/rtl8366_smi.h @@ -0,0 +1,160 @@ +/* + * Realtek RTL8366 SMI interface driver defines + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * 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. + */ + +#ifndef _RTL8366_SMI_H +#define _RTL8366_SMI_H + +#include +#include +#include +#include + +struct rtl8366_smi_ops; +struct rtl8366_vlan_ops; +struct mii_bus; +struct dentry; +struct inode; +struct file; + +struct rtl8366_mib_counter { + unsigned base; + unsigned offset; + unsigned length; + const char *name; +}; + +struct rtl8366_smi { + struct device *parent; + unsigned int gpio_sda; + unsigned int gpio_sck; + void (*hw_reset)(struct rtl8366_smi *smi, bool active); + unsigned int clk_delay; /* ns */ + u8 cmd_read; + u8 cmd_write; + spinlock_t lock; + struct mii_bus *mii_bus; + int mii_irq[PHY_MAX_ADDR]; + struct switch_dev sw_dev; + + unsigned int cpu_port; + unsigned int num_ports; + unsigned int num_vlan_mc; + unsigned int num_mib_counters; + struct rtl8366_mib_counter *mib_counters; + + struct rtl8366_smi_ops *ops; + + int vlan_enabled; + int vlan4k_enabled; + + char buf[4096]; + + struct reset_control *reset; + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS + struct dentry *debugfs_root; + u16 dbg_reg; + u8 dbg_vlan_4k_page; +#endif + struct mii_bus *ext_mbus; +}; + +struct rtl8366_vlan_mc { + u16 vid; + u16 untag; + u16 member; + u8 fid; + u8 priority; +}; + +struct rtl8366_vlan_4k { + u16 vid; + u16 untag; + u16 member; + u8 fid; +}; + +struct rtl8366_smi_ops { + int (*detect)(struct rtl8366_smi *smi); + int (*reset_chip)(struct rtl8366_smi *smi); + int (*setup)(struct rtl8366_smi *smi); + + int (*mii_read)(struct mii_bus *bus, int addr, int reg); + int (*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val); + + int (*get_vlan_mc)(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc); + int (*set_vlan_mc)(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc); + int (*get_vlan_4k)(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k); + int (*set_vlan_4k)(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k); + int (*get_mc_index)(struct rtl8366_smi *smi, int port, int *val); + int (*set_mc_index)(struct rtl8366_smi *smi, int port, int index); + int (*get_mib_counter)(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val); + int (*is_vlan_valid)(struct rtl8366_smi *smi, unsigned vlan); + int (*enable_vlan)(struct rtl8366_smi *smi, int enable); + int (*enable_vlan4k)(struct rtl8366_smi *smi, int enable); + int (*enable_port)(struct rtl8366_smi *smi, int port, int enable); +}; + +struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent); +int rtl8366_smi_init(struct rtl8366_smi *smi); +void rtl8366_smi_cleanup(struct rtl8366_smi *smi); +int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data); +int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data); +int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data); +int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data); + +int rtl8366_reset_vlan(struct rtl8366_smi *smi); +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable); +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable); + +#ifdef CONFIG_RTL8366_SMI_DEBUG_FS +int rtl8366_debugfs_open(struct inode *inode, struct file *file); +#endif + +static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw) +{ + return container_of(sw, struct rtl8366_smi, sw_dev); +} + +int rtl8366_sw_reset_switch(struct switch_dev *dev); +int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val); +int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val); +int rtl8366_sw_get_port_mib(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_info(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val); +int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val); +int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_set_vlan_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val); +int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats, + int txb_id, int rxb_id); + +struct rtl8366_smi* rtl8366_smi_probe(struct platform_device *pdev); + +#endif /* _RTL8366_SMI_H */ diff --git a/ipq806x/files-5.4/drivers/net/phy/rtl8366rb.c b/ipq806x/files-5.4/drivers/net/phy/rtl8366rb.c new file mode 100644 index 0000000..0e01160 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/rtl8366rb.c @@ -0,0 +1,1532 @@ +/* + * Platform driver for the Realtek RTL8366RB ethernet switch + * + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Seppälä + * Copyright (C) 2010 Roman Yeryomin + * Copyright (C) 2011 Colin Leitner + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8366RB_DRIVER_DESC "Realtek RTL8366RB ethernet switch driver" +#define RTL8366RB_DRIVER_VER "0.2.4" + +#define RTL8366RB_PHY_NO_MAX 4 +#define RTL8366RB_PHY_PAGE_MAX 7 +#define RTL8366RB_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366RB_SGCR 0x0000 +#define RTL8366RB_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366RB_SGCR_MAX_LENGTH(_x) (_x << 4) +#define RTL8366RB_SGCR_MAX_LENGTH_MASK RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_MAX_LENGTH_1522 RTL8366RB_SGCR_MAX_LENGTH(0x0) +#define RTL8366RB_SGCR_MAX_LENGTH_1536 RTL8366RB_SGCR_MAX_LENGTH(0x1) +#define RTL8366RB_SGCR_MAX_LENGTH_1552 RTL8366RB_SGCR_MAX_LENGTH(0x2) +#define RTL8366RB_SGCR_MAX_LENGTH_9216 RTL8366RB_SGCR_MAX_LENGTH(0x3) +#define RTL8366RB_SGCR_EN_VLAN BIT(13) +#define RTL8366RB_SGCR_EN_VLAN_4KTB BIT(14) + +/* Port Enable Control register */ +#define RTL8366RB_PECR 0x0001 + +/* Port Mirror Control Register */ +#define RTL8366RB_PMCR 0x0007 +#define RTL8366RB_PMCR_SOURCE_PORT(_x) (_x) +#define RTL8366RB_PMCR_SOURCE_PORT_MASK 0x000f +#define RTL8366RB_PMCR_MONITOR_PORT(_x) ((_x) << 4) +#define RTL8366RB_PMCR_MONITOR_PORT_MASK 0x00f0 +#define RTL8366RB_PMCR_MIRROR_RX BIT(8) +#define RTL8366RB_PMCR_MIRROR_TX BIT(9) +#define RTL8366RB_PMCR_MIRROR_SPC BIT(10) +#define RTL8366RB_PMCR_MIRROR_ISO BIT(11) + +/* Switch Security Control registers */ +#define RTL8366RB_SSCR0 0x0002 +#define RTL8366RB_SSCR1 0x0003 +#define RTL8366RB_SSCR2 0x0004 +#define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) + +#define RTL8366RB_RESET_CTRL_REG 0x0100 +#define RTL8366RB_CHIP_CTRL_RESET_HW 1 +#define RTL8366RB_CHIP_CTRL_RESET_SW (1 << 1) + +#define RTL8366RB_CHIP_VERSION_CTRL_REG 0x050A +#define RTL8366RB_CHIP_VERSION_MASK 0xf +#define RTL8366RB_CHIP_ID_REG 0x0509 +#define RTL8366RB_CHIP_ID_8366 0x5937 + +/* PHY registers control */ +#define RTL8366RB_PHY_ACCESS_CTRL_REG 0x8000 +#define RTL8366RB_PHY_ACCESS_DATA_REG 0x8002 + +#define RTL8366RB_PHY_CTRL_READ 1 +#define RTL8366RB_PHY_CTRL_WRITE 0 + +#define RTL8366RB_PHY_REG_MASK 0x1f +#define RTL8366RB_PHY_PAGE_OFFSET 5 +#define RTL8366RB_PHY_PAGE_MASK (0xf << 5) +#define RTL8366RB_PHY_NO_OFFSET 9 +#define RTL8366RB_PHY_NO_MASK (0x1f << 9) + +#define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f + +/* LED control registers */ +#define RTL8366RB_LED_BLINKRATE_REG 0x0430 +#define RTL8366RB_LED_BLINKRATE_BIT 0 +#define RTL8366RB_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366RB_LED_CTRL_REG 0x0431 +#define RTL8366RB_LED_0_1_CTRL_REG 0x0432 +#define RTL8366RB_LED_2_3_CTRL_REG 0x0433 + +#define RTL8366RB_MIB_COUNT 33 +#define RTL8366RB_GLOBAL_MIB_COUNT 1 +#define RTL8366RB_MIB_COUNTER_PORT_OFFSET 0x0050 +#define RTL8366RB_MIB_COUNTER_BASE 0x1000 +#define RTL8366RB_MIB_CTRL_REG 0x13F0 +#define RTL8366RB_MIB_CTRL_USER_MASK 0x0FFC +#define RTL8366RB_MIB_CTRL_BUSY_MASK BIT(0) +#define RTL8366RB_MIB_CTRL_RESET_MASK BIT(1) +#define RTL8366RB_MIB_CTRL_PORT_RESET(_p) BIT(2 + (_p)) +#define RTL8366RB_MIB_CTRL_GLOBAL_RESET BIT(11) + +#define RTL8366RB_PORT_VLAN_CTRL_BASE 0x0063 +#define RTL8366RB_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366RB_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + + +#define RTL8366RB_VLAN_TABLE_READ_BASE 0x018C +#define RTL8366RB_VLAN_TABLE_WRITE_BASE 0x0185 + + +#define RTL8366RB_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366RB_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366RB_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366RB_VLAN_MC_BASE(_x) (0x0020 + (_x) * 3) + + +#define RTL8366RB_PORT_LINK_STATUS_BASE 0x0014 +#define RTL8366RB_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366RB_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366RB_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366RB_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366RB_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366RB_PORT_STATUS_AN_MASK 0x0080 + + +#define RTL8366RB_PORT_NUM_CPU 5 +#define RTL8366RB_NUM_PORTS 6 +#define RTL8366RB_NUM_VLANS 16 +#define RTL8366RB_NUM_LEDGROUPS 4 +#define RTL8366RB_NUM_VIDS 4096 +#define RTL8366RB_PRIORITYMAX 7 +#define RTL8366RB_FIDMAX 7 + + +#define RTL8366RB_PORT_1 (1 << 0) /* In userspace port 0 */ +#define RTL8366RB_PORT_2 (1 << 1) /* In userspace port 1 */ +#define RTL8366RB_PORT_3 (1 << 2) /* In userspace port 2 */ +#define RTL8366RB_PORT_4 (1 << 3) /* In userspace port 3 */ +#define RTL8366RB_PORT_5 (1 << 4) /* In userspace port 4 */ + +#define RTL8366RB_PORT_CPU (1 << 5) /* CPU port */ + +#define RTL8366RB_PORT_ALL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5 | \ + RTL8366RB_PORT_CPU) + +#define RTL8366RB_PORT_ALL_BUT_CPU (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4 | \ + RTL8366RB_PORT_5) + +#define RTL8366RB_PORT_ALL_EXTERNAL (RTL8366RB_PORT_1 | \ + RTL8366RB_PORT_2 | \ + RTL8366RB_PORT_3 | \ + RTL8366RB_PORT_4) + +#define RTL8366RB_PORT_ALL_INTERNAL RTL8366RB_PORT_CPU + +#define RTL8366RB_VLAN_VID_MASK 0xfff +#define RTL8366RB_VLAN_PRIORITY_SHIFT 12 +#define RTL8366RB_VLAN_PRIORITY_MASK 0x7 +#define RTL8366RB_VLAN_UNTAG_SHIFT 8 +#define RTL8366RB_VLAN_UNTAG_MASK 0xff +#define RTL8366RB_VLAN_MEMBER_MASK 0xff +#define RTL8366RB_VLAN_FID_MASK 0x7 + + +/* Port ingress bandwidth control */ +#define RTL8366RB_IB_BASE 0x0200 +#define RTL8366RB_IB_REG(pnum) (RTL8366RB_IB_BASE + pnum) +#define RTL8366RB_IB_BDTH_MASK 0x3fff +#define RTL8366RB_IB_PREIFG_OFFSET 14 +#define RTL8366RB_IB_PREIFG_MASK (1 << RTL8366RB_IB_PREIFG_OFFSET) + +/* Port egress bandwidth control */ +#define RTL8366RB_EB_BASE 0x02d1 +#define RTL8366RB_EB_REG(pnum) (RTL8366RB_EB_BASE + pnum) +#define RTL8366RB_EB_BDTH_MASK 0x3fff +#define RTL8366RB_EB_PREIFG_REG 0x02f8 +#define RTL8366RB_EB_PREIFG_OFFSET 9 +#define RTL8366RB_EB_PREIFG_MASK (1 << RTL8366RB_EB_PREIFG_OFFSET) + +#define RTL8366RB_BDTH_SW_MAX 1048512 +#define RTL8366RB_BDTH_UNIT 64 +#define RTL8366RB_BDTH_REG_DEFAULT 16383 + +/* QOS */ +#define RTL8366RB_QOS_BIT 15 +#define RTL8366RB_QOS_MASK (1 << RTL8366RB_QOS_BIT) +/* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */ +#define RTL8366RB_QOS_DEFAULT_PREIFG 1 + + +#define RTL8366RB_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8366RB_MIB_TXB_ID 20 /* IfOutOctets */ + +static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 0, 64, 2, "Dot1dTpPortInDiscards" }, + { 0, 66, 2, "IfOutUcastPkts" }, + { 0, 68, 2, "IfOutMulticastPkts" }, + { 0, 70, 2, "IfOutBroadcastPkts" }, +}; + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static int rtl8366rb_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + u32 data; + + rtl8366_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG, + RTL8366RB_CHIP_CTRL_RESET_HW); + do { + msleep(1); + if (rtl8366_smi_read_reg(smi, RTL8366RB_RESET_CTRL_REG, &data)) + return -EIO; + + if (!(data & RTL8366RB_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + printk("Timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366rb_setup(struct rtl8366_smi *smi) +{ + int err; +#ifdef CONFIG_OF + unsigned i; + struct device_node *np; + unsigned num_initvals; + const __be32 *paddr; + + np = smi->parent->of_node; + + paddr = of_get_property(np, "realtek,initvals", &num_initvals); + if (paddr) { + dev_info(smi->parent, "applying initvals from DTS\n"); + + if (num_initvals < (2 * sizeof(*paddr))) + return -EINVAL; + + num_initvals /= sizeof(*paddr); + + for (i = 0; i < num_initvals - 1; i += 2) { + u32 reg = be32_to_cpup(paddr + i); + u32 val = be32_to_cpup(paddr + i + 1); + + REG_WR(smi, reg, val); + } + } +#endif + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_MAX_LENGTH_MASK, + RTL8366RB_SGCR_MAX_LENGTH_1536); + + /* enable learning for all ports */ + REG_WR(smi, RTL8366RB_SSCR0, 0); + + /* enable auto ageing for all ports */ + REG_WR(smi, RTL8366RB_SSCR1, 0); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8366RB_VLAN_INGRESS_CTRL2_REG, RTL8366RB_PORT_ALL); + + /* don't drop packets whose DA has not been learned */ + REG_RMW(smi, RTL8366RB_SSCR2, RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0); + + return 0; +} + +static int rtl8366rb_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 *data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366RB_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366RB_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | + ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | + (addr & RTL8366RB_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, 0); + if (ret) + return ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_PHY_ACCESS_DATA_REG, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366RB_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366RB_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366RB_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366RB_PHY_ACCESS_CTRL_REG, + RTL8366RB_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366RB_PHY_NO_OFFSET)) | + ((page << RTL8366RB_PHY_PAGE_OFFSET) & RTL8366RB_PHY_PAGE_MASK) | + (addr & RTL8366RB_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366rb_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8366RB_NUM_PORTS || counter >= RTL8366RB_MIB_COUNT) + return -EINVAL; + + addr = RTL8366RB_MIB_COUNTER_BASE + + RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) + + rtl8366rb_mib_counters[counter].offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + data = 0; /* writing data will be discard by ASIC */ + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + /* read MIB control register */ + err = rtl8366_smi_read_reg(smi, RTL8366RB_MIB_CTRL_REG, &data); + if (err) + return err; + + if (data & RTL8366RB_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8366RB_MIB_CTRL_RESET_MASK) + return -EIO; + + mibvalue = 0; + for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) { + err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); + if (err) + return err; + + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8366rb_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8366RB_NUM_VIDS) + return -EINVAL; + + /* write VID */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_VLAN_TABLE_WRITE_BASE, + vid & RTL8366RB_VLAN_VID_MASK); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_READ_CTRL); + if (err) + return err; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366RB_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (err) + return err; + } + + vlan4k->vid = vid; + vlan4k->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlan4k->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlan4k->fid = data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[3]; + int err; + int i; + + if (vlan4k->vid >= RTL8366RB_NUM_VIDS || + vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] = vlan4k->vid & RTL8366RB_VLAN_VID_MASK; + data[1] = (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] = vlan4k->fid & RTL8366RB_VLAN_FID_MASK; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366RB_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (err) + return err; + } + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366RB_TABLE_ACCESS_CTRL_REG, + RTL8366RB_TABLE_VLAN_WRITE_CTRL); + + return err; +} + +static int rtl8366rb_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8366RB_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366RB_VLAN_MC_BASE(index) + i, + &data[i]); + if (err) + return err; + } + + vlanmc->vid = data[0] & RTL8366RB_VLAN_VID_MASK; + vlanmc->priority = (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) & + RTL8366RB_VLAN_PRIORITY_MASK; + vlanmc->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) & + RTL8366RB_VLAN_UNTAG_MASK; + vlanmc->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK; + vlanmc->fid = data[2] & RTL8366RB_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366rb_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[3]; + int err; + int i; + + if (index >= RTL8366RB_NUM_VLANS || + vlanmc->vid >= RTL8366RB_NUM_VIDS || + vlanmc->priority > RTL8366RB_PRIORITYMAX || + vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366RB_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) << + RTL8366RB_VLAN_PRIORITY_SHIFT); + data[1] = (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) << + RTL8366RB_VLAN_UNTAG_SHIFT); + data[2] = vlanmc->fid & RTL8366RB_VLAN_FID_MASK; + + for (i = 0; i < 3; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366RB_VLAN_MC_BASE(index) + i, + data[i]); + if (err) + return err; + } + + return 0; +} + +static int rtl8366rb_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + *val = (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366RB_PORT_VLAN_CTRL_MASK; + + return 0; + +} + +static int rtl8366rb_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8366RB_NUM_PORTS || index >= RTL8366RB_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PORT_VLAN_CTRL_REG(port), + RTL8366RB_PORT_VLAN_CTRL_MASK << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); +} + +static int rtl8366rb_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8366RB_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8366RB_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8366rb_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN, + (enable) ? RTL8366RB_SGCR_EN_VLAN : 0); +} + +static int rtl8366rb_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, + RTL8366RB_SGCR_EN_VLAN_4KTB, + (enable) ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0); +} + +static int rtl8366rb_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, (1 << port), + (enable) ? 0 : (1 << port)); +} + +static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, + RTL8366RB_MIB_CTRL_GLOBAL_RESET); +} + +static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_LED_BLINKRATE_REG, &data); + + val->value.i = (data & (RTL8366RB_LED_BLINKRATE_MASK)); + + return 0; +} + +static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->value.i >= 6) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_LED_BLINKRATE_REG, + RTL8366RB_LED_BLINKRATE_MASK, + val->value.i); +} + +static int rtl8366rb_sw_get_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_SSCR0, &data); + val->value.i = !data; + + return 0; +} + + +static int rtl8366rb_sw_set_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 portmask = 0; + int err = 0; + + if (!val->value.i) + portmask = RTL8366RB_PORT_ALL; + + /* set learning for all ports */ + REG_WR(smi, RTL8366RB_SSCR0, portmask); + + /* set auto ageing for all ports */ + REG_WR(smi, RTL8366RB_SSCR1, portmask); + + return 0; +} + +static int rtl8366rb_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_PORT_LINK_STATUS_BASE + (port / 2), + &data); + + if (port % 2) + data = data >> 8; + + link->link = !!(data & RTL8366RB_PORT_STATUS_LINK_MASK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8366RB_PORT_STATUS_DUPLEX_MASK); + link->rx_flow = !!(data & RTL8366RB_PORT_STATUS_RXPAUSE_MASK); + link->tx_flow = !!(data & RTL8366RB_PORT_STATUS_TXPAUSE_MASK); + link->aneg = !!(data & RTL8366RB_PORT_STATUS_AN_MASK); + + speed = (data & RTL8366RB_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8366rb_sw_set_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + u32 mask; + u32 reg; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + if (val->port_vlan == RTL8366RB_PORT_NUM_CPU) { + reg = RTL8366RB_LED_BLINKRATE_REG; + mask = 0xF << 4; + data = val->value.i << 4; + } else { + reg = RTL8366RB_LED_CTRL_REG; + mask = 0xF << (val->port_vlan * 4), + data = val->value.i << (val->port_vlan * 4); + } + + return rtl8366_smi_rmwr(smi, reg, mask, data); +} + +static int rtl8366rb_sw_get_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + + if (val->port_vlan >= RTL8366RB_NUM_LEDGROUPS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_LED_CTRL_REG, &data); + val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; + + return 0; +} + +static int rtl8366rb_sw_set_port_disable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 mask, data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + mask = 1 << val->port_vlan ; + if (val->value.i) + data = mask; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PECR, mask, data); +} + +static int rtl8366rb_sw_get_port_disable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_PECR, &data); + if (data & (1 << val->port_vlan)) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_port_rate_in(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) + val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; + else + val->value.i = RTL8366RB_BDTH_REG_DEFAULT; + + return rtl8366_smi_rmwr(smi, RTL8366RB_IB_REG(val->port_vlan), + RTL8366RB_IB_BDTH_MASK | RTL8366RB_IB_PREIFG_MASK, + val->value.i | + (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_IB_PREIFG_OFFSET)); + +} + +static int rtl8366rb_sw_get_port_rate_in(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_IB_REG(val->port_vlan), &data); + data &= RTL8366RB_IB_BDTH_MASK; + if (data < RTL8366RB_IB_BDTH_MASK) + data += 1; + + val->value.i = (int)data * RTL8366RB_BDTH_UNIT; + + return 0; +} + +static int rtl8366rb_sw_set_port_rate_out(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_rmwr(smi, RTL8366RB_EB_PREIFG_REG, + RTL8366RB_EB_PREIFG_MASK, + (RTL8366RB_QOS_DEFAULT_PREIFG << RTL8366RB_EB_PREIFG_OFFSET)); + + if (val->value.i > 0 && val->value.i < RTL8366RB_BDTH_SW_MAX) + val->value.i = (val->value.i - 1) / RTL8366RB_BDTH_UNIT; + else + val->value.i = RTL8366RB_BDTH_REG_DEFAULT; + + return rtl8366_smi_rmwr(smi, RTL8366RB_EB_REG(val->port_vlan), + RTL8366RB_EB_BDTH_MASK, val->value.i ); + +} + +static int rtl8366rb_sw_get_port_rate_out(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366RB_EB_REG(val->port_vlan), &data); + data &= RTL8366RB_EB_BDTH_MASK; + if (data < RTL8366RB_EB_BDTH_MASK) + data += 1; + + val->value.i = (int)data * RTL8366RB_BDTH_UNIT; + + return 0; +} + +static int rtl8366rb_sw_set_qos_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_QOS_MASK; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_SGCR, RTL8366RB_QOS_MASK, data); +} + +static int rtl8366rb_sw_get_qos_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_SGCR, &data); + if (data & RTL8366RB_QOS_MASK) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_RX; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_RX, data); +} + +static int rtl8366rb_sw_get_mirror_rx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_RX) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_TX; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_TX, data); +} + +static int rtl8366rb_sw_get_mirror_tx_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_TX) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_monitor_isolation_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_ISO; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_ISO, data); +} + +static int rtl8366rb_sw_get_monitor_isolation_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_ISO) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_pause_frames_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + if (val->value.i) + data = RTL8366RB_PMCR_MIRROR_SPC; + else + data = 0; + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MIRROR_SPC, data); +} + +static int rtl8366rb_sw_get_mirror_pause_frames_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + if (data & RTL8366RB_PMCR_MIRROR_SPC) + val->value.i = 1; + else + val->value.i = 0; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + data = RTL8366RB_PMCR_MONITOR_PORT(val->value.i); + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_MONITOR_PORT_MASK, data); +} + +static int rtl8366rb_sw_get_mirror_monitor_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + val->value.i = (data & RTL8366RB_PMCR_MONITOR_PORT_MASK) >> 4; + + return 0; +} + +static int rtl8366rb_sw_set_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + data = RTL8366RB_PMCR_SOURCE_PORT(val->value.i); + + return rtl8366_smi_rmwr(smi, RTL8366RB_PMCR, RTL8366RB_PMCR_SOURCE_PORT_MASK, data); +} + +static int rtl8366rb_sw_get_mirror_source_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366RB_PMCR, &data); + val->value.i = data & RTL8366RB_PMCR_SOURCE_PORT_MASK; + + return 0; +} + +static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366RB_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366RB_MIB_CTRL_REG, 0, + RTL8366RB_MIB_CTRL_PORT_RESET(val->port_vlan)); +} + +static int rtl8366rb_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8366RB_MIB_TXB_ID, RTL8366RB_MIB_RXB_ID)); +} + +static struct switch_attr rtl8366rb_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_learning", + .description = "Enable learning, enable aging", + .set = rtl8366rb_sw_set_learning_enable, + .get = rtl8366rb_sw_get_learning_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8366rb_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "blinkrate", + .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," + " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", + .set = rtl8366rb_sw_set_blinkrate, + .get = rtl8366rb_sw_get_blinkrate, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_qos", + .description = "Enable QOS", + .set = rtl8366rb_sw_set_qos_enable, + .get = rtl8366rb_sw_get_qos_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_rx", + .description = "Enable mirroring of RX packets", + .set = rtl8366rb_sw_set_mirror_rx_enable, + .get = rtl8366rb_sw_get_mirror_rx_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_tx", + .description = "Enable mirroring of TX packets", + .set = rtl8366rb_sw_set_mirror_tx_enable, + .get = rtl8366rb_sw_get_mirror_tx_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_monitor_isolation", + .description = "Enable isolation of monitor port (TX packets will be dropped)", + .set = rtl8366rb_sw_set_monitor_isolation_enable, + .get = rtl8366rb_sw_get_monitor_isolation_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_mirror_pause_frames", + .description = "Enable mirroring of RX pause frames", + .set = rtl8366rb_sw_set_mirror_pause_frames_enable, + .get = rtl8366rb_sw_get_mirror_pause_frames_enable, + .max = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "mirror_monitor_port", + .description = "Mirror monitor port", + .set = rtl8366rb_sw_set_mirror_monitor_port, + .get = rtl8366rb_sw_get_mirror_monitor_port, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "mirror_source_port", + .description = "Mirror source port", + .set = rtl8366rb_sw_set_mirror_source_port, + .get = rtl8366rb_sw_get_mirror_source_port, + .max = 5 + }, +}; + +static struct switch_attr rtl8366rb_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8366rb_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, { + .type = SWITCH_TYPE_INT, + .name = "led", + .description = "Get/Set port group (0 - 3) led mode (0 - 15)", + .max = 15, + .set = rtl8366rb_sw_set_port_led, + .get = rtl8366rb_sw_get_port_led, + }, { + .type = SWITCH_TYPE_INT, + .name = "disable", + .description = "Get/Set port state (enabled or disabled)", + .max = 1, + .set = rtl8366rb_sw_set_port_disable, + .get = rtl8366rb_sw_get_port_disable, + }, { + .type = SWITCH_TYPE_INT, + .name = "rate_in", + .description = "Get/Set port ingress (incoming) bandwidth limit in kbps", + .max = RTL8366RB_BDTH_SW_MAX, + .set = rtl8366rb_sw_set_port_rate_in, + .get = rtl8366rb_sw_get_port_rate_in, + }, { + .type = SWITCH_TYPE_INT, + .name = "rate_out", + .description = "Get/Set port egress (outgoing) bandwidth limit in kbps", + .max = RTL8366RB_BDTH_SW_MAX, + .set = rtl8366rb_sw_set_port_rate_out, + .get = rtl8366rb_sw_get_port_rate_out, + }, +}; + +static struct switch_attr rtl8366rb_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8366RB_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8366_ops = { + .attr_global = { + .attr = rtl8366rb_globals, + .n_attr = ARRAY_SIZE(rtl8366rb_globals), + }, + .attr_port = { + .attr = rtl8366rb_port, + .n_attr = ARRAY_SIZE(rtl8366rb_port), + }, + .attr_vlan = { + .attr = rtl8366rb_vlan, + .n_attr = ARRAY_SIZE(rtl8366rb_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8366rb_sw_get_port_link, + .get_port_stats = rtl8366rb_sw_get_port_stats, +}; + +static int rtl8366rb_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8366RB"; + dev->cpu_port = RTL8366RB_PORT_NUM_CPU; + dev->ports = RTL8366RB_NUM_PORTS; + dev->vlans = RTL8366RB_NUM_VIDS; + dev->ops = &rtl8366_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8366rb_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8366rb_read_phy_reg(smi, addr, 0, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8366rb_write_phy_reg(smi, addr, 0, reg, val); + /* flush write */ + (void) rtl8366rb_read_phy_reg(smi, addr, 0, reg, &t); + + return err; +} + +static int rtl8366rb_detect(struct rtl8366_smi *smi) +{ + u32 chip_id = 0; + u32 chip_ver = 0; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(smi->parent, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366RB_CHIP_ID_8366: + break; + default: + dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8366RB_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%04x ver. %u chip found\n", + chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8366rb_smi_ops = { + .detect = rtl8366rb_detect, + .reset_chip = rtl8366rb_reset_chip, + .setup = rtl8366rb_setup, + + .mii_read = rtl8366rb_mii_read, + .mii_write = rtl8366rb_mii_write, + + .get_vlan_mc = rtl8366rb_get_vlan_mc, + .set_vlan_mc = rtl8366rb_set_vlan_mc, + .get_vlan_4k = rtl8366rb_get_vlan_4k, + .set_vlan_4k = rtl8366rb_set_vlan_4k, + .get_mc_index = rtl8366rb_get_mc_index, + .set_mc_index = rtl8366rb_set_mc_index, + .get_mib_counter = rtl8366rb_get_mib_counter, + .is_vlan_valid = rtl8366rb_is_vlan_valid, + .enable_vlan = rtl8366rb_enable_vlan, + .enable_vlan4k = rtl8366rb_enable_vlan4k, + .enable_port = rtl8366rb_enable_port, +}; + +static int rtl8366rb_probe(struct platform_device *pdev) +{ + static int rtl8366_smi_version_printed; + struct rtl8366_smi *smi; + int err; + + if (!rtl8366_smi_version_printed++) + printk(KERN_NOTICE RTL8366RB_DRIVER_DESC + " version " RTL8366RB_DRIVER_VER"\n"); + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 10; + smi->cmd_read = 0xa9; + smi->cmd_write = 0xa8; + smi->ops = &rtl8366rb_smi_ops; + smi->cpu_port = RTL8366RB_PORT_NUM_CPU; + smi->num_ports = RTL8366RB_NUM_PORTS; + smi->num_vlan_mc = RTL8366RB_NUM_VLANS; + smi->mib_counters = rtl8366rb_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8366rb_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8366rb_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8366rb_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8366rb_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8366rb_match[] = { + { .compatible = "realtek,rtl8366rb" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8366rb_match); +#endif + +static struct platform_driver rtl8366rb_driver = { + .driver = { + .name = RTL8366RB_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtl8366rb_match), + }, + .probe = rtl8366rb_probe, + .remove = rtl8366rb_remove, +}; + +static int __init rtl8366rb_module_init(void) +{ + return platform_driver_register(&rtl8366rb_driver); +} +module_init(rtl8366rb_module_init); + +static void __exit rtl8366rb_module_exit(void) +{ + platform_driver_unregister(&rtl8366rb_driver); +} +module_exit(rtl8366rb_module_exit); + +MODULE_DESCRIPTION(RTL8366RB_DRIVER_DESC); +MODULE_VERSION(RTL8366RB_DRIVER_VER); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Antti Seppälä "); +MODULE_AUTHOR("Roman Yeryomin "); +MODULE_AUTHOR("Colin Leitner "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME); diff --git a/ipq806x/files-5.4/drivers/net/phy/rtl8366s.c b/ipq806x/files-5.4/drivers/net/phy/rtl8366s.c new file mode 100644 index 0000000..8c74677 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/rtl8366s.c @@ -0,0 +1,1320 @@ +/* + * Platform driver for the Realtek RTL8366S ethernet switch + * + * Copyright (C) 2009-2010 Gabor Juhos + * Copyright (C) 2010 Antti Seppälä + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8366S_DRIVER_DESC "Realtek RTL8366S ethernet switch driver" +#define RTL8366S_DRIVER_VER "0.2.2" + +#define RTL8366S_PHY_NO_MAX 4 +#define RTL8366S_PHY_PAGE_MAX 7 +#define RTL8366S_PHY_ADDR_MAX 31 + +/* Switch Global Configuration register */ +#define RTL8366S_SGCR 0x0000 +#define RTL8366S_SGCR_EN_BC_STORM_CTRL BIT(0) +#define RTL8366S_SGCR_MAX_LENGTH(_x) (_x << 4) +#define RTL8366S_SGCR_MAX_LENGTH_MASK RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_MAX_LENGTH_1522 RTL8366S_SGCR_MAX_LENGTH(0x0) +#define RTL8366S_SGCR_MAX_LENGTH_1536 RTL8366S_SGCR_MAX_LENGTH(0x1) +#define RTL8366S_SGCR_MAX_LENGTH_1552 RTL8366S_SGCR_MAX_LENGTH(0x2) +#define RTL8366S_SGCR_MAX_LENGTH_16000 RTL8366S_SGCR_MAX_LENGTH(0x3) +#define RTL8366S_SGCR_EN_VLAN BIT(13) + +/* Port Enable Control register */ +#define RTL8366S_PECR 0x0001 + +/* Green Ethernet Feature (based on GPL_BELKIN_F5D8235-4_v1000 v1.01.24) */ +#define RTL8366S_GREEN_ETHERNET_CTRL_REG 0x000a +#define RTL8366S_GREEN_ETHERNET_CTRL_MASK 0x0018 +#define RTL8366S_GREEN_ETHERNET_TX_BIT (1 << 3) +#define RTL8366S_GREEN_ETHERNET_RX_BIT (1 << 4) + +/* Switch Security Control registers */ +#define RTL8366S_SSCR0 0x0002 +#define RTL8366S_SSCR1 0x0003 +#define RTL8366S_SSCR2 0x0004 +#define RTL8366S_SSCR2_DROP_UNKNOWN_DA BIT(0) + +#define RTL8366S_RESET_CTRL_REG 0x0100 +#define RTL8366S_CHIP_CTRL_RESET_HW 1 +#define RTL8366S_CHIP_CTRL_RESET_SW (1 << 1) + +#define RTL8366S_CHIP_VERSION_CTRL_REG 0x0104 +#define RTL8366S_CHIP_VERSION_MASK 0xf +#define RTL8366S_CHIP_ID_REG 0x0105 +#define RTL8366S_CHIP_ID_8366 0x8366 + +/* PHY registers control */ +#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 +#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 + +#define RTL8366S_PHY_CTRL_READ 1 +#define RTL8366S_PHY_CTRL_WRITE 0 + +#define RTL8366S_PHY_REG_MASK 0x1f +#define RTL8366S_PHY_PAGE_OFFSET 5 +#define RTL8366S_PHY_PAGE_MASK (0x7 << 5) +#define RTL8366S_PHY_NO_OFFSET 9 +#define RTL8366S_PHY_NO_MASK (0x1f << 9) + +/* Green Ethernet Feature for PHY ports */ +#define RTL8366S_PHY_POWER_SAVING_CTRL_REG 12 +#define RTL8366S_PHY_POWER_SAVING_MASK 0x1000 + +/* LED control registers */ +#define RTL8366S_LED_BLINKRATE_REG 0x0420 +#define RTL8366S_LED_BLINKRATE_BIT 0 +#define RTL8366S_LED_BLINKRATE_MASK 0x0007 + +#define RTL8366S_LED_CTRL_REG 0x0421 +#define RTL8366S_LED_0_1_CTRL_REG 0x0422 +#define RTL8366S_LED_2_3_CTRL_REG 0x0423 + +#define RTL8366S_MIB_COUNT 33 +#define RTL8366S_GLOBAL_MIB_COUNT 1 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0040 +#define RTL8366S_MIB_COUNTER_BASE 0x1000 +#define RTL8366S_MIB_COUNTER_PORT_OFFSET2 0x0008 +#define RTL8366S_MIB_COUNTER_BASE2 0x1180 +#define RTL8366S_MIB_CTRL_REG 0x11F0 +#define RTL8366S_MIB_CTRL_USER_MASK 0x01FF +#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 +#define RTL8366S_MIB_CTRL_RESET_MASK 0x0002 + +#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 +#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 +#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC + + +#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 +#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ + (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) +#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf +#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) + + +#define RTL8366S_VLAN_TABLE_READ_BASE 0x018B +#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 + +#define RTL8366S_VLAN_TB_CTRL_REG 0x010F + +#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 +#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 +#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 + +#define RTL8366S_VLAN_MC_BASE(_x) (0x0016 + (_x) * 2) + +#define RTL8366S_VLAN_MEMBERINGRESS_REG 0x0379 + +#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 +#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 +#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 +#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 +#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 +#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 + + +#define RTL8366S_PORT_NUM_CPU 5 +#define RTL8366S_NUM_PORTS 6 +#define RTL8366S_NUM_VLANS 16 +#define RTL8366S_NUM_LEDGROUPS 4 +#define RTL8366S_NUM_VIDS 4096 +#define RTL8366S_PRIORITYMAX 7 +#define RTL8366S_FIDMAX 7 + + +#define RTL8366S_PORT_1 (1 << 0) /* In userspace port 0 */ +#define RTL8366S_PORT_2 (1 << 1) /* In userspace port 1 */ +#define RTL8366S_PORT_3 (1 << 2) /* In userspace port 2 */ +#define RTL8366S_PORT_4 (1 << 3) /* In userspace port 3 */ + +#define RTL8366S_PORT_UNKNOWN (1 << 4) /* No known connection */ +#define RTL8366S_PORT_CPU (1 << 5) /* CPU port */ + +#define RTL8366S_PORT_ALL (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_UNKNOWN | \ + RTL8366S_PORT_CPU) + +#define RTL8366S_PORT_ALL_BUT_CPU (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4 | \ + RTL8366S_PORT_UNKNOWN) + +#define RTL8366S_PORT_ALL_EXTERNAL (RTL8366S_PORT_1 | \ + RTL8366S_PORT_2 | \ + RTL8366S_PORT_3 | \ + RTL8366S_PORT_4) + +#define RTL8366S_PORT_ALL_INTERNAL (RTL8366S_PORT_UNKNOWN | \ + RTL8366S_PORT_CPU) + +#define RTL8366S_VLAN_VID_MASK 0xfff +#define RTL8366S_VLAN_PRIORITY_SHIFT 12 +#define RTL8366S_VLAN_PRIORITY_MASK 0x7 +#define RTL8366S_VLAN_MEMBER_MASK 0x3f +#define RTL8366S_VLAN_UNTAG_SHIFT 6 +#define RTL8366S_VLAN_UNTAG_MASK 0x3f +#define RTL8366S_VLAN_FID_SHIFT 12 +#define RTL8366S_VLAN_FID_MASK 0x7 + +#define RTL8366S_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8366S_MIB_TXB_ID 20 /* IfOutOctets */ + +static struct rtl8366_mib_counter rtl8366s_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 4, "EtherStatsOctets" }, + { 0, 8, 2, "EtherStatsUnderSizePkts" }, + { 0, 10, 2, "EtherFragments" }, + { 0, 12, 2, "EtherStatsPkts64Octets" }, + { 0, 14, 2, "EtherStatsPkts65to127Octets" }, + { 0, 16, 2, "EtherStatsPkts128to255Octets" }, + { 0, 18, 2, "EtherStatsPkts256to511Octets" }, + { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 24, 2, "EtherOversizeStats" }, + { 0, 26, 2, "EtherStatsJabbers" }, + { 0, 28, 2, "IfInUcastPkts" }, + { 0, 30, 2, "EtherStatsMulticastPkts" }, + { 0, 32, 2, "EtherStatsBroadcastPkts" }, + { 0, 34, 2, "EtherStatsDropEvents" }, + { 0, 36, 2, "Dot3StatsFCSErrors" }, + { 0, 38, 2, "Dot3StatsSymbolErrors" }, + { 0, 40, 2, "Dot3InPauseFrames" }, + { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 44, 4, "IfOutOctets" }, + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + + /* + * The following counters are accessible at a different + * base address. + */ + { 1, 0, 2, "Dot1dTpPortInDiscards" }, + { 1, 2, 2, "IfOutUcastPkts" }, + { 1, 4, 2, "IfOutMulticastPkts" }, + { 1, 6, 2, "IfOutBroadcastPkts" }, +}; + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static int rtl8366s_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + u32 data; + + rtl8366_smi_write_reg_noack(smi, RTL8366S_RESET_CTRL_REG, + RTL8366S_CHIP_CTRL_RESET_HW); + do { + msleep(1); + if (rtl8366_smi_read_reg(smi, RTL8366S_RESET_CTRL_REG, &data)) + return -EIO; + + if (!(data & RTL8366S_CHIP_CTRL_RESET_HW)) + break; + } while (--timeout); + + if (!timeout) { + printk("Timeout waiting for the switch to reset\n"); + return -EIO; + } + + return 0; +} + +static int rtl8366s_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 *data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_READ); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, 0); + if (ret) + return ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366s_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_no, u32 page, u32 addr, u32 data) +{ + u32 reg; + int ret; + + if (phy_no > RTL8366S_PHY_NO_MAX) + return -EINVAL; + + if (page > RTL8366S_PHY_PAGE_MAX) + return -EINVAL; + + if (addr > RTL8366S_PHY_ADDR_MAX) + return -EINVAL; + + ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, + RTL8366S_PHY_CTRL_WRITE); + if (ret) + return ret; + + reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | + ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | + (addr & RTL8366S_PHY_REG_MASK); + + ret = rtl8366_smi_write_reg(smi, reg, data); + if (ret) + return ret; + + return 0; +} + +static int rtl8366s_set_green_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + u32 phyData; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + err = rtl8366s_read_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData); + if (err) + return err; + + if (enable) + phyData |= RTL8366S_PHY_POWER_SAVING_MASK; + else + phyData &= ~RTL8366S_PHY_POWER_SAVING_MASK; + + err = rtl8366s_write_phy_reg(smi, port, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, phyData); + if (err) + return err; + + return 0; +} + +static int rtl8366s_set_green(struct rtl8366_smi *smi, int enable) +{ + int err; + unsigned i; + u32 data = 0; + + if (!enable) { + for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) { + rtl8366s_set_green_port(smi, i, 0); + } + } + + if (enable) + data = (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT); + + REG_RMW(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, RTL8366S_GREEN_ETHERNET_CTRL_MASK, data); + + return 0; +} + +static int rtl8366s_setup(struct rtl8366_smi *smi) +{ + struct rtl8366_platform_data *pdata; + int err; + unsigned i; +#ifdef CONFIG_OF + struct device_node *np; + unsigned num_initvals; + const __be32 *paddr; +#endif + + pdata = smi->parent->platform_data; + if (pdata && pdata->num_initvals && pdata->initvals) { + dev_info(smi->parent, "applying initvals\n"); + for (i = 0; i < pdata->num_initvals; i++) + REG_WR(smi, pdata->initvals[i].reg, + pdata->initvals[i].val); + } + +#ifdef CONFIG_OF + np = smi->parent->of_node; + + paddr = of_get_property(np, "realtek,initvals", &num_initvals); + if (paddr) { + dev_info(smi->parent, "applying initvals from DTS\n"); + + if (num_initvals < (2 * sizeof(*paddr))) + return -EINVAL; + + num_initvals /= sizeof(*paddr); + + for (i = 0; i < num_initvals - 1; i += 2) { + u32 reg = be32_to_cpup(paddr + i); + u32 val = be32_to_cpup(paddr + i + 1); + + REG_WR(smi, reg, val); + } + } + + if (of_property_read_bool(np, "realtek,green-ethernet-features")) { + dev_info(smi->parent, "activating Green Ethernet features\n"); + + err = rtl8366s_set_green(smi, 1); + if (err) + return err; + + for (i = 0; i <= RTL8366S_PHY_NO_MAX; i++) { + err = rtl8366s_set_green_port(smi, i, 1); + if (err) + return err; + } + } +#endif + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8366S_SGCR, RTL8366S_SGCR_MAX_LENGTH_MASK, + RTL8366S_SGCR_MAX_LENGTH_1536); + + /* enable learning for all ports */ + REG_WR(smi, RTL8366S_SSCR0, 0); + + /* enable auto ageing for all ports */ + REG_WR(smi, RTL8366S_SSCR1, 0); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8366S_VLAN_MEMBERINGRESS_REG, RTL8366S_PORT_ALL); + + /* don't drop packets whose DA has not been learned */ + REG_RMW(smi, RTL8366S_SSCR2, RTL8366S_SSCR2_DROP_UNKNOWN_DA, 0); + + return 0; +} + +static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8366S_NUM_PORTS || counter >= RTL8366S_MIB_COUNT) + return -EINVAL; + + switch (rtl8366s_mib_counters[counter].base) { + case 0: + addr = RTL8366S_MIB_COUNTER_BASE + + RTL8366S_MIB_COUNTER_PORT_OFFSET * port; + break; + + case 1: + addr = RTL8366S_MIB_COUNTER_BASE2 + + RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port; + break; + + default: + return -EINVAL; + } + + addr += rtl8366s_mib_counters[counter].offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + data = 0; /* writing data will be discard by ASIC */ + err = rtl8366_smi_write_reg(smi, addr, data); + if (err) + return err; + + /* read MIB control register */ + err = rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); + if (err) + return err; + + if (data & RTL8366S_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8366S_MIB_CTRL_RESET_MASK) + return -EIO; + + mibvalue = 0; + for (i = rtl8366s_mib_counters[counter].length; i > 0; i--) { + err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); + if (err) + return err; + + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8366s_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8366S_NUM_VIDS) + return -EINVAL; + + /* write VID */ + err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, + vid & RTL8366S_VLAN_VID_MASK); + if (err) + return err; + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_READ_CTRL); + if (err) + return err; + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366S_VLAN_TABLE_READ_BASE + i, + &data[i]); + if (err) + return err; + } + + vlan4k->vid = vid; + vlan4k->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlan4k->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlan4k->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[2]; + int err; + int i; + + if (vlan4k->vid >= RTL8366S_NUM_VIDS || + vlan4k->member > RTL8366S_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8366S_VLAN_UNTAG_MASK || + vlan4k->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = vlan4k->vid & RTL8366S_VLAN_VID_MASK; + data[1] = (vlan4k->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlan4k->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlan4k->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366S_VLAN_TABLE_WRITE_BASE + i, + data[i]); + if (err) + return err; + } + + /* write table access control word */ + err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, + RTL8366S_TABLE_VLAN_WRITE_CTRL); + + return err; +} + +static int rtl8366s_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_read_reg(smi, + RTL8366S_VLAN_MC_BASE(index) + i, + &data[i]); + if (err) + return err; + } + + vlanmc->vid = data[0] & RTL8366S_VLAN_VID_MASK; + vlanmc->priority = (data[0] >> RTL8366S_VLAN_PRIORITY_SHIFT) & + RTL8366S_VLAN_PRIORITY_MASK; + vlanmc->untag = (data[1] >> RTL8366S_VLAN_UNTAG_SHIFT) & + RTL8366S_VLAN_UNTAG_MASK; + vlanmc->member = data[1] & RTL8366S_VLAN_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8366S_VLAN_FID_SHIFT) & + RTL8366S_VLAN_FID_MASK; + + return 0; +} + +static int rtl8366s_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[2]; + int err; + int i; + + if (index >= RTL8366S_NUM_VLANS || + vlanmc->vid >= RTL8366S_NUM_VIDS || + vlanmc->priority > RTL8366S_PRIORITYMAX || + vlanmc->member > RTL8366S_VLAN_MEMBER_MASK || + vlanmc->untag > RTL8366S_VLAN_UNTAG_MASK || + vlanmc->fid > RTL8366S_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->vid & RTL8366S_VLAN_VID_MASK) | + ((vlanmc->priority & RTL8366S_VLAN_PRIORITY_MASK) << + RTL8366S_VLAN_PRIORITY_SHIFT); + data[1] = (vlanmc->member & RTL8366S_VLAN_MEMBER_MASK) | + ((vlanmc->untag & RTL8366S_VLAN_UNTAG_MASK) << + RTL8366S_VLAN_UNTAG_SHIFT) | + ((vlanmc->fid & RTL8366S_VLAN_FID_MASK) << + RTL8366S_VLAN_FID_SHIFT); + + for (i = 0; i < 2; i++) { + err = rtl8366_smi_write_reg(smi, + RTL8366S_VLAN_MC_BASE(index) + i, + data[i]); + if (err) + return err; + } + + return 0; +} + +static int rtl8366s_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + &data); + if (err) + return err; + + *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & + RTL8366S_PORT_VLAN_CTRL_MASK; + + return 0; +} + +static int rtl8366s_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8366S_NUM_PORTS || index >= RTL8366S_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), + RTL8366S_PORT_VLAN_CTRL_MASK << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366S_PORT_VLAN_CTRL_MASK) << + RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); +} + +static int rtl8366s_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, RTL8366S_SGCR_EN_VLAN, + (enable) ? RTL8366S_SGCR_EN_VLAN : 0); +} + +static int rtl8366s_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_VLAN_TB_CTRL_REG, + 1, (enable) ? 1 : 0); +} + +static int rtl8366s_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8366S_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8366S_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8366s_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8366S_PECR, (1 << port), + (enable) ? 0 : (1 << port)); +} + +static int rtl8366s_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2)); +} + +static int rtl8366s_sw_get_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366S_LED_BLINKRATE_REG, &data); + + val->value.i = (data & (RTL8366S_LED_BLINKRATE_MASK)); + + return 0; +} + +static int rtl8366s_sw_set_blinkrate(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->value.i >= 6) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8366S_LED_BLINKRATE_REG, + RTL8366S_LED_BLINKRATE_MASK, + val->value.i); +} + +static int rtl8366s_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8366S_SGCR, &data); + + val->value.i = ((data & (RTL8366S_SGCR_MAX_LENGTH_MASK)) >> 4); + + return 0; +} + +static int rtl8366s_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + char length_code; + + switch (val->value.i) { + case 0: + length_code = RTL8366S_SGCR_MAX_LENGTH_1522; + break; + case 1: + length_code = RTL8366S_SGCR_MAX_LENGTH_1536; + break; + case 2: + length_code = RTL8366S_SGCR_MAX_LENGTH_1552; + break; + case 3: + length_code = RTL8366S_SGCR_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8366S_SGCR, + RTL8366S_SGCR_MAX_LENGTH_MASK, + length_code); +} + +static int rtl8366s_sw_get_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi,RTL8366S_SSCR0, &data); + val->value.i = !data; + + return 0; +} + + +static int rtl8366s_sw_set_learning_enable(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 portmask = 0; + int err = 0; + + if (!val->value.i) + portmask = RTL8366S_PORT_ALL; + + /* set learning for all ports */ + REG_WR(smi, RTL8366S_SSCR0, portmask); + + /* set auto ageing for all ports */ + REG_WR(smi, RTL8366S_SSCR1, portmask); + + return 0; +} + +static int rtl8366s_sw_get_green(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + int err; + + err = rtl8366_smi_read_reg(smi, RTL8366S_GREEN_ETHERNET_CTRL_REG, &data); + if (err) + return err; + + val->value.i = ((data & (RTL8366S_GREEN_ETHERNET_TX_BIT | RTL8366S_GREEN_ETHERNET_RX_BIT)) != 0) ? 1 : 0; + + return 0; +} + +static int rtl8366s_sw_set_green(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366s_set_green(smi, val->value.i); +} + +static int rtl8366s_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8366S_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + (port / 2), + &data); + + if (port % 2) + data = data >> 8; + + link->link = !!(data & RTL8366S_PORT_STATUS_LINK_MASK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8366S_PORT_STATUS_DUPLEX_MASK); + link->rx_flow = !!(data & RTL8366S_PORT_STATUS_RXPAUSE_MASK); + link->tx_flow = !!(data & RTL8366S_PORT_STATUS_TXPAUSE_MASK); + link->aneg = !!(data & RTL8366S_PORT_STATUS_AN_MASK); + + speed = (data & RTL8366S_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8366s_sw_set_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + u32 mask; + u32 reg; + + if (val->port_vlan >= RTL8366S_NUM_PORTS || + (1 << val->port_vlan) == RTL8366S_PORT_UNKNOWN) + return -EINVAL; + + if (val->port_vlan == RTL8366S_PORT_NUM_CPU) { + reg = RTL8366S_LED_BLINKRATE_REG; + mask = 0xF << 4; + data = val->value.i << 4; + } else { + reg = RTL8366S_LED_CTRL_REG; + mask = 0xF << (val->port_vlan * 4), + data = val->value.i << (val->port_vlan * 4); + } + + return rtl8366_smi_rmwr(smi, reg, mask, data); +} + +static int rtl8366s_sw_get_port_led(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + + if (val->port_vlan >= RTL8366S_NUM_LEDGROUPS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8366S_LED_CTRL_REG, &data); + val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; + + return 0; +} + +static int rtl8366s_sw_get_green_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + u32 phyData; + + if (val->port_vlan >= RTL8366S_NUM_PORTS) + return -EINVAL; + + err = rtl8366s_read_phy_reg(smi, val->port_vlan, 0, RTL8366S_PHY_POWER_SAVING_CTRL_REG, &phyData); + if (err) + return err; + + val->value.i = ((phyData & RTL8366S_PHY_POWER_SAVING_MASK) != 0) ? 1 : 0; + + return 0; +} + +static int rtl8366s_sw_set_green_port(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + return rtl8366s_set_green_port(smi, val->port_vlan, val->value.i); +} + +static int rtl8366s_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + if (val->port_vlan >= RTL8366S_NUM_PORTS) + return -EINVAL; + + + return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, + 0, (1 << (val->port_vlan + 3))); +} + +static int rtl8366s_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8366S_MIB_TXB_ID, RTL8366S_MIB_RXB_ID)); +} + +static struct switch_attr rtl8366s_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_learning", + .description = "Enable learning, enable aging", + .set = rtl8366s_sw_set_learning_enable, + .get = rtl8366s_sw_get_learning_enable, + .max = 1, + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8366s_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "blinkrate", + .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," + " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", + .set = rtl8366s_sw_set_blinkrate, + .get = rtl8366s_sw_get_blinkrate, + .max = 5 + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + " (0 = 1522, 1 = 1536, 2 = 1552, 3 = 16000 (9216?))", + .set = rtl8366s_sw_set_max_length, + .get = rtl8366s_sw_get_max_length, + .max = 3, + }, { + .type = SWITCH_TYPE_INT, + .name = "green_mode", + .description = "Get/Set the router green feature", + .set = rtl8366s_sw_set_green, + .get = rtl8366s_sw_get_green, + .max = 1, + }, +}; + +static struct switch_attr rtl8366s_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8366s_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, { + .type = SWITCH_TYPE_INT, + .name = "led", + .description = "Get/Set port group (0 - 3) led mode (0 - 15)", + .max = 15, + .set = rtl8366s_sw_set_port_led, + .get = rtl8366s_sw_get_port_led, + }, { + .type = SWITCH_TYPE_INT, + .name = "green_port", + .description = "Get/Set port green feature (0 - 1)", + .max = 1, + .set = rtl8366s_sw_set_green_port, + .get = rtl8366s_sw_get_green_port, + }, +}; + +static struct switch_attr rtl8366s_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8366S_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8366_ops = { + .attr_global = { + .attr = rtl8366s_globals, + .n_attr = ARRAY_SIZE(rtl8366s_globals), + }, + .attr_port = { + .attr = rtl8366s_port, + .n_attr = ARRAY_SIZE(rtl8366s_port), + }, + .attr_vlan = { + .attr = rtl8366s_vlan, + .n_attr = ARRAY_SIZE(rtl8366s_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8366s_sw_get_port_link, + .get_port_stats = rtl8366s_sw_get_port_stats, +}; + +static int rtl8366s_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8366S"; + dev->cpu_port = RTL8366S_PORT_NUM_CPU; + dev->ports = RTL8366S_NUM_PORTS; + dev->vlans = RTL8366S_NUM_VIDS; + dev->ops = &rtl8366_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8366s_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8366s_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8366s_read_phy_reg(smi, addr, 0, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8366s_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8366s_write_phy_reg(smi, addr, 0, reg, val); + /* flush write */ + (void) rtl8366s_read_phy_reg(smi, addr, 0, reg, &t); + + return err; +} + +static int rtl8366s_detect(struct rtl8366_smi *smi) +{ + u32 chip_id = 0; + u32 chip_ver = 0; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id); + if (ret) { + dev_err(smi->parent, "unable to read chip id\n"); + return ret; + } + + switch (chip_id) { + case RTL8366S_CHIP_ID_8366: + break; + default: + dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG, + &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%04x ver. %u chip found\n", + chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8366s_smi_ops = { + .detect = rtl8366s_detect, + .reset_chip = rtl8366s_reset_chip, + .setup = rtl8366s_setup, + + .mii_read = rtl8366s_mii_read, + .mii_write = rtl8366s_mii_write, + + .get_vlan_mc = rtl8366s_get_vlan_mc, + .set_vlan_mc = rtl8366s_set_vlan_mc, + .get_vlan_4k = rtl8366s_get_vlan_4k, + .set_vlan_4k = rtl8366s_set_vlan_4k, + .get_mc_index = rtl8366s_get_mc_index, + .set_mc_index = rtl8366s_set_mc_index, + .get_mib_counter = rtl8366_get_mib_counter, + .is_vlan_valid = rtl8366s_is_vlan_valid, + .enable_vlan = rtl8366s_enable_vlan, + .enable_vlan4k = rtl8366s_enable_vlan4k, + .enable_port = rtl8366s_enable_port, +}; + +static int rtl8366s_probe(struct platform_device *pdev) +{ + static int rtl8366_smi_version_printed; + struct rtl8366_smi *smi; + int err; + + if (!rtl8366_smi_version_printed++) + printk(KERN_NOTICE RTL8366S_DRIVER_DESC + " version " RTL8366S_DRIVER_VER"\n"); + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 10; + smi->cmd_read = 0xa9; + smi->cmd_write = 0xa8; + smi->ops = &rtl8366s_smi_ops; + smi->cpu_port = RTL8366S_PORT_NUM_CPU; + smi->num_ports = RTL8366S_NUM_PORTS; + smi->num_vlan_mc = RTL8366S_NUM_VLANS; + smi->mib_counters = rtl8366s_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8366s_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8366s_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8366s_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8366s_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8366s_match[] = { + { .compatible = "realtek,rtl8366s" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8366s_match); +#endif + +static struct platform_driver rtl8366s_driver = { + .driver = { + .name = RTL8366S_DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8366s_match), +#endif + }, + .probe = rtl8366s_probe, + .remove = rtl8366s_remove, +}; + +static int __init rtl8366s_module_init(void) +{ + return platform_driver_register(&rtl8366s_driver); +} +module_init(rtl8366s_module_init); + +static void __exit rtl8366s_module_exit(void) +{ + platform_driver_unregister(&rtl8366s_driver); +} +module_exit(rtl8366s_module_exit); + +MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC); +MODULE_VERSION(RTL8366S_DRIVER_VER); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_AUTHOR("Antti Seppälä "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8366S_DRIVER_NAME); diff --git a/ipq806x/files-5.4/drivers/net/phy/rtl8367.c b/ipq806x/files-5.4/drivers/net/phy/rtl8367.c new file mode 100644 index 0000000..7f0569d --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/rtl8367.c @@ -0,0 +1,1846 @@ +/* + * Platform driver for the Realtek RTL8367R/M ethernet switches + * + * Copyright (C) 2011 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8367_RESET_DELAY 1000 /* msecs*/ + +#define RTL8367_PHY_ADDR_MAX 8 +#define RTL8367_PHY_REG_MAX 31 + +#define RTL8367_VID_MASK 0xffff +#define RTL8367_FID_MASK 0xfff +#define RTL8367_UNTAG_MASK 0xffff +#define RTL8367_MEMBER_MASK 0xffff + +#define RTL8367_PORT_CFG_REG(_p) (0x000e + 0x20 * (_p)) +#define RTL8367_PORT_CFG_EGRESS_MODE_SHIFT 4 +#define RTL8367_PORT_CFG_EGRESS_MODE_MASK 0x3 +#define RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL 0 +#define RTL8367_PORT_CFG_EGRESS_MODE_KEEP 1 +#define RTL8367_PORT_CFG_EGRESS_MODE_PRI 2 +#define RTL8367_PORT_CFG_EGRESS_MODE_REAL 3 + +#define RTL8367_BYPASS_LINE_RATE_REG 0x03f7 + +#define RTL8367_TA_CTRL_REG 0x0500 +#define RTL8367_TA_CTRL_STATUS BIT(12) +#define RTL8367_TA_CTRL_METHOD BIT(5) +#define RTL8367_TA_CTRL_CMD_SHIFT 4 +#define RTL8367_TA_CTRL_CMD_READ 0 +#define RTL8367_TA_CTRL_CMD_WRITE 1 +#define RTL8367_TA_CTRL_TABLE_SHIFT 0 +#define RTL8367_TA_CTRL_TABLE_ACLRULE 1 +#define RTL8367_TA_CTRL_TABLE_ACLACT 2 +#define RTL8367_TA_CTRL_TABLE_CVLAN 3 +#define RTL8367_TA_CTRL_TABLE_L2 4 +#define RTL8367_TA_CTRL_CVLAN_READ \ + ((RTL8367_TA_CTRL_CMD_READ << RTL8367_TA_CTRL_CMD_SHIFT) | \ + RTL8367_TA_CTRL_TABLE_CVLAN) +#define RTL8367_TA_CTRL_CVLAN_WRITE \ + ((RTL8367_TA_CTRL_CMD_WRITE << RTL8367_TA_CTRL_CMD_SHIFT) | \ + RTL8367_TA_CTRL_TABLE_CVLAN) + +#define RTL8367_TA_ADDR_REG 0x0501 +#define RTL8367_TA_ADDR_MASK 0x3fff + +#define RTL8367_TA_DATA_REG(_x) (0x0503 + (_x)) +#define RTL8367_TA_VLAN_DATA_SIZE 4 +#define RTL8367_TA_VLAN_VID_MASK RTL8367_VID_MASK +#define RTL8367_TA_VLAN_MEMBER_SHIFT 0 +#define RTL8367_TA_VLAN_MEMBER_MASK RTL8367_MEMBER_MASK +#define RTL8367_TA_VLAN_FID_SHIFT 0 +#define RTL8367_TA_VLAN_FID_MASK RTL8367_FID_MASK +#define RTL8367_TA_VLAN_UNTAG1_SHIFT 14 +#define RTL8367_TA_VLAN_UNTAG1_MASK 0x3 +#define RTL8367_TA_VLAN_UNTAG2_SHIFT 0 +#define RTL8367_TA_VLAN_UNTAG2_MASK 0x3fff + +#define RTL8367_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) +#define RTL8367_VLAN_PVID_CTRL_MASK 0x1f +#define RTL8367_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) + +#define RTL8367_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) +#define RTL8367_VLAN_MC_DATA_SIZE 4 +#define RTL8367_VLAN_MC_MEMBER_SHIFT 0 +#define RTL8367_VLAN_MC_MEMBER_MASK RTL8367_MEMBER_MASK +#define RTL8367_VLAN_MC_FID_SHIFT 0 +#define RTL8367_VLAN_MC_FID_MASK RTL8367_FID_MASK +#define RTL8367_VLAN_MC_EVID_SHIFT 0 +#define RTL8367_VLAN_MC_EVID_MASK RTL8367_VID_MASK + +#define RTL8367_VLAN_CTRL_REG 0x07a8 +#define RTL8367_VLAN_CTRL_ENABLE BIT(0) + +#define RTL8367_VLAN_INGRESS_REG 0x07a9 + +#define RTL8367_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) + +#define RTL8367_MIB_COUNTER_REG(_x) (0x1000 + (_x)) + +#define RTL8367_MIB_ADDRESS_REG 0x1004 + +#define RTL8367_MIB_CTRL_REG(_x) (0x1005 + (_x)) +#define RTL8367_MIB_CTRL_GLOBAL_RESET_MASK BIT(11) +#define RTL8367_MIB_CTRL_QM_RESET_MASK BIT(10) +#define RTL8367_MIB_CTRL_PORT_RESET_MASK(_p) BIT(2 + (_p)) +#define RTL8367_MIB_CTRL_RESET_MASK BIT(1) +#define RTL8367_MIB_CTRL_BUSY_MASK BIT(0) + +#define RTL8367_MIB_COUNT 36 +#define RTL8367_MIB_COUNTER_PORT_OFFSET 0x0050 + +#define RTL8367_SWC0_REG 0x1200 +#define RTL8367_SWC0_MAX_LENGTH_SHIFT 13 +#define RTL8367_SWC0_MAX_LENGTH(_x) ((_x) << 13) +#define RTL8367_SWC0_MAX_LENGTH_MASK RTL8367_SWC0_MAX_LENGTH(0x3) +#define RTL8367_SWC0_MAX_LENGTH_1522 RTL8367_SWC0_MAX_LENGTH(0) +#define RTL8367_SWC0_MAX_LENGTH_1536 RTL8367_SWC0_MAX_LENGTH(1) +#define RTL8367_SWC0_MAX_LENGTH_1552 RTL8367_SWC0_MAX_LENGTH(2) +#define RTL8367_SWC0_MAX_LENGTH_16000 RTL8367_SWC0_MAX_LENGTH(3) + +#define RTL8367_CHIP_NUMBER_REG 0x1300 + +#define RTL8367_CHIP_VER_REG 0x1301 +#define RTL8367_CHIP_VER_RLVID_SHIFT 12 +#define RTL8367_CHIP_VER_RLVID_MASK 0xf +#define RTL8367_CHIP_VER_MCID_SHIFT 8 +#define RTL8367_CHIP_VER_MCID_MASK 0xf +#define RTL8367_CHIP_VER_BOID_SHIFT 4 +#define RTL8367_CHIP_VER_BOID_MASK 0xf + +#define RTL8367_CHIP_MODE_REG 0x1302 +#define RTL8367_CHIP_MODE_MASK 0x7 + +#define RTL8367_CHIP_DEBUG0_REG 0x1303 +#define RTL8367_CHIP_DEBUG0_DUMMY0(_x) BIT(8 + (_x)) + +#define RTL8367_CHIP_DEBUG1_REG 0x1304 + +#define RTL8367_DIS_REG 0x1305 +#define RTL8367_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) +#define RTL8367_DIS_RGMII_SHIFT(_x) (4 * (_x)) +#define RTL8367_DIS_RGMII_MASK 0x7 + +#define RTL8367_EXT_RGMXF_REG(_x) (0x1306 + (_x)) +#define RTL8367_EXT_RGMXF_DUMMY0_SHIFT 5 +#define RTL8367_EXT_RGMXF_DUMMY0_MASK 0x7ff +#define RTL8367_EXT_RGMXF_TXDELAY_SHIFT 3 +#define RTL8367_EXT_RGMXF_TXDELAY_MASK 1 +#define RTL8367_EXT_RGMXF_RXDELAY_MASK 0x7 + +#define RTL8367_DI_FORCE_REG(_x) (0x1310 + (_x)) +#define RTL8367_DI_FORCE_MODE BIT(12) +#define RTL8367_DI_FORCE_NWAY BIT(7) +#define RTL8367_DI_FORCE_TXPAUSE BIT(6) +#define RTL8367_DI_FORCE_RXPAUSE BIT(5) +#define RTL8367_DI_FORCE_LINK BIT(4) +#define RTL8367_DI_FORCE_DUPLEX BIT(2) +#define RTL8367_DI_FORCE_SPEED_MASK 3 +#define RTL8367_DI_FORCE_SPEED_10 0 +#define RTL8367_DI_FORCE_SPEED_100 1 +#define RTL8367_DI_FORCE_SPEED_1000 2 + +#define RTL8367_MAC_FORCE_REG(_x) (0x1312 + (_x)) + +#define RTL8367_CHIP_RESET_REG 0x1322 +#define RTL8367_CHIP_RESET_SW BIT(1) +#define RTL8367_CHIP_RESET_HW BIT(0) + +#define RTL8367_PORT_STATUS_REG(_p) (0x1352 + (_p)) +#define RTL8367_PORT_STATUS_NWAY BIT(7) +#define RTL8367_PORT_STATUS_TXPAUSE BIT(6) +#define RTL8367_PORT_STATUS_RXPAUSE BIT(5) +#define RTL8367_PORT_STATUS_LINK BIT(4) +#define RTL8367_PORT_STATUS_DUPLEX BIT(2) +#define RTL8367_PORT_STATUS_SPEED_MASK 0x0003 +#define RTL8367_PORT_STATUS_SPEED_10 0 +#define RTL8367_PORT_STATUS_SPEED_100 1 +#define RTL8367_PORT_STATUS_SPEED_1000 2 + +#define RTL8367_RTL_NO_REG 0x13c0 +#define RTL8367_RTL_NO_8367R 0x3670 +#define RTL8367_RTL_NO_8367M 0x3671 + +#define RTL8367_RTL_VER_REG 0x13c1 +#define RTL8367_RTL_VER_MASK 0xf + +#define RTL8367_RTL_MAGIC_ID_REG 0x13c2 +#define RTL8367_RTL_MAGIC_ID_VAL 0x0249 + +#define RTL8367_LED_SYS_CONFIG_REG 0x1b00 +#define RTL8367_LED_MODE_REG 0x1b02 +#define RTL8367_LED_MODE_RATE_M 0x7 +#define RTL8367_LED_MODE_RATE_S 1 + +#define RTL8367_LED_CONFIG_REG 0x1b03 +#define RTL8367_LED_CONFIG_DATA_S 12 +#define RTL8367_LED_CONFIG_DATA_M 0x3 +#define RTL8367_LED_CONFIG_SEL BIT(14) +#define RTL8367_LED_CONFIG_LED_CFG_M 0xf + +#define RTL8367_PARA_LED_IO_EN1_REG 0x1b24 +#define RTL8367_PARA_LED_IO_EN2_REG 0x1b25 +#define RTL8367_PARA_LED_IO_EN_PMASK 0xff + +#define RTL8367_IA_CTRL_REG 0x1f00 +#define RTL8367_IA_CTRL_RW(_x) ((_x) << 1) +#define RTL8367_IA_CTRL_RW_READ RTL8367_IA_CTRL_RW(0) +#define RTL8367_IA_CTRL_RW_WRITE RTL8367_IA_CTRL_RW(1) +#define RTL8367_IA_CTRL_CMD_MASK BIT(0) + +#define RTL8367_IA_STATUS_REG 0x1f01 +#define RTL8367_IA_STATUS_PHY_BUSY BIT(2) +#define RTL8367_IA_STATUS_SDS_BUSY BIT(1) +#define RTL8367_IA_STATUS_MDX_BUSY BIT(0) + +#define RTL8367_IA_ADDRESS_REG 0x1f02 + +#define RTL8367_IA_WRITE_DATA_REG 0x1f03 +#define RTL8367_IA_READ_DATA_REG 0x1f04 + +#define RTL8367_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) + +#define RTL8367_CPU_PORT_NUM 9 +#define RTL8367_NUM_PORTS 10 +#define RTL8367_NUM_VLANS 32 +#define RTL8367_NUM_LEDGROUPS 4 +#define RTL8367_NUM_VIDS 4096 +#define RTL8367_PRIORITYMAX 7 +#define RTL8367_FIDMAX 7 + +#define RTL8367_PORT_0 BIT(0) +#define RTL8367_PORT_1 BIT(1) +#define RTL8367_PORT_2 BIT(2) +#define RTL8367_PORT_3 BIT(3) +#define RTL8367_PORT_4 BIT(4) +#define RTL8367_PORT_5 BIT(5) +#define RTL8367_PORT_6 BIT(6) +#define RTL8367_PORT_7 BIT(7) +#define RTL8367_PORT_E1 BIT(8) /* external port 1 */ +#define RTL8367_PORT_E0 BIT(9) /* external port 0 */ + +#define RTL8367_PORTS_ALL \ + (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ + RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ + RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1 | \ + RTL8367_PORT_E0) + +#define RTL8367_PORTS_ALL_BUT_CPU \ + (RTL8367_PORT_0 | RTL8367_PORT_1 | RTL8367_PORT_2 | \ + RTL8367_PORT_3 | RTL8367_PORT_4 | RTL8367_PORT_5 | \ + RTL8367_PORT_6 | RTL8367_PORT_7 | RTL8367_PORT_E1) + +struct rtl8367_initval { + u16 reg; + u16 val; +}; + +#define RTL8367_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8367_MIB_TXB_ID 20 /* IfOutOctets */ + +static struct rtl8366_mib_counter rtl8367_mib_counters[] = { + { 0, 0, 4, "IfInOctets" }, + { 0, 4, 2, "Dot3StatsFCSErrors" }, + { 0, 6, 2, "Dot3StatsSymbolErrors" }, + { 0, 8, 2, "Dot3InPauseFrames" }, + { 0, 10, 2, "Dot3ControlInUnknownOpcodes" }, + { 0, 12, 2, "EtherStatsFragments" }, + { 0, 14, 2, "EtherStatsJabbers" }, + { 0, 16, 2, "IfInUcastPkts" }, + { 0, 18, 2, "EtherStatsDropEvents" }, + { 0, 20, 4, "EtherStatsOctets" }, + + { 0, 24, 2, "EtherStatsUnderSizePkts" }, + { 0, 26, 2, "EtherOversizeStats" }, + { 0, 28, 2, "EtherStatsPkts64Octets" }, + { 0, 30, 2, "EtherStatsPkts65to127Octets" }, + { 0, 32, 2, "EtherStatsPkts128to255Octets" }, + { 0, 34, 2, "EtherStatsPkts256to511Octets" }, + { 0, 36, 2, "EtherStatsPkts512to1023Octets" }, + { 0, 38, 2, "EtherStatsPkts1024to1518Octets" }, + { 0, 40, 2, "EtherStatsMulticastPkts" }, + { 0, 42, 2, "EtherStatsBroadcastPkts" }, + + { 0, 44, 4, "IfOutOctets" }, + + { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, + { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, + { 0, 52, 2, "Dot3sDeferredTransmissions" }, + { 0, 54, 2, "Dot3StatsLateCollisions" }, + { 0, 56, 2, "EtherStatsCollisions" }, + { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, + { 0, 60, 2, "Dot3OutPauseFrames" }, + { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, + { 0, 64, 2, "Dot1dTpPortInDiscards" }, + { 0, 66, 2, "IfOutUcastPkts" }, + { 0, 68, 2, "IfOutMulticastPkts" }, + { 0, 70, 2, "IfOutBroadcastPkts" }, + { 0, 72, 2, "OutOampduPkts" }, + { 0, 74, 2, "InOampduPkts" }, + { 0, 76, 2, "PktgenPkts" }, +}; + +#define REG_RD(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_read_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static const struct rtl8367_initval rtl8367_initvals_0_0[] = { + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, + {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, + {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, + {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, + {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, + {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, + {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, + {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, + {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, + {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, + {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, + {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, + {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, + {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, + {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, + {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, + {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, + {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, + {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, + {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, + {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, + {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1006}, {0x121e, 0x03e8}, + {0x121f, 0x02b3}, {0x1220, 0x028f}, {0x1221, 0x029b}, {0x1222, 0x0277}, + {0x1223, 0x02b3}, {0x1224, 0x028f}, {0x1225, 0x029b}, {0x1226, 0x0277}, + {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, {0x1230, 0x00b4}, + {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, + {0x0219, 0x0032}, {0x0200, 0x03e8}, {0x0201, 0x03e8}, {0x0202, 0x03e8}, + {0x0203, 0x03e8}, {0x0204, 0x03e8}, {0x0205, 0x03e8}, {0x0206, 0x03e8}, + {0x0207, 0x03e8}, {0x0218, 0x0032}, {0x0208, 0x029b}, {0x0209, 0x029b}, + {0x020a, 0x029b}, {0x020b, 0x029b}, {0x020c, 0x029b}, {0x020d, 0x029b}, + {0x020e, 0x029b}, {0x020f, 0x029b}, {0x0210, 0x029b}, {0x0211, 0x029b}, + {0x0212, 0x029b}, {0x0213, 0x029b}, {0x0214, 0x029b}, {0x0215, 0x029b}, + {0x0216, 0x029b}, {0x0217, 0x029b}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, + {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x1700, 0x014C}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, + {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, + {0x133f, 0x0010}, {0x20A0, 0x1940}, {0x20C0, 0x1940}, {0x20E0, 0x1940}, +}; + +static const struct rtl8367_initval rtl8367_initvals_0_1[] = { + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0000}, {0x2215, 0x1006}, + {0x221f, 0x0005}, {0x2200, 0x00c6}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2215, 0x6412}, {0x2216, 0x6412}, {0x2217, 0x6412}, {0x2218, 0x6412}, + {0x2219, 0x6412}, {0x221A, 0x6412}, {0x221f, 0x0001}, {0x220c, 0xdbf0}, + {0x2209, 0x2576}, {0x2207, 0x287E}, {0x220A, 0x68E5}, {0x221D, 0x3DA4}, + {0x221C, 0xE7F7}, {0x2214, 0x7F52}, {0x2218, 0x7FCE}, {0x2208, 0x04B7}, + {0x2206, 0x4072}, {0x2210, 0xF05E}, {0x221B, 0xB414}, {0x221F, 0x0003}, + {0x221A, 0x06A6}, {0x2210, 0xF05E}, {0x2213, 0x06EB}, {0x2212, 0xF4D2}, + {0x220E, 0xE120}, {0x2200, 0x7C00}, {0x2202, 0x5FD0}, {0x220D, 0x0207}, + {0x221f, 0x0002}, {0x2205, 0x0978}, {0x2202, 0x8C01}, {0x2207, 0x3620}, + {0x221C, 0x0001}, {0x2203, 0x0420}, {0x2204, 0x80C8}, {0x133e, 0x0ede}, + {0x221f, 0x0002}, {0x220c, 0x0073}, {0x220d, 0xEB65}, {0x220e, 0x51d1}, + {0x220f, 0x5dcb}, {0x2210, 0x3044}, {0x2211, 0x1800}, {0x2212, 0x7E00}, + {0x2213, 0x0000}, {0x133f, 0x0010}, {0x133e, 0x0ffe}, {0x207f, 0x0002}, + {0x2074, 0x3D22}, {0x2075, 0x2000}, {0x2076, 0x6040}, {0x2077, 0x0000}, + {0x2078, 0x0f0a}, {0x2079, 0x50AB}, {0x207a, 0x0000}, {0x207b, 0x0f0f}, + {0x205f, 0x0002}, {0x2054, 0xFF00}, {0x2055, 0x000A}, {0x2056, 0x000A}, + {0x2057, 0x0005}, {0x2058, 0x0005}, {0x2059, 0x0000}, {0x205A, 0x0005}, + {0x205B, 0x0005}, {0x205C, 0x0005}, {0x209f, 0x0002}, {0x2094, 0x00AA}, + {0x2095, 0x00AA}, {0x2096, 0x00AA}, {0x2097, 0x00AA}, {0x2098, 0x0055}, + {0x2099, 0x00AA}, {0x209A, 0x00AA}, {0x209B, 0x00AA}, {0x1363, 0x8354}, + {0x1270, 0x3333}, {0x1271, 0x3333}, {0x1272, 0x3333}, {0x1330, 0x00DB}, + {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x1b06}, {0x121e, 0x07f0}, + {0x121f, 0x0438}, {0x1220, 0x040f}, {0x1221, 0x040f}, {0x1222, 0x03eb}, + {0x1223, 0x0438}, {0x1224, 0x040f}, {0x1225, 0x040f}, {0x1226, 0x03eb}, + {0x1227, 0x0144}, {0x1228, 0x0138}, {0x122f, 0x0144}, {0x1230, 0x0138}, + {0x1229, 0x0020}, {0x122a, 0x000c}, {0x1231, 0x0030}, {0x1232, 0x0024}, + {0x0219, 0x0032}, {0x0200, 0x07d0}, {0x0201, 0x07d0}, {0x0202, 0x07d0}, + {0x0203, 0x07d0}, {0x0204, 0x07d0}, {0x0205, 0x07d0}, {0x0206, 0x07d0}, + {0x0207, 0x07d0}, {0x0218, 0x0032}, {0x0208, 0x0190}, {0x0209, 0x0190}, + {0x020a, 0x0190}, {0x020b, 0x0190}, {0x020c, 0x0190}, {0x020d, 0x0190}, + {0x020e, 0x0190}, {0x020f, 0x0190}, {0x0210, 0x0190}, {0x0211, 0x0190}, + {0x0212, 0x0190}, {0x0213, 0x0190}, {0x0214, 0x0190}, {0x0215, 0x0190}, + {0x0216, 0x0190}, {0x0217, 0x0190}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, + {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x1700, 0x0125}, {0x0301, 0x00FF}, {0x12AA, 0x0096}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0005}, {0x2200, 0x00C4}, + {0x221f, 0x0000}, {0x2210, 0x05EF}, {0x2204, 0x05E1}, {0x2200, 0x1340}, + {0x133f, 0x0010}, +}; + +static const struct rtl8367_initval rtl8367_initvals_1_0[] = { + {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, + {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, + {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, + {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, + {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, + {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, + {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, + {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, + {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, + {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, + {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, + {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, + {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, + {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, + {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, + {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, + {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, + {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, + {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, + {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, + {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, + {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, + {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, + {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, + {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, + {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, + {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, + {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, + {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, + {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, + {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, + {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, + {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, + {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, + {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, + {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, + {0x121D, 0x7D16}, {0x121E, 0x03E8}, {0x121F, 0x024E}, {0x1220, 0x0230}, + {0x1221, 0x0244}, {0x1222, 0x0226}, {0x1223, 0x024E}, {0x1224, 0x0230}, + {0x1225, 0x0244}, {0x1226, 0x0226}, {0x1227, 0x00C0}, {0x1228, 0x00B4}, + {0x122F, 0x00C0}, {0x1230, 0x00B4}, {0x0208, 0x03E8}, {0x0209, 0x03E8}, + {0x020A, 0x03E8}, {0x020B, 0x03E8}, {0x020C, 0x03E8}, {0x020D, 0x03E8}, + {0x020E, 0x03E8}, {0x020F, 0x03E8}, {0x0210, 0x03E8}, {0x0211, 0x03E8}, + {0x0212, 0x03E8}, {0x0213, 0x03E8}, {0x0214, 0x03E8}, {0x0215, 0x03E8}, + {0x0216, 0x03E8}, {0x0217, 0x03E8}, {0x0900, 0x0000}, {0x0901, 0x0000}, + {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087B, 0x0000}, + {0x087C, 0xFF00}, {0x087D, 0x0000}, {0x087E, 0x0000}, {0x0801, 0x0100}, + {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, + {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, + {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, {0x2200, 0x1340}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x20A0, 0x1940}, + {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, +}; + +static const struct rtl8367_initval rtl8367_initvals_1_1[] = { + {0x1B24, 0x0000}, {0x1B25, 0x0000}, {0x1B26, 0x0000}, {0x1B27, 0x0000}, + {0x207F, 0x0002}, {0x2079, 0x0200}, {0x207F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2201, 0x0700}, {0x2205, 0x8B82}, + {0x2206, 0x05CB}, {0x221F, 0x0002}, {0x2204, 0x80C2}, {0x2205, 0x0938}, + {0x221F, 0x0003}, {0x2212, 0xC4D2}, {0x220D, 0x0207}, {0x221F, 0x0001}, + {0x2207, 0x267E}, {0x221C, 0xE5F7}, {0x221B, 0x0424}, {0x221F, 0x0007}, + {0x221E, 0x0040}, {0x2218, 0x0000}, {0x221F, 0x0007}, {0x221E, 0x002C}, + {0x2218, 0x008B}, {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, + {0x2205, 0x8000}, {0x2206, 0xF8E0}, {0x2206, 0xE000}, {0x2206, 0xE1E0}, + {0x2206, 0x01AC}, {0x2206, 0x2408}, {0x2206, 0xE08B}, {0x2206, 0x84F7}, + {0x2206, 0x20E4}, {0x2206, 0x8B84}, {0x2206, 0xFC05}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AC}, {0x2206, 0x201A}, + {0x2206, 0xBF80}, {0x2206, 0x59D0}, {0x2206, 0x2402}, {0x2206, 0x803D}, + {0x2206, 0xE0E0}, {0x2206, 0xE4E1}, {0x2206, 0xE0E5}, {0x2206, 0x5806}, + {0x2206, 0x68C0}, {0x2206, 0xD1D2}, {0x2206, 0xE4E0}, {0x2206, 0xE4E5}, + {0x2206, 0xE0E5}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x05FB}, + {0x2206, 0x0BFB}, {0x2206, 0x58FF}, {0x2206, 0x9E11}, {0x2206, 0x06F0}, + {0x2206, 0x0C81}, {0x2206, 0x8AE0}, {0x2206, 0x0019}, {0x2206, 0x1B89}, + {0x2206, 0xCFEB}, {0x2206, 0x19EB}, {0x2206, 0x19B0}, {0x2206, 0xEFFF}, + {0x2206, 0x0BFF}, {0x2206, 0x0425}, {0x2206, 0x0807}, {0x2206, 0x2640}, + {0x2206, 0x7227}, {0x2206, 0x267E}, {0x2206, 0x2804}, {0x2206, 0xB729}, + {0x2206, 0x2576}, {0x2206, 0x2A68}, {0x2206, 0xE52B}, {0x2206, 0xAD00}, + {0x2206, 0x2CDB}, {0x2206, 0xF02D}, {0x2206, 0x67BB}, {0x2206, 0x2E7B}, + {0x2206, 0x0F2F}, {0x2206, 0x7365}, {0x2206, 0x31AC}, {0x2206, 0xCC32}, + {0x2206, 0x2300}, {0x2206, 0x332D}, {0x2206, 0x1734}, {0x2206, 0x7F52}, + {0x2206, 0x3510}, {0x2206, 0x0036}, {0x2206, 0x0600}, {0x2206, 0x370C}, + {0x2206, 0xC038}, {0x2206, 0x7FCE}, {0x2206, 0x3CE5}, {0x2206, 0xF73D}, + {0x2206, 0x3DA4}, {0x2206, 0x6530}, {0x2206, 0x3E67}, {0x2206, 0x0053}, + {0x2206, 0x69D2}, {0x2206, 0x0F6A}, {0x2206, 0x012C}, {0x2206, 0x6C2B}, + {0x2206, 0x136E}, {0x2206, 0xE100}, {0x2206, 0x6F12}, {0x2206, 0xF771}, + {0x2206, 0x006B}, {0x2206, 0x7306}, {0x2206, 0xEB74}, {0x2206, 0x94C7}, + {0x2206, 0x7698}, {0x2206, 0x0A77}, {0x2206, 0x5000}, {0x2206, 0x788A}, + {0x2206, 0x1579}, {0x2206, 0x7F6F}, {0x2206, 0x7A06}, {0x2206, 0xA600}, + {0x2205, 0x8B90}, {0x2206, 0x8000}, {0x2205, 0x8B92}, {0x2206, 0x8000}, + {0x2205, 0x8B94}, {0x2206, 0x8014}, {0x2208, 0xFFFA}, {0x2202, 0x3C65}, + {0x2205, 0xFFF6}, {0x2206, 0x00F7}, {0x221F, 0x0000}, {0x221F, 0x0007}, + {0x221E, 0x0042}, {0x2218, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221E, 0x0020}, {0x2215, 0x0000}, {0x221E, 0x0023}, {0x2216, 0x8000}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x1306, 0x000C}, {0x1307, 0x000C}, + {0x1303, 0x0067}, {0x1304, 0x4444}, {0x1203, 0xFF00}, {0x1200, 0x7FC4}, + {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, + {0x0865, 0x3210}, {0x087B, 0x0000}, {0x087C, 0xFF00}, {0x087D, 0x0000}, + {0x087E, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, + {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, + {0x0A25, 0x2040}, {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, + {0x0A29, 0x2040}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x221F, 0x0000}, + {0x2200, 0x1340}, {0x221F, 0x0000}, {0x133F, 0x0010}, {0x133E, 0x0FFE}, + {0x1B03, 0x0876}, +}; + +static const struct rtl8367_initval rtl8367_initvals_2_0[] = { + {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, + {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, + {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, + {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, + {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, + {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, + {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, + {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, + {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, + {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, + {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, + {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, + {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, + {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, + {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, + {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, + {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, + {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, + {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, + {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, + {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, + {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, + {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, + {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, + {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, + {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, + {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, + {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, + {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, + {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, + {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, + {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, + {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, + {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, + {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, + {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x121d, 0x7D16}, + {0x121e, 0x03e8}, {0x121f, 0x024e}, {0x1220, 0x0230}, {0x1221, 0x0244}, + {0x1222, 0x0226}, {0x1223, 0x024e}, {0x1224, 0x0230}, {0x1225, 0x0244}, + {0x1226, 0x0226}, {0x1227, 0x00c0}, {0x1228, 0x00b4}, {0x122f, 0x00c0}, + {0x1230, 0x00b4}, {0x0208, 0x03e8}, {0x0209, 0x03e8}, {0x020a, 0x03e8}, + {0x020b, 0x03e8}, {0x020c, 0x03e8}, {0x020d, 0x03e8}, {0x020e, 0x03e8}, + {0x020f, 0x03e8}, {0x0210, 0x03e8}, {0x0211, 0x03e8}, {0x0212, 0x03e8}, + {0x0213, 0x03e8}, {0x0214, 0x03e8}, {0x0215, 0x03e8}, {0x0216, 0x03e8}, + {0x0217, 0x03e8}, {0x0900, 0x0000}, {0x0901, 0x0000}, {0x0902, 0x0000}, + {0x0903, 0x0000}, {0x0865, 0x3210}, {0x087b, 0x0000}, {0x087c, 0xff00}, + {0x087d, 0x0000}, {0x087e, 0x0000}, {0x0801, 0x0100}, {0x0802, 0x0100}, + {0x0A20, 0x2040}, {0x0A21, 0x2040}, {0x0A22, 0x2040}, {0x0A23, 0x2040}, + {0x0A24, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, {0x20A0, 0x1940}, + {0x20C0, 0x1940}, {0x20E0, 0x1940}, {0x130c, 0x0050}, +}; + +static const struct rtl8367_initval rtl8367_initvals_2_1[] = { + {0x1b24, 0x0000}, {0x1b25, 0x0000}, {0x1b26, 0x0000}, {0x1b27, 0x0000}, + {0x133f, 0x0030}, {0x133e, 0x000e}, {0x221f, 0x0007}, {0x221e, 0x0048}, + {0x2219, 0x4012}, {0x221f, 0x0003}, {0x2201, 0x3554}, {0x2202, 0x63e8}, + {0x2203, 0x99c2}, {0x2204, 0x0113}, {0x2205, 0x303e}, {0x220d, 0x0207}, + {0x220e, 0xe100}, {0x221f, 0x0007}, {0x221e, 0x0040}, {0x2218, 0x0000}, + {0x221f, 0x0007}, {0x221e, 0x002c}, {0x2218, 0x008b}, {0x221f, 0x0005}, + {0x2205, 0xfff6}, {0x2206, 0x0080}, {0x221f, 0x0005}, {0x2205, 0x8000}, + {0x2206, 0x0280}, {0x2206, 0x2bf7}, {0x2206, 0x00e0}, {0x2206, 0xfff7}, + {0x2206, 0xa080}, {0x2206, 0x02ae}, {0x2206, 0xf602}, {0x2206, 0x804e}, + {0x2206, 0x0201}, {0x2206, 0x5002}, {0x2206, 0x0163}, {0x2206, 0x0201}, + {0x2206, 0x79e0}, {0x2206, 0x8b8c}, {0x2206, 0xe18b}, {0x2206, 0x8d1e}, + {0x2206, 0x01e1}, {0x2206, 0x8b8e}, {0x2206, 0x1e01}, {0x2206, 0xa000}, + {0x2206, 0xe4ae}, {0x2206, 0xd8bf}, {0x2206, 0x8b88}, {0x2206, 0xec00}, + {0x2206, 0x19a9}, {0x2206, 0x8b90}, {0x2206, 0xf9ee}, {0x2206, 0xfff6}, + {0x2206, 0x00ee}, {0x2206, 0xfff7}, {0x2206, 0xfce0}, {0x2206, 0xe140}, + {0x2206, 0xe1e1}, {0x2206, 0x41f7}, {0x2206, 0x2ff6}, {0x2206, 0x28e4}, + {0x2206, 0xe140}, {0x2206, 0xe5e1}, {0x2206, 0x4104}, {0x2206, 0xf8fa}, + {0x2206, 0xef69}, {0x2206, 0xe08b}, {0x2206, 0x86ac}, {0x2206, 0x201a}, + {0x2206, 0xbf80}, {0x2206, 0x77d0}, {0x2206, 0x6c02}, {0x2206, 0x2978}, + {0x2206, 0xe0e0}, {0x2206, 0xe4e1}, {0x2206, 0xe0e5}, {0x2206, 0x5806}, + {0x2206, 0x68c0}, {0x2206, 0xd1d2}, {0x2206, 0xe4e0}, {0x2206, 0xe4e5}, + {0x2206, 0xe0e5}, {0x2206, 0xef96}, {0x2206, 0xfefc}, {0x2206, 0x0425}, + {0x2206, 0x0807}, {0x2206, 0x2640}, {0x2206, 0x7227}, {0x2206, 0x267e}, + {0x2206, 0x2804}, {0x2206, 0xb729}, {0x2206, 0x2576}, {0x2206, 0x2a68}, + {0x2206, 0xe52b}, {0x2206, 0xad00}, {0x2206, 0x2cdb}, {0x2206, 0xf02d}, + {0x2206, 0x67bb}, {0x2206, 0x2e7b}, {0x2206, 0x0f2f}, {0x2206, 0x7365}, + {0x2206, 0x31ac}, {0x2206, 0xcc32}, {0x2206, 0x2300}, {0x2206, 0x332d}, + {0x2206, 0x1734}, {0x2206, 0x7f52}, {0x2206, 0x3510}, {0x2206, 0x0036}, + {0x2206, 0x0600}, {0x2206, 0x370c}, {0x2206, 0xc038}, {0x2206, 0x7fce}, + {0x2206, 0x3ce5}, {0x2206, 0xf73d}, {0x2206, 0x3da4}, {0x2206, 0x6530}, + {0x2206, 0x3e67}, {0x2206, 0x0053}, {0x2206, 0x69d2}, {0x2206, 0x0f6a}, + {0x2206, 0x012c}, {0x2206, 0x6c2b}, {0x2206, 0x136e}, {0x2206, 0xe100}, + {0x2206, 0x6f12}, {0x2206, 0xf771}, {0x2206, 0x006b}, {0x2206, 0x7306}, + {0x2206, 0xeb74}, {0x2206, 0x94c7}, {0x2206, 0x7698}, {0x2206, 0x0a77}, + {0x2206, 0x5000}, {0x2206, 0x788a}, {0x2206, 0x1579}, {0x2206, 0x7f6f}, + {0x2206, 0x7a06}, {0x2206, 0xa600}, {0x2201, 0x0701}, {0x2200, 0x0405}, + {0x221f, 0x0000}, {0x2200, 0x1340}, {0x221f, 0x0000}, {0x133f, 0x0010}, + {0x133e, 0x0ffe}, {0x1203, 0xff00}, {0x1200, 0x7fc4}, {0x0900, 0x0000}, + {0x0901, 0x0000}, {0x0902, 0x0000}, {0x0903, 0x0000}, {0x0865, 0x3210}, + {0x087b, 0x0000}, {0x087c, 0xff00}, {0x087d, 0x0000}, {0x087e, 0x0000}, + {0x0801, 0x0100}, {0x0802, 0x0100}, {0x0A20, 0x2040}, {0x0A21, 0x2040}, + {0x0A22, 0x2040}, {0x0A23, 0x2040}, {0x0A24, 0x2040}, {0x0A25, 0x2040}, + {0x0A26, 0x2040}, {0x0A27, 0x2040}, {0x0A28, 0x2040}, {0x0A29, 0x2040}, + {0x130c, 0x0050}, +}; + +static int rtl8367_write_initvals(struct rtl8366_smi *smi, + const struct rtl8367_initval *initvals, + int count) +{ + int err; + int i; + + for (i = 0; i < count; i++) + REG_WR(smi, initvals[i].reg, initvals[i].val); + + return 0; +} + +static int rtl8367_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 *val) +{ + int timeout; + u32 data; + int err; + + if (phy_addr > RTL8367_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if (data & RTL8367_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* prepare address */ + REG_WR(smi, RTL8367_IA_ADDRESS_REG, + RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send read command */ + REG_WR(smi, RTL8367_IA_CTRL_REG, + RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_READ); + + timeout = 5; + do { + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy read timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + /* read data */ + REG_RD(smi, RTL8367_IA_READ_DATA_REG, val); + + dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, *val); + return 0; +} + +static int rtl8367_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 val) +{ + int timeout; + u32 data; + int err; + + dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, val); + + if (phy_addr > RTL8367_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if (data & RTL8367_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* preapre data */ + REG_WR(smi, RTL8367_IA_WRITE_DATA_REG, val); + + /* prepare address */ + REG_WR(smi, RTL8367_IA_ADDRESS_REG, + RTL8367_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send write command */ + REG_WR(smi, RTL8367_IA_CTRL_REG, + RTL8367_IA_CTRL_CMD_MASK | RTL8367_IA_CTRL_RW_WRITE); + + timeout = 5; + do { + REG_RD(smi, RTL8367_IA_STATUS_REG, &data); + if ((data & RTL8367_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy write timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + return 0; +} + +static int rtl8367_init_regs0(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + int err; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_0_0; + count = ARRAY_SIZE(rtl8367_initvals_0_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_0_1; + count = ARRAY_SIZE(rtl8367_initvals_0_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + err = rtl8367_write_initvals(smi, initvals, count); + if (err) + return err; + + /* TODO: complete this */ + + return 0; +} + +static int rtl8367_init_regs1(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_1_0; + count = ARRAY_SIZE(rtl8367_initvals_1_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_1_1; + count = ARRAY_SIZE(rtl8367_initvals_1_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + return rtl8367_write_initvals(smi, initvals, count); +} + +static int rtl8367_init_regs2(struct rtl8366_smi *smi, unsigned mode) +{ + const struct rtl8367_initval *initvals; + int count; + + switch (mode) { + case 0: + initvals = rtl8367_initvals_2_0; + count = ARRAY_SIZE(rtl8367_initvals_2_0); + break; + + case 1: + case 2: + initvals = rtl8367_initvals_2_1; + count = ARRAY_SIZE(rtl8367_initvals_2_1); + break; + + default: + dev_err(smi->parent, "%s: unknow mode %u\n", __func__, mode); + return -ENODEV; + } + + return rtl8367_write_initvals(smi, initvals, count); +} + +static int rtl8367_init_regs(struct rtl8366_smi *smi) +{ + u32 data; + u32 rlvid; + u32 mode; + int err; + + REG_WR(smi, RTL8367_RTL_MAGIC_ID_REG, RTL8367_RTL_MAGIC_ID_VAL); + + REG_RD(smi, RTL8367_CHIP_VER_REG, &data); + rlvid = (data >> RTL8367_CHIP_VER_RLVID_SHIFT) & + RTL8367_CHIP_VER_RLVID_MASK; + + REG_RD(smi, RTL8367_CHIP_MODE_REG, &data); + mode = data & RTL8367_CHIP_MODE_MASK; + + switch (rlvid) { + case 0: + err = rtl8367_init_regs0(smi, mode); + break; + + case 1: + err = rtl8367_write_phy_reg(smi, 0, 31, 5); + if (err) + break; + + err = rtl8367_write_phy_reg(smi, 0, 5, 0x3ffe); + if (err) + break; + + err = rtl8367_read_phy_reg(smi, 0, 6, &data); + if (err) + break; + + if (data == 0x94eb) { + err = rtl8367_init_regs1(smi, mode); + } else if (data == 0x2104) { + err = rtl8367_init_regs2(smi, mode); + } else { + dev_err(smi->parent, "unknow phy data %04x\n", data); + return -ENODEV; + } + + break; + + default: + dev_err(smi->parent, "unknow rlvid %u\n", rlvid); + err = -ENODEV; + break; + } + + return err; +} + +static int rtl8367_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + int err; + u32 data; + + REG_WR(smi, RTL8367_CHIP_RESET_REG, RTL8367_CHIP_RESET_HW); + msleep(RTL8367_RESET_DELAY); + + do { + REG_RD(smi, RTL8367_CHIP_RESET_REG, &data); + if (!(data & RTL8367_CHIP_RESET_HW)) + break; + + msleep(1); + } while (--timeout); + + if (!timeout) { + dev_err(smi->parent, "chip reset timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8367_extif_set_mode(struct rtl8366_smi *smi, int id, + enum rtl8367_extif_mode mode) +{ + int err; + + /* set port mode */ + switch (mode) { + case RTL8367_EXTIF_MODE_RGMII: + case RTL8367_EXTIF_MODE_RGMII_33V: + REG_WR(smi, RTL8367_CHIP_DEBUG0_REG, 0x0367); + REG_WR(smi, RTL8367_CHIP_DEBUG1_REG, 0x7777); + break; + + case RTL8367_EXTIF_MODE_TMII_MAC: + case RTL8367_EXTIF_MODE_TMII_PHY: + REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), BIT((id + 1) % 2)); + break; + + case RTL8367_EXTIF_MODE_GMII: + REG_RMW(smi, RTL8367_CHIP_DEBUG0_REG, + RTL8367_CHIP_DEBUG0_DUMMY0(id), + RTL8367_CHIP_DEBUG0_DUMMY0(id)); + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), BIT(6)); + break; + + case RTL8367_EXTIF_MODE_MII_MAC: + case RTL8367_EXTIF_MODE_MII_PHY: + case RTL8367_EXTIF_MODE_DISABLED: + REG_RMW(smi, RTL8367_BYPASS_LINE_RATE_REG, + BIT((id + 1) % 2), 0); + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), BIT(6), 0); + break; + + default: + dev_err(smi->parent, + "invalid mode for external interface %d\n", id); + return -EINVAL; + } + + REG_RMW(smi, RTL8367_DIS_REG, + RTL8367_DIS_RGMII_MASK << RTL8367_DIS_RGMII_SHIFT(id), + mode << RTL8367_DIS_RGMII_SHIFT(id)); + + return 0; +} + +static int rtl8367_extif_set_force(struct rtl8366_smi *smi, int id, + struct rtl8367_port_ability *pa) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367_DI_FORCE_MODE | + RTL8367_DI_FORCE_NWAY | + RTL8367_DI_FORCE_TXPAUSE | + RTL8367_DI_FORCE_RXPAUSE | + RTL8367_DI_FORCE_LINK | + RTL8367_DI_FORCE_DUPLEX | + RTL8367_DI_FORCE_SPEED_MASK); + + val = pa->speed; + val |= pa->force_mode ? RTL8367_DI_FORCE_MODE : 0; + val |= pa->nway ? RTL8367_DI_FORCE_NWAY : 0; + val |= pa->txpause ? RTL8367_DI_FORCE_TXPAUSE : 0; + val |= pa->rxpause ? RTL8367_DI_FORCE_RXPAUSE : 0; + val |= pa->link ? RTL8367_DI_FORCE_LINK : 0; + val |= pa->duplex ? RTL8367_DI_FORCE_DUPLEX : 0; + + REG_RMW(smi, RTL8367_DI_FORCE_REG(id), mask, val); + + return 0; +} + +static int rtl8367_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, + unsigned txdelay, unsigned rxdelay) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367_EXT_RGMXF_RXDELAY_MASK | + (RTL8367_EXT_RGMXF_TXDELAY_MASK << + RTL8367_EXT_RGMXF_TXDELAY_SHIFT)); + + val = rxdelay; + val |= txdelay << RTL8367_EXT_RGMXF_TXDELAY_SHIFT; + + REG_RMW(smi, RTL8367_EXT_RGMXF_REG(id), mask, val); + + return 0; +} + +static int rtl8367_extif_init(struct rtl8366_smi *smi, int id, + struct rtl8367_extif_config *cfg) +{ + enum rtl8367_extif_mode mode; + int err; + + mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; + + err = rtl8367_extif_set_mode(smi, id, mode); + if (err) + return err; + + if (mode != RTL8367_EXTIF_MODE_DISABLED) { + err = rtl8367_extif_set_force(smi, id, &cfg->ability); + if (err) + return err; + + err = rtl8367_extif_set_rgmii_delay(smi, id, cfg->txdelay, + cfg->rxdelay); + if (err) + return err; + } + + return 0; +} + +static int rtl8367_led_group_set_ports(struct rtl8366_smi *smi, + unsigned int group, u16 port_mask) +{ + u32 reg; + u32 s; + int err; + + port_mask &= RTL8367_PARA_LED_IO_EN_PMASK; + s = (group % 2) * 8; + reg = RTL8367_PARA_LED_IO_EN1_REG + (group / 2); + + REG_RMW(smi, reg, (RTL8367_PARA_LED_IO_EN_PMASK << s), port_mask << s); + + return 0; +} + +static int rtl8367_led_group_set_mode(struct rtl8366_smi *smi, + unsigned int mode) +{ + u16 mask; + u16 set; + int err; + + mode &= RTL8367_LED_CONFIG_DATA_M; + + mask = (RTL8367_LED_CONFIG_DATA_M << RTL8367_LED_CONFIG_DATA_S) | + RTL8367_LED_CONFIG_SEL; + set = (mode << RTL8367_LED_CONFIG_DATA_S) | RTL8367_LED_CONFIG_SEL; + + REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); + + return 0; +} + +static int rtl8367_led_group_set_config(struct rtl8366_smi *smi, + unsigned int led, unsigned int cfg) +{ + u16 mask; + u16 set; + int err; + + mask = (RTL8367_LED_CONFIG_LED_CFG_M << (led * 4)) | + RTL8367_LED_CONFIG_SEL; + set = (cfg & RTL8367_LED_CONFIG_LED_CFG_M) << (led * 4); + + REG_RMW(smi, RTL8367_LED_CONFIG_REG, mask, set); + return 0; +} + +static int rtl8367_led_op_select_parallel(struct rtl8366_smi *smi) +{ + int err; + + REG_WR(smi, RTL8367_LED_SYS_CONFIG_REG, 0x1472); + return 0; +} + +static int rtl8367_led_blinkrate_set(struct rtl8366_smi *smi, unsigned int rate) +{ + u16 mask; + u16 set; + int err; + + mask = RTL8367_LED_MODE_RATE_M << RTL8367_LED_MODE_RATE_S; + set = (rate & RTL8367_LED_MODE_RATE_M) << RTL8367_LED_MODE_RATE_S; + REG_RMW(smi, RTL8367_LED_MODE_REG, mask, set); + + return 0; +} + +#ifdef CONFIG_OF +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + struct rtl8367_extif_config *cfg; + const __be32 *prop; + int size; + int err; + + prop = of_get_property(smi->parent->of_node, name, &size); + if (!prop) + return rtl8367_extif_init(smi, id, NULL); + + if (size != (9 * sizeof(*prop))) { + dev_err(smi->parent, "%s property is invalid\n", name); + return -EINVAL; + } + + cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->txdelay = be32_to_cpup(prop++); + cfg->rxdelay = be32_to_cpup(prop++); + cfg->mode = be32_to_cpup(prop++); + cfg->ability.force_mode = be32_to_cpup(prop++); + cfg->ability.txpause = be32_to_cpup(prop++); + cfg->ability.rxpause = be32_to_cpup(prop++); + cfg->ability.link = be32_to_cpup(prop++); + cfg->ability.duplex = be32_to_cpup(prop++); + cfg->ability.speed = be32_to_cpup(prop++); + + err = rtl8367_extif_init(smi, id, cfg); + kfree(cfg); + + return err; +} +#else +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + return -EINVAL; +} +#endif + +static int rtl8367_setup(struct rtl8366_smi *smi) +{ + struct rtl8367_platform_data *pdata; + int err; + int i; + + pdata = smi->parent->platform_data; + + err = rtl8367_init_regs(smi); + if (err) + return err; + + /* initialize external interfaces */ + if (smi->parent->of_node) { + err = rtl8367_extif_init_of(smi, 0, "realtek,extif0"); + if (err) + return err; + + err = rtl8367_extif_init_of(smi, 1, "realtek,extif1"); + if (err) + return err; + } else { + err = rtl8367_extif_init(smi, 0, pdata->extif0_cfg); + if (err) + return err; + + err = rtl8367_extif_init(smi, 1, pdata->extif1_cfg); + if (err) + return err; + } + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8367_SWC0_REG, RTL8367_SWC0_MAX_LENGTH_MASK, + RTL8367_SWC0_MAX_LENGTH_1536); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8367_VLAN_INGRESS_REG, RTL8367_PORTS_ALL); + + /* + * Setup egress tag mode for each port. + */ + for (i = 0; i < RTL8367_NUM_PORTS; i++) + REG_RMW(smi, + RTL8367_PORT_CFG_REG(i), + RTL8367_PORT_CFG_EGRESS_MODE_MASK << + RTL8367_PORT_CFG_EGRESS_MODE_SHIFT, + RTL8367_PORT_CFG_EGRESS_MODE_ORIGINAL << + RTL8367_PORT_CFG_EGRESS_MODE_SHIFT); + + /* setup LEDs */ + err = rtl8367_led_group_set_ports(smi, 0, RTL8367_PORTS_ALL); + if (err) + return err; + + err = rtl8367_led_group_set_mode(smi, 0); + if (err) + return err; + + err = rtl8367_led_op_select_parallel(smi); + if (err) + return err; + + err = rtl8367_led_blinkrate_set(smi, 1); + if (err) + return err; + + err = rtl8367_led_group_set_config(smi, 0, 2); + if (err) + return err; + + return 0; +} + +static int rtl8367_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + struct rtl8366_mib_counter *mib; + int offset; + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8367_NUM_PORTS || counter >= RTL8367_MIB_COUNT) + return -EINVAL; + + mib = &rtl8367_mib_counters[counter]; + addr = RTL8367_MIB_COUNTER_PORT_OFFSET * port + mib->offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + REG_WR(smi, RTL8367_MIB_ADDRESS_REG, addr >> 2); + + /* read MIB control register */ + REG_RD(smi, RTL8367_MIB_CTRL_REG(0), &data); + + if (data & RTL8367_MIB_CTRL_BUSY_MASK) + return -EBUSY; + + if (data & RTL8367_MIB_CTRL_RESET_MASK) + return -EIO; + + if (mib->length == 4) + offset = 3; + else + offset = (mib->offset + 1) % 4; + + mibvalue = 0; + for (i = 0; i < mib->length; i++) { + REG_RD(smi, RTL8367_MIB_COUNTER_REG(offset - i), &data); + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8367_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367_TA_VLAN_DATA_SIZE]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8367_NUM_VIDS) + return -EINVAL; + + /* write VID */ + REG_WR(smi, RTL8367_TA_ADDR_REG, vid); + + /* write table access control word */ + REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_READ); + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367_TA_DATA_REG(i), &data[i]); + + vlan4k->vid = vid; + vlan4k->member = (data[0] >> RTL8367_TA_VLAN_MEMBER_SHIFT) & + RTL8367_TA_VLAN_MEMBER_MASK; + vlan4k->fid = (data[1] >> RTL8367_TA_VLAN_FID_SHIFT) & + RTL8367_TA_VLAN_FID_MASK; + vlan4k->untag = (data[2] >> RTL8367_TA_VLAN_UNTAG1_SHIFT) & + RTL8367_TA_VLAN_UNTAG1_MASK; + vlan4k->untag |= ((data[3] >> RTL8367_TA_VLAN_UNTAG2_SHIFT) & + RTL8367_TA_VLAN_UNTAG2_MASK) << 2; + + return 0; +} + +static int rtl8367_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367_TA_VLAN_DATA_SIZE]; + int err; + int i; + + if (vlan4k->vid >= RTL8367_NUM_VIDS || + vlan4k->member > RTL8367_TA_VLAN_MEMBER_MASK || + vlan4k->untag > RTL8367_UNTAG_MASK || + vlan4k->fid > RTL8367_FIDMAX) + return -EINVAL; + + data[0] = (vlan4k->member & RTL8367_TA_VLAN_MEMBER_MASK) << + RTL8367_TA_VLAN_MEMBER_SHIFT; + data[1] = (vlan4k->fid & RTL8367_TA_VLAN_FID_MASK) << + RTL8367_TA_VLAN_FID_SHIFT; + data[2] = (vlan4k->untag & RTL8367_TA_VLAN_UNTAG1_MASK) << + RTL8367_TA_VLAN_UNTAG1_SHIFT; + data[3] = ((vlan4k->untag >> 2) & RTL8367_TA_VLAN_UNTAG2_MASK) << + RTL8367_TA_VLAN_UNTAG2_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367_TA_DATA_REG(i), data[i]); + + /* write VID */ + REG_WR(smi, RTL8367_TA_ADDR_REG, + vlan4k->vid & RTL8367_TA_VLAN_VID_MASK); + + /* write table access control word */ + REG_WR(smi, RTL8367_TA_CTRL_REG, RTL8367_TA_CTRL_CVLAN_WRITE); + + return 0; +} + +static int rtl8367_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367_VLAN_MC_DATA_SIZE]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8367_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367_VLAN_MC_BASE(index) + i, &data[i]); + + vlanmc->member = (data[0] >> RTL8367_VLAN_MC_MEMBER_SHIFT) & + RTL8367_VLAN_MC_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8367_VLAN_MC_FID_SHIFT) & + RTL8367_VLAN_MC_FID_MASK; + vlanmc->vid = (data[3] >> RTL8367_VLAN_MC_EVID_SHIFT) & + RTL8367_VLAN_MC_EVID_MASK; + + return 0; +} + +static int rtl8367_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367_VLAN_MC_DATA_SIZE]; + int err; + int i; + + if (index >= RTL8367_NUM_VLANS || + vlanmc->vid >= RTL8367_NUM_VIDS || + vlanmc->priority > RTL8367_PRIORITYMAX || + vlanmc->member > RTL8367_VLAN_MC_MEMBER_MASK || + vlanmc->untag > RTL8367_UNTAG_MASK || + vlanmc->fid > RTL8367_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->member & RTL8367_VLAN_MC_MEMBER_MASK) << + RTL8367_VLAN_MC_MEMBER_SHIFT; + data[1] = (vlanmc->fid & RTL8367_VLAN_MC_FID_MASK) << + RTL8367_VLAN_MC_FID_SHIFT; + data[2] = 0; + data[3] = (vlanmc->vid & RTL8367_VLAN_MC_EVID_MASK) << + RTL8367_VLAN_MC_EVID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367_VLAN_MC_BASE(index) + i, data[i]); + + return 0; +} + +static int rtl8367_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + REG_RD(smi, RTL8367_VLAN_PVID_CTRL_REG(port), &data); + + *val = (data >> RTL8367_VLAN_PVID_CTRL_SHIFT(port)) & + RTL8367_VLAN_PVID_CTRL_MASK; + + return 0; +} + +static int rtl8367_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8367_NUM_PORTS || index >= RTL8367_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367_VLAN_PVID_CTRL_REG(port), + RTL8367_VLAN_PVID_CTRL_MASK << + RTL8367_VLAN_PVID_CTRL_SHIFT(port), + (index & RTL8367_VLAN_PVID_CTRL_MASK) << + RTL8367_VLAN_PVID_CTRL_SHIFT(port)); +} + +static int rtl8367_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8367_VLAN_CTRL_REG, + RTL8367_VLAN_CTRL_ENABLE, + (enable) ? RTL8367_VLAN_CTRL_ENABLE : 0); +} + +static int rtl8367_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return 0; +} + +static int rtl8367_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8367_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8367_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8367_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + + REG_WR(smi, RTL8367_PORT_ISOLATION_REG(port), + (enable) ? RTL8367_PORTS_ALL : 0); + + return 0; +} + +static int rtl8367_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(0), 0, + RTL8367_MIB_CTRL_GLOBAL_RESET_MASK); +} + +static int rtl8367_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8367_PORT_STATUS_REG(port), &data); + + link->link = !!(data & RTL8367_PORT_STATUS_LINK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8367_PORT_STATUS_DUPLEX); + link->rx_flow = !!(data & RTL8367_PORT_STATUS_RXPAUSE); + link->tx_flow = !!(data & RTL8367_PORT_STATUS_TXPAUSE); + link->aneg = !!(data & RTL8367_PORT_STATUS_NWAY); + + speed = (data & RTL8367_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8367_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8367_SWC0_REG, &data); + val->value.i = (data & RTL8367_SWC0_MAX_LENGTH_MASK) >> + RTL8367_SWC0_MAX_LENGTH_SHIFT; + + return 0; +} + +static int rtl8367_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 max_len; + + switch (val->value.i) { + case 0: + max_len = RTL8367_SWC0_MAX_LENGTH_1522; + break; + case 1: + max_len = RTL8367_SWC0_MAX_LENGTH_1536; + break; + case 2: + max_len = RTL8367_SWC0_MAX_LENGTH_1552; + break; + case 3: + max_len = RTL8367_SWC0_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8367_SWC0_REG, + RTL8367_SWC0_MAX_LENGTH_MASK, max_len); +} + + +static int rtl8367_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int port; + + port = val->port_vlan; + if (port >= RTL8367_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367_MIB_CTRL_REG(port / 8), 0, + RTL8367_MIB_CTRL_PORT_RESET_MASK(port % 8)); +} + +static int rtl8367_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8367_MIB_TXB_ID, RTL8367_MIB_RXB_ID)); +} + +static struct switch_attr rtl8367_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8367_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + "(0:1522, 1:1536, 2:1552, 3:16000)", + .set = rtl8367_sw_set_max_length, + .get = rtl8367_sw_get_max_length, + .max = 3, + } +}; + +static struct switch_attr rtl8367_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8367_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, +}; + +static struct switch_attr rtl8367_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, { + .type = SWITCH_TYPE_INT, + .name = "fid", + .description = "Get/Set vlan FID", + .max = RTL8367_FIDMAX, + .set = rtl8366_sw_set_vlan_fid, + .get = rtl8366_sw_get_vlan_fid, + }, +}; + +static const struct switch_dev_ops rtl8367_sw_ops = { + .attr_global = { + .attr = rtl8367_globals, + .n_attr = ARRAY_SIZE(rtl8367_globals), + }, + .attr_port = { + .attr = rtl8367_port, + .n_attr = ARRAY_SIZE(rtl8367_port), + }, + .attr_vlan = { + .attr = rtl8367_vlan, + .n_attr = ARRAY_SIZE(rtl8367_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8367_sw_get_port_link, + .get_port_stats = rtl8367_sw_get_port_stats, +}; + +static int rtl8367_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8367"; + dev->cpu_port = RTL8367_CPU_PORT_NUM; + dev->ports = RTL8367_NUM_PORTS; + dev->vlans = RTL8367_NUM_VIDS; + dev->ops = &rtl8367_sw_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8367_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8367_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8367_read_phy_reg(smi, addr, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8367_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8367_write_phy_reg(smi, addr, reg, val); + if (err) + return err; + + /* flush write */ + (void) rtl8367_read_phy_reg(smi, addr, reg, &t); + + return err; +} + +static int rtl8367_detect(struct rtl8366_smi *smi) +{ + u32 rtl_no = 0; + u32 rtl_ver = 0; + char *chip_name; + int ret; + + ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_NO_REG, &rtl_no); + if (ret) { + dev_err(smi->parent, "unable to read chip number\n"); + return ret; + } + + switch (rtl_no) { + case RTL8367_RTL_NO_8367R: + chip_name = "8367R"; + break; + case RTL8367_RTL_NO_8367M: + chip_name = "8367M"; + break; + default: + dev_err(smi->parent, "unknown chip number (%04x)\n", rtl_no); + return -ENODEV; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367_RTL_VER_REG, &rtl_ver); + if (ret) { + dev_err(smi->parent, "unable to read chip version\n"); + return ret; + } + + dev_info(smi->parent, "RTL%s ver. %u chip found\n", + chip_name, rtl_ver & RTL8367_RTL_VER_MASK); + + return 0; +} + +static struct rtl8366_smi_ops rtl8367_smi_ops = { + .detect = rtl8367_detect, + .reset_chip = rtl8367_reset_chip, + .setup = rtl8367_setup, + + .mii_read = rtl8367_mii_read, + .mii_write = rtl8367_mii_write, + + .get_vlan_mc = rtl8367_get_vlan_mc, + .set_vlan_mc = rtl8367_set_vlan_mc, + .get_vlan_4k = rtl8367_get_vlan_4k, + .set_vlan_4k = rtl8367_set_vlan_4k, + .get_mc_index = rtl8367_get_mc_index, + .set_mc_index = rtl8367_set_mc_index, + .get_mib_counter = rtl8367_get_mib_counter, + .is_vlan_valid = rtl8367_is_vlan_valid, + .enable_vlan = rtl8367_enable_vlan, + .enable_vlan4k = rtl8367_enable_vlan4k, + .enable_port = rtl8367_enable_port, +}; + +static int rtl8367_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 1500; + smi->cmd_read = 0xb9; + smi->cmd_write = 0xb8; + smi->ops = &rtl8367_smi_ops; + smi->cpu_port = RTL8367_CPU_PORT_NUM; + smi->num_ports = RTL8367_NUM_PORTS; + smi->num_vlan_mc = RTL8367_NUM_VLANS; + smi->mib_counters = rtl8367_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8367_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8367_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8367_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8367_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +static void rtl8367_shutdown(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) + rtl8367_reset_chip(smi); +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8367_match[] = { + { .compatible = "realtek,rtl8367" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8367_match); +#endif + +static struct platform_driver rtl8367_driver = { + .driver = { + .name = RTL8367_DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8367_match), +#endif + }, + .probe = rtl8367_probe, + .remove = rtl8367_remove, + .shutdown = rtl8367_shutdown, +}; + +static int __init rtl8367_module_init(void) +{ + return platform_driver_register(&rtl8367_driver); +} +module_init(rtl8367_module_init); + +static void __exit rtl8367_module_exit(void) +{ + platform_driver_unregister(&rtl8367_driver); +} +module_exit(rtl8367_module_exit); + +MODULE_DESCRIPTION("Realtek RTL8367 ethernet switch driver"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8367_DRIVER_NAME); diff --git a/ipq806x/files-5.4/drivers/net/phy/rtl8367b.c b/ipq806x/files-5.4/drivers/net/phy/rtl8367b.c new file mode 100644 index 0000000..3599791 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/rtl8367b.c @@ -0,0 +1,1673 @@ +/* + * Platform driver for the Realtek RTL8367R-VB ethernet switches + * + * Copyright (C) 2012 Gabor Juhos + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtl8366_smi.h" + +#define RTL8367B_RESET_DELAY 1000 /* msecs*/ + +#define RTL8367B_PHY_ADDR_MAX 8 +#define RTL8367B_PHY_REG_MAX 31 + +#define RTL8367B_VID_MASK 0x3fff +#define RTL8367B_FID_MASK 0xf +#define RTL8367B_UNTAG_MASK 0xff +#define RTL8367B_MEMBER_MASK 0xff + +#define RTL8367B_PORT_MISC_CFG_REG(_p) (0x000e + 0x20 * (_p)) +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT 4 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK 0x3 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL 0 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_KEEP 1 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_PRI 2 +#define RTL8367B_PORT_MISC_CFG_EGRESS_MODE_REAL 3 + +#define RTL8367B_BYPASS_LINE_RATE_REG 0x03f7 + +#define RTL8367B_TA_CTRL_REG 0x0500 /*GOOD*/ +#define RTL8367B_TA_CTRL_SPA_SHIFT 8 +#define RTL8367B_TA_CTRL_SPA_MASK 0x7 +#define RTL8367B_TA_CTRL_METHOD BIT(4)/*GOOD*/ +#define RTL8367B_TA_CTRL_CMD_SHIFT 3 +#define RTL8367B_TA_CTRL_CMD_READ 0 +#define RTL8367B_TA_CTRL_CMD_WRITE 1 +#define RTL8367B_TA_CTRL_TABLE_SHIFT 0 /*GOOD*/ +#define RTL8367B_TA_CTRL_TABLE_ACLRULE 1 +#define RTL8367B_TA_CTRL_TABLE_ACLACT 2 +#define RTL8367B_TA_CTRL_TABLE_CVLAN 3 +#define RTL8367B_TA_CTRL_TABLE_L2 4 +#define RTL8367B_TA_CTRL_CVLAN_READ \ + ((RTL8367B_TA_CTRL_CMD_READ << RTL8367B_TA_CTRL_CMD_SHIFT) | \ + RTL8367B_TA_CTRL_TABLE_CVLAN) +#define RTL8367B_TA_CTRL_CVLAN_WRITE \ + ((RTL8367B_TA_CTRL_CMD_WRITE << RTL8367B_TA_CTRL_CMD_SHIFT) | \ + RTL8367B_TA_CTRL_TABLE_CVLAN) + +#define RTL8367B_TA_ADDR_REG 0x0501/*GOOD*/ +#define RTL8367B_TA_ADDR_MASK 0x3fff/*GOOD*/ + +#define RTL8367B_TA_LUT_REG 0x0502/*GOOD*/ + +#define RTL8367B_TA_WRDATA_REG(_x) (0x0510 + (_x))/*GOOD*/ +#define RTL8367B_TA_VLAN_NUM_WORDS 2 +#define RTL8367B_TA_VLAN_VID_MASK RTL8367B_VID_MASK +#define RTL8367B_TA_VLAN0_MEMBER_SHIFT 0 +#define RTL8367B_TA_VLAN0_MEMBER_MASK RTL8367B_MEMBER_MASK +#define RTL8367B_TA_VLAN0_UNTAG_SHIFT 8 +#define RTL8367B_TA_VLAN0_UNTAG_MASK RTL8367B_MEMBER_MASK +#define RTL8367B_TA_VLAN1_FID_SHIFT 0 +#define RTL8367B_TA_VLAN1_FID_MASK RTL8367B_FID_MASK + +#define RTL8367B_TA_RDDATA_REG(_x) (0x0520 + (_x))/*GOOD*/ + +#define RTL8367B_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p) / 2) /*GOOD*/ +#define RTL8367B_VLAN_PVID_CTRL_MASK 0x1f /*GOOD*/ +#define RTL8367B_VLAN_PVID_CTRL_SHIFT(_p) (8 * ((_p) % 2)) /*GOOD*/ + +#define RTL8367B_VLAN_MC_BASE(_x) (0x0728 + (_x) * 4) /*GOOD*/ +#define RTL8367B_VLAN_MC_NUM_WORDS 4 /*GOOD*/ +#define RTL8367B_VLAN_MC0_MEMBER_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC0_MEMBER_MASK RTL8367B_MEMBER_MASK/*GOOD*/ +#define RTL8367B_VLAN_MC1_FID_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC1_FID_MASK RTL8367B_FID_MASK/*GOOD*/ +#define RTL8367B_VLAN_MC3_EVID_SHIFT 0/*GOOD*/ +#define RTL8367B_VLAN_MC3_EVID_MASK RTL8367B_VID_MASK/*GOOD*/ + +#define RTL8367B_VLAN_CTRL_REG 0x07a8 /*GOOD*/ +#define RTL8367B_VLAN_CTRL_ENABLE BIT(0) + +#define RTL8367B_VLAN_INGRESS_REG 0x07a9 /*GOOD*/ + +#define RTL8367B_PORT_ISOLATION_REG(_p) (0x08a2 + (_p)) /*GOOD*/ + +#define RTL8367B_MIB_COUNTER_REG(_x) (0x1000 + (_x)) /*GOOD*/ +#define RTL8367B_MIB_COUNTER_PORT_OFFSET 0x007c /*GOOD*/ + +#define RTL8367B_MIB_ADDRESS_REG 0x1004 /*GOOD*/ + +#define RTL8367B_MIB_CTRL0_REG(_x) (0x1005 + (_x)) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK BIT(11) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_QM_RESET_MASK BIT(10) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_PORT_RESET_MASK(_p) BIT(2 + (_p)) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_RESET_MASK BIT(1) /*GOOD*/ +#define RTL8367B_MIB_CTRL0_BUSY_MASK BIT(0) /*GOOD*/ + +#define RTL8367B_SWC0_REG 0x1200/*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH_SHIFT 13/*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH(_x) ((_x) << 13) /*GOOD*/ +#define RTL8367B_SWC0_MAX_LENGTH_MASK RTL8367B_SWC0_MAX_LENGTH(0x3) +#define RTL8367B_SWC0_MAX_LENGTH_1522 RTL8367B_SWC0_MAX_LENGTH(0) +#define RTL8367B_SWC0_MAX_LENGTH_1536 RTL8367B_SWC0_MAX_LENGTH(1) +#define RTL8367B_SWC0_MAX_LENGTH_1552 RTL8367B_SWC0_MAX_LENGTH(2) +#define RTL8367B_SWC0_MAX_LENGTH_16000 RTL8367B_SWC0_MAX_LENGTH(3) + +#define RTL8367B_CHIP_NUMBER_REG 0x1300/*GOOD*/ + +#define RTL8367B_CHIP_VER_REG 0x1301/*GOOD*/ +#define RTL8367B_CHIP_VER_RLVID_SHIFT 12/*GOOD*/ +#define RTL8367B_CHIP_VER_RLVID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_MCID_SHIFT 8/*GOOD*/ +#define RTL8367B_CHIP_VER_MCID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_BOID_SHIFT 4/*GOOD*/ +#define RTL8367B_CHIP_VER_BOID_MASK 0xf/*GOOD*/ +#define RTL8367B_CHIP_VER_AFE_SHIFT 0/*GOOD*/ +#define RTL8367B_CHIP_VER_AFE_MASK 0x1/*GOOD*/ + +#define RTL8367B_CHIP_MODE_REG 0x1302 +#define RTL8367B_CHIP_MODE_MASK 0x7 + +#define RTL8367B_CHIP_DEBUG0_REG 0x1303 +#define RTL8367B_DEBUG0_SEL33(_x) BIT(8 + (_x)) +#define RTL8367B_DEBUG0_DRI_OTHER BIT(7) +#define RTL8367B_DEBUG0_DRI_RG(_x) BIT(5 + (_x)) +#define RTL8367B_DEBUG0_DRI(_x) BIT(3 + (_x)) +#define RTL8367B_DEBUG0_SLR_OTHER BIT(2) +#define RTL8367B_DEBUG0_SLR(_x) BIT(_x) + +#define RTL8367B_CHIP_DEBUG1_REG 0x1304 +#define RTL8367B_DEBUG1_DN_MASK(_x) \ + GENMASK(6 + (_x)*8, 4 + (_x)*8) +#define RTL8367B_DEBUG1_DN_SHIFT(_x) (4 + (_x) * 8) +#define RTL8367B_DEBUG1_DP_MASK(_x) \ + GENMASK(2 + (_x) * 8, (_x) * 8) +#define RTL8367B_DEBUG1_DP_SHIFT(_x) ((_x) * 8) + +#define RTL8367B_CHIP_DEBUG2_REG 0x13e2 +#define RTL8367B_DEBUG2_RG2_DN_MASK GENMASK(8, 6) +#define RTL8367B_DEBUG2_RG2_DN_SHIFT 6 +#define RTL8367B_DEBUG2_RG2_DP_MASK GENMASK(5, 3) +#define RTL8367B_DEBUG2_RG2_DP_SHIFT 3 +#define RTL8367B_DEBUG2_DRI_EXT2_RG BIT(2) +#define RTL8367B_DEBUG2_DRI_EXT2 BIT(1) +#define RTL8367B_DEBUG2_SLR_EXT2 BIT(0) + +#define RTL8367B_DIS_REG 0x1305 +#define RTL8367B_DIS_SKIP_MII_RXER(_x) BIT(12 + (_x)) +#define RTL8367B_DIS_RGMII_SHIFT(_x) (4 * (_x)) +#define RTL8367B_DIS_RGMII_MASK 0x7 + +#define RTL8367B_DIS2_REG 0x13c3 +#define RTL8367B_DIS2_SKIP_MII_RXER_SHIFT 4 +#define RTL8367B_DIS2_SKIP_MII_RXER 0x10 +#define RTL8367B_DIS2_RGMII_SHIFT 0 +#define RTL8367B_DIS2_RGMII_MASK 0xf + +#define RTL8367B_EXT_RGMXF_REG(_x) \ + ((_x) == 2 ? 0x13c5 : 0x1306 + (_x)) +#define RTL8367B_EXT_RGMXF_DUMMY0_SHIFT 5 +#define RTL8367B_EXT_RGMXF_DUMMY0_MASK 0x7ff +#define RTL8367B_EXT_RGMXF_TXDELAY_SHIFT 3 +#define RTL8367B_EXT_RGMXF_TXDELAY_MASK 1 +#define RTL8367B_EXT_RGMXF_RXDELAY_MASK 0x7 + +#define RTL8367B_DI_FORCE_REG(_x) \ + ((_x) == 2 ? 0x13c4 : 0x1310 + (_x)) +#define RTL8367B_DI_FORCE_MODE BIT(12) +#define RTL8367B_DI_FORCE_NWAY BIT(7) +#define RTL8367B_DI_FORCE_TXPAUSE BIT(6) +#define RTL8367B_DI_FORCE_RXPAUSE BIT(5) +#define RTL8367B_DI_FORCE_LINK BIT(4) +#define RTL8367B_DI_FORCE_DUPLEX BIT(2) +#define RTL8367B_DI_FORCE_SPEED_MASK 3 +#define RTL8367B_DI_FORCE_SPEED_10 0 +#define RTL8367B_DI_FORCE_SPEED_100 1 +#define RTL8367B_DI_FORCE_SPEED_1000 2 + +#define RTL8367B_MAC_FORCE_REG(_x) (0x1312 + (_x)) + +#define RTL8367B_CHIP_RESET_REG 0x1322 /*GOOD*/ +#define RTL8367B_CHIP_RESET_SW BIT(1) /*GOOD*/ +#define RTL8367B_CHIP_RESET_HW BIT(0) /*GOOD*/ + +#define RTL8367B_PORT_STATUS_REG(_p) (0x1352 + (_p)) /*GOOD*/ +#define RTL8367B_PORT_STATUS_EN_1000_SPI BIT(11) /*GOOD*/ +#define RTL8367B_PORT_STATUS_EN_100_SPI BIT(10)/*GOOD*/ +#define RTL8367B_PORT_STATUS_NWAY_FAULT BIT(9)/*GOOD*/ +#define RTL8367B_PORT_STATUS_LINK_MASTER BIT(8)/*GOOD*/ +#define RTL8367B_PORT_STATUS_NWAY BIT(7)/*GOOD*/ +#define RTL8367B_PORT_STATUS_TXPAUSE BIT(6)/*GOOD*/ +#define RTL8367B_PORT_STATUS_RXPAUSE BIT(5)/*GOOD*/ +#define RTL8367B_PORT_STATUS_LINK BIT(4)/*GOOD*/ +#define RTL8367B_PORT_STATUS_DUPLEX BIT(2)/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_MASK 0x0003/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_10 0/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_100 1/*GOOD*/ +#define RTL8367B_PORT_STATUS_SPEED_1000 2/*GOOD*/ + +#define RTL8367B_RTL_MAGIC_ID_REG 0x13c2 +#define RTL8367B_RTL_MAGIC_ID_VAL 0x0249 + +#define RTL8367B_IA_CTRL_REG 0x1f00 +#define RTL8367B_IA_CTRL_RW(_x) ((_x) << 1) +#define RTL8367B_IA_CTRL_RW_READ RTL8367B_IA_CTRL_RW(0) +#define RTL8367B_IA_CTRL_RW_WRITE RTL8367B_IA_CTRL_RW(1) +#define RTL8367B_IA_CTRL_CMD_MASK BIT(0) + +#define RTL8367B_IA_STATUS_REG 0x1f01 +#define RTL8367B_IA_STATUS_PHY_BUSY BIT(2) +#define RTL8367B_IA_STATUS_SDS_BUSY BIT(1) +#define RTL8367B_IA_STATUS_MDX_BUSY BIT(0) + +#define RTL8367B_IA_ADDRESS_REG 0x1f02 +#define RTL8367B_IA_WRITE_DATA_REG 0x1f03 +#define RTL8367B_IA_READ_DATA_REG 0x1f04 + +#define RTL8367B_INTERNAL_PHY_REG(_a, _r) (0x2000 + 32 * (_a) + (_r)) + +#define RTL8367B_NUM_MIB_COUNTERS 58 + +#define RTL8367B_CPU_PORT_NUM 5 +#define RTL8367B_NUM_PORTS 8 +#define RTL8367B_NUM_VLANS 32 +#define RTL8367B_NUM_VIDS 4096 +#define RTL8367B_PRIORITYMAX 7 +#define RTL8367B_FIDMAX 7 + +#define RTL8367B_PORT_0 BIT(0) +#define RTL8367B_PORT_1 BIT(1) +#define RTL8367B_PORT_2 BIT(2) +#define RTL8367B_PORT_3 BIT(3) +#define RTL8367B_PORT_4 BIT(4) +#define RTL8367B_PORT_E0 BIT(5) /* External port 0 */ +#define RTL8367B_PORT_E1 BIT(6) /* External port 1 */ +#define RTL8367B_PORT_E2 BIT(7) /* External port 2 */ + +#define RTL8367B_PORTS_ALL \ + (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ + RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E0 | \ + RTL8367B_PORT_E1 | RTL8367B_PORT_E2) + +#define RTL8367B_PORTS_ALL_BUT_CPU \ + (RTL8367B_PORT_0 | RTL8367B_PORT_1 | RTL8367B_PORT_2 | \ + RTL8367B_PORT_3 | RTL8367B_PORT_4 | RTL8367B_PORT_E1 | \ + RTL8367B_PORT_E2) + +struct rtl8367b_initval { + u16 reg; + u16 val; +}; + +#define RTL8367B_MIB_RXB_ID 0 /* IfInOctets */ +#define RTL8367B_MIB_TXB_ID 28 /* IfOutOctets */ + +static struct rtl8366_mib_counter +rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = { + {0, 0, 4, "ifInOctets" }, + {0, 4, 2, "dot3StatsFCSErrors" }, + {0, 6, 2, "dot3StatsSymbolErrors" }, + {0, 8, 2, "dot3InPauseFrames" }, + {0, 10, 2, "dot3ControlInUnknownOpcodes" }, + {0, 12, 2, "etherStatsFragments" }, + {0, 14, 2, "etherStatsJabbers" }, + {0, 16, 2, "ifInUcastPkts" }, + {0, 18, 2, "etherStatsDropEvents" }, + {0, 20, 2, "ifInMulticastPkts" }, + {0, 22, 2, "ifInBroadcastPkts" }, + {0, 24, 2, "inMldChecksumError" }, + {0, 26, 2, "inIgmpChecksumError" }, + {0, 28, 2, "inMldSpecificQuery" }, + {0, 30, 2, "inMldGeneralQuery" }, + {0, 32, 2, "inIgmpSpecificQuery" }, + {0, 34, 2, "inIgmpGeneralQuery" }, + {0, 36, 2, "inMldLeaves" }, + {0, 38, 2, "inIgmpLeaves" }, + + {0, 40, 4, "etherStatsOctets" }, + {0, 44, 2, "etherStatsUnderSizePkts" }, + {0, 46, 2, "etherOversizeStats" }, + {0, 48, 2, "etherStatsPkts64Octets" }, + {0, 50, 2, "etherStatsPkts65to127Octets" }, + {0, 52, 2, "etherStatsPkts128to255Octets" }, + {0, 54, 2, "etherStatsPkts256to511Octets" }, + {0, 56, 2, "etherStatsPkts512to1023Octets" }, + {0, 58, 2, "etherStatsPkts1024to1518Octets" }, + + {0, 60, 4, "ifOutOctets" }, + {0, 64, 2, "dot3StatsSingleCollisionFrames" }, + {0, 66, 2, "dot3StatMultipleCollisionFrames" }, + {0, 68, 2, "dot3sDeferredTransmissions" }, + {0, 70, 2, "dot3StatsLateCollisions" }, + {0, 72, 2, "etherStatsCollisions" }, + {0, 74, 2, "dot3StatsExcessiveCollisions" }, + {0, 76, 2, "dot3OutPauseFrames" }, + {0, 78, 2, "ifOutDiscards" }, + {0, 80, 2, "dot1dTpPortInDiscards" }, + {0, 82, 2, "ifOutUcastPkts" }, + {0, 84, 2, "ifOutMulticastPkts" }, + {0, 86, 2, "ifOutBroadcastPkts" }, + {0, 88, 2, "outOampduPkts" }, + {0, 90, 2, "inOampduPkts" }, + {0, 92, 2, "inIgmpJoinsSuccess" }, + {0, 94, 2, "inIgmpJoinsFail" }, + {0, 96, 2, "inMldJoinsSuccess" }, + {0, 98, 2, "inMldJoinsFail" }, + {0, 100, 2, "inReportSuppressionDrop" }, + {0, 102, 2, "inLeaveSuppressionDrop" }, + {0, 104, 2, "outIgmpReports" }, + {0, 106, 2, "outIgmpLeaves" }, + {0, 108, 2, "outIgmpGeneralQuery" }, + {0, 110, 2, "outIgmpSpecificQuery" }, + {0, 112, 2, "outMldReports" }, + {0, 114, 2, "outMldLeaves" }, + {0, 116, 2, "outMldGeneralQuery" }, + {0, 118, 2, "outMldSpecificQuery" }, + {0, 120, 2, "inKnownMulticastPkts" }, +}; + +#define REG_RD(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_read_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_WR(_smi, _reg, _val) \ + do { \ + err = rtl8366_smi_write_reg(_smi, _reg, _val); \ + if (err) \ + return err; \ + } while (0) + +#define REG_RMW(_smi, _reg, _mask, _val) \ + do { \ + err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ + if (err) \ + return err; \ + } while (0) + +static const struct rtl8367b_initval rtl8367r_vb_initvals_0[] = { + {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x0301, 0x0026}, {0x1722, 0x0E14}, + {0x205F, 0x0002}, {0x2059, 0x1A00}, {0x205F, 0x0000}, {0x207F, 0x0002}, + {0x2077, 0x0000}, {0x2078, 0x0000}, {0x2079, 0x0000}, {0x207A, 0x0000}, + {0x207B, 0x0000}, {0x207F, 0x0000}, {0x205F, 0x0002}, {0x2053, 0x0000}, + {0x2054, 0x0000}, {0x2055, 0x0000}, {0x2056, 0x0000}, {0x2057, 0x0000}, + {0x205F, 0x0000}, {0x12A4, 0x110A}, {0x12A6, 0x150A}, {0x13F1, 0x0013}, + {0x13F4, 0x0010}, {0x13F5, 0x0000}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, + {0x0058, 0x0F00}, {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x12B6, 0x0C02}, + {0x12B7, 0x030F}, {0x12B8, 0x11FF}, {0x12BC, 0x0004}, {0x1362, 0x0115}, + {0x1363, 0x0002}, {0x1363, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, + {0x221F, 0x0007}, {0x221E, 0x002D}, {0x2218, 0xF030}, {0x221F, 0x0007}, + {0x221E, 0x0023}, {0x2216, 0x0005}, {0x2215, 0x00B9}, {0x2219, 0x0044}, + {0x2215, 0x00BA}, {0x2219, 0x0020}, {0x2215, 0x00BB}, {0x2219, 0x00C1}, + {0x2215, 0x0148}, {0x2219, 0x0096}, {0x2215, 0x016E}, {0x2219, 0x0026}, + {0x2216, 0x0000}, {0x2216, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, + {0x221F, 0x0007}, {0x221E, 0x0020}, {0x2215, 0x0D00}, {0x221F, 0x0000}, + {0x221F, 0x0000}, {0x2217, 0x2160}, {0x221F, 0x0001}, {0x2210, 0xF25E}, + {0x221F, 0x0007}, {0x221E, 0x0042}, {0x2215, 0x0F00}, {0x2215, 0x0F00}, + {0x2216, 0x7408}, {0x2215, 0x0E00}, {0x2215, 0x0F00}, {0x2215, 0x0F01}, + {0x2216, 0x4000}, {0x2215, 0x0E01}, {0x2215, 0x0F01}, {0x2215, 0x0F02}, + {0x2216, 0x9400}, {0x2215, 0x0E02}, {0x2215, 0x0F02}, {0x2215, 0x0F03}, + {0x2216, 0x7408}, {0x2215, 0x0E03}, {0x2215, 0x0F03}, {0x2215, 0x0F04}, + {0x2216, 0x4008}, {0x2215, 0x0E04}, {0x2215, 0x0F04}, {0x2215, 0x0F05}, + {0x2216, 0x9400}, {0x2215, 0x0E05}, {0x2215, 0x0F05}, {0x2215, 0x0F06}, + {0x2216, 0x0803}, {0x2215, 0x0E06}, {0x2215, 0x0F06}, {0x2215, 0x0D00}, + {0x2215, 0x0100}, {0x221F, 0x0001}, {0x2210, 0xF05E}, {0x221F, 0x0000}, + {0x2217, 0x2100}, {0x221F, 0x0000}, {0x220D, 0x0003}, {0x220E, 0x0015}, + {0x220D, 0x4003}, {0x220E, 0x0006}, {0x221F, 0x0000}, {0x2200, 0x1340}, + {0x133F, 0x0010}, {0x12A0, 0x0058}, {0x12A1, 0x0058}, {0x133E, 0x000E}, + {0x133F, 0x0030}, {0x221F, 0x0000}, {0x2210, 0x0166}, {0x221F, 0x0000}, + {0x133E, 0x000E}, {0x133F, 0x0010}, {0x133F, 0x0030}, {0x133E, 0x000E}, + {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8B6E}, + {0x2206, 0x0000}, {0x220F, 0x0100}, {0x2205, 0x8000}, {0x2206, 0x0280}, + {0x2206, 0x28F7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080}, + {0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201}, + {0x2206, 0x6602}, {0x2206, 0x80B9}, {0x2206, 0xE08B}, {0x2206, 0x8CE1}, + {0x2206, 0x8B8D}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x8E1E}, + {0x2206, 0x01A0}, {0x2206, 0x00E7}, {0x2206, 0xAEDB}, {0x2206, 0xEEE0}, + {0x2206, 0x120E}, {0x2206, 0xEEE0}, {0x2206, 0x1300}, {0x2206, 0xEEE0}, + {0x2206, 0x2001}, {0x2206, 0xEEE0}, {0x2206, 0x2166}, {0x2206, 0xEEE0}, + {0x2206, 0xC463}, {0x2206, 0xEEE0}, {0x2206, 0xC5E8}, {0x2206, 0xEEE0}, + {0x2206, 0xC699}, {0x2206, 0xEEE0}, {0x2206, 0xC7C2}, {0x2206, 0xEEE0}, + {0x2206, 0xC801}, {0x2206, 0xEEE0}, {0x2206, 0xC913}, {0x2206, 0xEEE0}, + {0x2206, 0xCA30}, {0x2206, 0xEEE0}, {0x2206, 0xCB3E}, {0x2206, 0xEEE0}, + {0x2206, 0xDCE1}, {0x2206, 0xEEE0}, {0x2206, 0xDD00}, {0x2206, 0xEEE2}, + {0x2206, 0x0001}, {0x2206, 0xEEE2}, {0x2206, 0x0100}, {0x2206, 0xEEE4}, + {0x2206, 0x8860}, {0x2206, 0xEEE4}, {0x2206, 0x8902}, {0x2206, 0xEEE4}, + {0x2206, 0x8C00}, {0x2206, 0xEEE4}, {0x2206, 0x8D30}, {0x2206, 0xEEEA}, + {0x2206, 0x1480}, {0x2206, 0xEEEA}, {0x2206, 0x1503}, {0x2206, 0xEEEA}, + {0x2206, 0xC600}, {0x2206, 0xEEEA}, {0x2206, 0xC706}, {0x2206, 0xEE85}, + {0x2206, 0xEE00}, {0x2206, 0xEE85}, {0x2206, 0xEF00}, {0x2206, 0xEE8B}, + {0x2206, 0x6750}, {0x2206, 0xEE8B}, {0x2206, 0x6632}, {0x2206, 0xEE8A}, + {0x2206, 0xD448}, {0x2206, 0xEE8A}, {0x2206, 0xD548}, {0x2206, 0xEE8A}, + {0x2206, 0xD649}, {0x2206, 0xEE8A}, {0x2206, 0xD7F8}, {0x2206, 0xEE8B}, + {0x2206, 0x85E2}, {0x2206, 0xEE8B}, {0x2206, 0x8700}, {0x2206, 0xEEFF}, + {0x2206, 0xF600}, {0x2206, 0xEEFF}, {0x2206, 0xF7FC}, {0x2206, 0x04F8}, + {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2023}, {0x2206, 0xF620}, + {0x2206, 0xE48B}, {0x2206, 0x8E02}, {0x2206, 0x2877}, {0x2206, 0x0225}, + {0x2206, 0xC702}, {0x2206, 0x26A1}, {0x2206, 0x0281}, {0x2206, 0xB302}, + {0x2206, 0x8496}, {0x2206, 0x0202}, {0x2206, 0xA102}, {0x2206, 0x27F1}, + {0x2206, 0x0228}, {0x2206, 0xF902}, {0x2206, 0x2AA0}, {0x2206, 0x0282}, + {0x2206, 0xB8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD21}, {0x2206, 0x08F6}, + {0x2206, 0x21E4}, {0x2206, 0x8B8E}, {0x2206, 0x0202}, {0x2206, 0x80E0}, + {0x2206, 0x8B8E}, {0x2206, 0xAD22}, {0x2206, 0x05F6}, {0x2206, 0x22E4}, + {0x2206, 0x8B8E}, {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2305}, + {0x2206, 0xF623}, {0x2206, 0xE48B}, {0x2206, 0x8EE0}, {0x2206, 0x8B8E}, + {0x2206, 0xAD24}, {0x2206, 0x08F6}, {0x2206, 0x24E4}, {0x2206, 0x8B8E}, + {0x2206, 0x0227}, {0x2206, 0x6AE0}, {0x2206, 0x8B8E}, {0x2206, 0xAD25}, + {0x2206, 0x05F6}, {0x2206, 0x25E4}, {0x2206, 0x8B8E}, {0x2206, 0xE08B}, + {0x2206, 0x8EAD}, {0x2206, 0x260B}, {0x2206, 0xF626}, {0x2206, 0xE48B}, + {0x2206, 0x8E02}, {0x2206, 0x830D}, {0x2206, 0x021D}, {0x2206, 0x6BE0}, + {0x2206, 0x8B8E}, {0x2206, 0xAD27}, {0x2206, 0x05F6}, {0x2206, 0x27E4}, + {0x2206, 0x8B8E}, {0x2206, 0x0281}, {0x2206, 0x4402}, {0x2206, 0x045C}, + {0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B83}, {0x2206, 0xAD23}, + {0x2206, 0x30E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x2359}, + {0x2206, 0x02E0}, {0x2206, 0x85EF}, {0x2206, 0xE585}, {0x2206, 0xEFAC}, + {0x2206, 0x2907}, {0x2206, 0x1F01}, {0x2206, 0x9E51}, {0x2206, 0xAD29}, + {0x2206, 0x20E0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x06E1}, + {0x2206, 0x8B84}, {0x2206, 0xAD28}, {0x2206, 0x42E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD21}, {0x2206, 0x06E1}, {0x2206, 0x8B84}, {0x2206, 0xAD29}, + {0x2206, 0x36BF}, {0x2206, 0x34BF}, {0x2206, 0x022C}, {0x2206, 0x31AE}, + {0x2206, 0x2EE0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x10E0}, + {0x2206, 0x8B84}, {0x2206, 0xF620}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, + {0x2206, 0x8ADA}, {0x2206, 0x00EE}, {0x2206, 0x8ADB}, {0x2206, 0x00E0}, + {0x2206, 0x8B85}, {0x2206, 0xAD21}, {0x2206, 0x0CE0}, {0x2206, 0x8B84}, + {0x2206, 0xF621}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, {0x2206, 0x8B72}, + {0x2206, 0xFFBF}, {0x2206, 0x34C2}, {0x2206, 0x022C}, {0x2206, 0x31FC}, + {0x2206, 0x04F8}, {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD21}, {0x2206, 0x42E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, + {0x2206, 0x2358}, {0x2206, 0xC059}, {0x2206, 0x021E}, {0x2206, 0x01E1}, + {0x2206, 0x8B72}, {0x2206, 0x1F10}, {0x2206, 0x9E2F}, {0x2206, 0xE48B}, + {0x2206, 0x72AD}, {0x2206, 0x2123}, {0x2206, 0xE18B}, {0x2206, 0x84F7}, + {0x2206, 0x29E5}, {0x2206, 0x8B84}, {0x2206, 0xAC27}, {0x2206, 0x10AC}, + {0x2206, 0x2605}, {0x2206, 0x0205}, {0x2206, 0x23AE}, {0x2206, 0x1602}, + {0x2206, 0x0535}, {0x2206, 0x0282}, {0x2206, 0x30AE}, {0x2206, 0x0E02}, + {0x2206, 0x056A}, {0x2206, 0x0282}, {0x2206, 0x75AE}, {0x2206, 0x0602}, + {0x2206, 0x04DC}, {0x2206, 0x0282}, {0x2206, 0x04EF}, {0x2206, 0x96FE}, + {0x2206, 0xFC04}, {0x2206, 0xF8F9}, {0x2206, 0xE08B}, {0x2206, 0x87AD}, + {0x2206, 0x2321}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15}, + {0x2206, 0xAD26}, {0x2206, 0x18F6}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15F6}, {0x2206, 0x26E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8F9}, + {0x2206, 0xE08B}, {0x2206, 0x87AD}, {0x2206, 0x233A}, {0x2206, 0xAD22}, + {0x2206, 0x37E0}, {0x2206, 0xE020}, {0x2206, 0xE1E0}, {0x2206, 0x21AC}, + {0x2206, 0x212E}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15}, + {0x2206, 0xF627}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, + {0x2206, 0xE2EA}, {0x2206, 0x12E3}, {0x2206, 0xEA13}, {0x2206, 0x5A8F}, + {0x2206, 0x6A20}, {0x2206, 0xE6EA}, {0x2206, 0x12E7}, {0x2206, 0xEA13}, + {0x2206, 0xF726}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, + {0x2206, 0xF727}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, + {0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B87}, + {0x2206, 0xAD23}, {0x2206, 0x38AD}, {0x2206, 0x2135}, {0x2206, 0xE0E0}, + {0x2206, 0x20E1}, {0x2206, 0xE021}, {0x2206, 0xAC21}, {0x2206, 0x2CE0}, + {0x2206, 0xEA14}, {0x2206, 0xE1EA}, {0x2206, 0x15F6}, {0x2206, 0x27E4}, + {0x2206, 0xEA14}, {0x2206, 0xE5EA}, {0x2206, 0x15E2}, {0x2206, 0xEA12}, + {0x2206, 0xE3EA}, {0x2206, 0x135A}, {0x2206, 0x8FE6}, {0x2206, 0xEA12}, + {0x2206, 0xE7EA}, {0x2206, 0x13F7}, {0x2206, 0x26E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, + {0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2146}, + {0x2206, 0xE0E0}, {0x2206, 0x22E1}, {0x2206, 0xE023}, {0x2206, 0x58C0}, + {0x2206, 0x5902}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x651F}, + {0x2206, 0x109E}, {0x2206, 0x33E4}, {0x2206, 0x8B65}, {0x2206, 0xAD21}, + {0x2206, 0x22AD}, {0x2206, 0x272A}, {0x2206, 0xD400}, {0x2206, 0x01BF}, + {0x2206, 0x34F2}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, {0x2206, 0x34F5}, + {0x2206, 0x022C}, {0x2206, 0xE0E0}, {0x2206, 0x8B67}, {0x2206, 0x1B10}, + {0x2206, 0xAA14}, {0x2206, 0xE18B}, {0x2206, 0x660D}, {0x2206, 0x1459}, + {0x2206, 0x0FAE}, {0x2206, 0x05E1}, {0x2206, 0x8B66}, {0x2206, 0x590F}, + {0x2206, 0xBF85}, {0x2206, 0x6102}, {0x2206, 0x2CA2}, {0x2206, 0xEF96}, + {0x2206, 0xFEFC}, {0x2206, 0x04F8}, {0x2206, 0xF9FA}, {0x2206, 0xFBEF}, + {0x2206, 0x79E2}, {0x2206, 0x8AD2}, {0x2206, 0xAC19}, {0x2206, 0x2DE0}, + {0x2206, 0xE036}, {0x2206, 0xE1E0}, {0x2206, 0x37EF}, {0x2206, 0x311F}, + {0x2206, 0x325B}, {0x2206, 0x019E}, {0x2206, 0x1F7A}, {0x2206, 0x0159}, + {0x2206, 0x019F}, {0x2206, 0x0ABF}, {0x2206, 0x348E}, {0x2206, 0x022C}, + {0x2206, 0x31F6}, {0x2206, 0x06AE}, {0x2206, 0x0FF6}, {0x2206, 0x0302}, + {0x2206, 0x0470}, {0x2206, 0xF703}, {0x2206, 0xF706}, {0x2206, 0xBF34}, + {0x2206, 0x9302}, {0x2206, 0x2C31}, {0x2206, 0xAC1A}, {0x2206, 0x25E0}, + {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x23EF}, {0x2206, 0x300D}, + {0x2206, 0x311F}, {0x2206, 0x325B}, {0x2206, 0x029E}, {0x2206, 0x157A}, + {0x2206, 0x0258}, {0x2206, 0xC4A0}, {0x2206, 0x0408}, {0x2206, 0xBF34}, + {0x2206, 0x9E02}, {0x2206, 0x2C31}, {0x2206, 0xAE06}, {0x2206, 0xBF34}, + {0x2206, 0x9C02}, {0x2206, 0x2C31}, {0x2206, 0xAC1B}, {0x2206, 0x4AE0}, + {0x2206, 0xE012}, {0x2206, 0xE1E0}, {0x2206, 0x13EF}, {0x2206, 0x300D}, + {0x2206, 0x331F}, {0x2206, 0x325B}, {0x2206, 0x1C9E}, {0x2206, 0x3AEF}, + {0x2206, 0x325B}, {0x2206, 0x1C9F}, {0x2206, 0x09BF}, {0x2206, 0x3498}, + {0x2206, 0x022C}, {0x2206, 0x3102}, {0x2206, 0x83C5}, {0x2206, 0x5A03}, + {0x2206, 0x0D03}, {0x2206, 0x581C}, {0x2206, 0x1E20}, {0x2206, 0x0207}, + {0x2206, 0xA0A0}, {0x2206, 0x000E}, {0x2206, 0x0284}, {0x2206, 0x17AD}, + {0x2206, 0x1817}, {0x2206, 0xBF34}, {0x2206, 0x9A02}, {0x2206, 0x2C31}, + {0x2206, 0xAE0F}, {0x2206, 0xBF34}, {0x2206, 0xC802}, {0x2206, 0x2C31}, + {0x2206, 0xBF34}, {0x2206, 0xC502}, {0x2206, 0x2C31}, {0x2206, 0x0284}, + {0x2206, 0x52E6}, {0x2206, 0x8AD2}, {0x2206, 0xEF97}, {0x2206, 0xFFFE}, + {0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xBF34}, {0x2206, 0xDA02}, + {0x2206, 0x2CE0}, {0x2206, 0xE58A}, {0x2206, 0xD3BF}, {0x2206, 0x34D4}, + {0x2206, 0x022C}, {0x2206, 0xE00C}, {0x2206, 0x1159}, {0x2206, 0x02E0}, + {0x2206, 0x8AD3}, {0x2206, 0x1E01}, {0x2206, 0xE48A}, {0x2206, 0xD3D1}, + {0x2206, 0x00BF}, {0x2206, 0x34DA}, {0x2206, 0x022C}, {0x2206, 0xA2D1}, + {0x2206, 0x01BF}, {0x2206, 0x34D4}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, + {0x2206, 0x34CB}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, {0x2206, 0x8ACE}, + {0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CE0}, {0x2206, 0xE58A}, + {0x2206, 0xCFBF}, {0x2206, 0x8564}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, + {0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, {0x2206, 0x2CE0}, + {0x2206, 0xE58A}, {0x2206, 0xD1FC}, {0x2206, 0x04F8}, {0x2206, 0xE18A}, + {0x2206, 0xD1BF}, {0x2206, 0x856A}, {0x2206, 0x022C}, {0x2206, 0xA2E1}, + {0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2}, + {0x2206, 0xE18A}, {0x2206, 0xCFBF}, {0x2206, 0x8567}, {0x2206, 0x022C}, + {0x2206, 0xA2E1}, {0x2206, 0x8ACE}, {0x2206, 0xBF34}, {0x2206, 0xCB02}, + {0x2206, 0x2CA2}, {0x2206, 0xE18A}, {0x2206, 0xD3BF}, {0x2206, 0x34DA}, + {0x2206, 0x022C}, {0x2206, 0xA2E1}, {0x2206, 0x8AD3}, {0x2206, 0x0D11}, + {0x2206, 0xBF34}, {0x2206, 0xD402}, {0x2206, 0x2CA2}, {0x2206, 0xFC04}, + {0x2206, 0xF9A0}, {0x2206, 0x0405}, {0x2206, 0xE38A}, {0x2206, 0xD4AE}, + {0x2206, 0x13A0}, {0x2206, 0x0805}, {0x2206, 0xE38A}, {0x2206, 0xD5AE}, + {0x2206, 0x0BA0}, {0x2206, 0x0C05}, {0x2206, 0xE38A}, {0x2206, 0xD6AE}, + {0x2206, 0x03E3}, {0x2206, 0x8AD7}, {0x2206, 0xEF13}, {0x2206, 0xBF34}, + {0x2206, 0xCB02}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, {0x2206, 0x0D11}, + {0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, + {0x2206, 0x0D14}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2}, + {0x2206, 0xEF13}, {0x2206, 0x0D17}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, + {0x2206, 0x2CA2}, {0x2206, 0xFD04}, {0x2206, 0xF8E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD27}, {0x2206, 0x2DE0}, {0x2206, 0xE036}, {0x2206, 0xE1E0}, + {0x2206, 0x37E1}, {0x2206, 0x8B73}, {0x2206, 0x1F10}, {0x2206, 0x9E20}, + {0x2206, 0xE48B}, {0x2206, 0x73AC}, {0x2206, 0x200B}, {0x2206, 0xAC21}, + {0x2206, 0x0DAC}, {0x2206, 0x250F}, {0x2206, 0xAC27}, {0x2206, 0x0EAE}, + {0x2206, 0x0F02}, {0x2206, 0x84CC}, {0x2206, 0xAE0A}, {0x2206, 0x0284}, + {0x2206, 0xD1AE}, {0x2206, 0x05AE}, {0x2206, 0x0302}, {0x2206, 0x84D8}, + {0x2206, 0xFC04}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0x0402}, + {0x2206, 0x84E5}, {0x2206, 0x0285}, {0x2206, 0x2804}, {0x2206, 0x0285}, + {0x2206, 0x4904}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0xEE8B}, + {0x2206, 0x6902}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B85}, + {0x2206, 0xAD26}, {0x2206, 0x38D0}, {0x2206, 0x0B02}, {0x2206, 0x2B4D}, + {0x2206, 0x5882}, {0x2206, 0x7882}, {0x2206, 0x9F2D}, {0x2206, 0xE08B}, + {0x2206, 0x68E1}, {0x2206, 0x8B69}, {0x2206, 0x1F10}, {0x2206, 0x9EC8}, + {0x2206, 0x10E4}, {0x2206, 0x8B68}, {0x2206, 0xE0E0}, {0x2206, 0x00E1}, + {0x2206, 0xE001}, {0x2206, 0xF727}, {0x2206, 0xE4E0}, {0x2206, 0x00E5}, + {0x2206, 0xE001}, {0x2206, 0xE2E0}, {0x2206, 0x20E3}, {0x2206, 0xE021}, + {0x2206, 0xAD30}, {0x2206, 0xF7F6}, {0x2206, 0x27E4}, {0x2206, 0xE000}, + {0x2206, 0xE5E0}, {0x2206, 0x01FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA}, + {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2212}, + {0x2206, 0xE0E0}, {0x2206, 0x14E1}, {0x2206, 0xE015}, {0x2206, 0xAD26}, + {0x2206, 0x9CE1}, {0x2206, 0x85E0}, {0x2206, 0xBF85}, {0x2206, 0x6D02}, + {0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x04F8}, + {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B86}, {0x2206, 0xAD22}, + {0x2206, 0x09E1}, {0x2206, 0x85E1}, {0x2206, 0xBF85}, {0x2206, 0x6D02}, + {0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x0464}, + {0x2206, 0xE48C}, {0x2206, 0xFDE4}, {0x2206, 0x80CA}, {0x2206, 0xE480}, + {0x2206, 0x66E0}, {0x2206, 0x8E70}, {0x2206, 0xE076}, {0x2205, 0xE142}, + {0x2206, 0x0701}, {0x2205, 0xE140}, {0x2206, 0x0405}, {0x220F, 0x0000}, + {0x221F, 0x0000}, {0x2200, 0x1340}, {0x133E, 0x000E}, {0x133F, 0x0010}, + {0x13EB, 0x11BB} +}; + +static const struct rtl8367b_initval rtl8367r_vb_initvals_1[] = { + {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x1305, 0xC000}, {0x121E, 0x03CA}, + {0x1233, 0x0352}, {0x1234, 0x0064}, {0x1237, 0x0096}, {0x1238, 0x0078}, + {0x1239, 0x0084}, {0x123A, 0x0030}, {0x205F, 0x0002}, {0x2059, 0x1A00}, + {0x205F, 0x0000}, {0x207F, 0x0002}, {0x2077, 0x0000}, {0x2078, 0x0000}, + {0x2079, 0x0000}, {0x207A, 0x0000}, {0x207B, 0x0000}, {0x207F, 0x0000}, + {0x205F, 0x0002}, {0x2053, 0x0000}, {0x2054, 0x0000}, {0x2055, 0x0000}, + {0x2056, 0x0000}, {0x2057, 0x0000}, {0x205F, 0x0000}, {0x133F, 0x0030}, + {0x133E, 0x000E}, {0x221F, 0x0005}, {0x2205, 0x8B86}, {0x2206, 0x800E}, + {0x221F, 0x0000}, {0x133F, 0x0010}, {0x12A3, 0x2200}, {0x6107, 0xE58B}, + {0x6103, 0xA970}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, {0x0058, 0x0F00}, + {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x133F, 0x0030}, {0x133E, 0x000E}, + {0x221F, 0x0005}, {0x2205, 0x8B6E}, {0x2206, 0x0000}, {0x220F, 0x0100}, + {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8000}, {0x2206, 0x0280}, + {0x2206, 0x2BF7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080}, + {0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201}, + {0x2206, 0x6602}, {0x2206, 0x8044}, {0x2206, 0x0201}, {0x2206, 0x7CE0}, + {0x2206, 0x8B8C}, {0x2206, 0xE18B}, {0x2206, 0x8D1E}, {0x2206, 0x01E1}, + {0x2206, 0x8B8E}, {0x2206, 0x1E01}, {0x2206, 0xA000}, {0x2206, 0xE4AE}, + {0x2206, 0xD8EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, {0x2206, 0x85C1}, + {0x2206, 0x00EE}, {0x2206, 0x8AFC}, {0x2206, 0x07EE}, {0x2206, 0x8AFD}, + {0x2206, 0x73EE}, {0x2206, 0xFFF6}, {0x2206, 0x00EE}, {0x2206, 0xFFF7}, + {0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD20}, + {0x2206, 0x0302}, {0x2206, 0x8050}, {0x2206, 0xFC04}, {0x2206, 0xF8F9}, + {0x2206, 0xE08B}, {0x2206, 0x85AD}, {0x2206, 0x2548}, {0x2206, 0xE08A}, + {0x2206, 0xE4E1}, {0x2206, 0x8AE5}, {0x2206, 0x7C00}, {0x2206, 0x009E}, + {0x2206, 0x35EE}, {0x2206, 0x8AE4}, {0x2206, 0x00EE}, {0x2206, 0x8AE5}, + {0x2206, 0x00E0}, {0x2206, 0x8AFC}, {0x2206, 0xE18A}, {0x2206, 0xFDE2}, + {0x2206, 0x85C0}, {0x2206, 0xE385}, {0x2206, 0xC102}, {0x2206, 0x2DAC}, + {0x2206, 0xAD20}, {0x2206, 0x12EE}, {0x2206, 0x8AE4}, {0x2206, 0x03EE}, + {0x2206, 0x8AE5}, {0x2206, 0xB7EE}, {0x2206, 0x85C0}, {0x2206, 0x00EE}, + {0x2206, 0x85C1}, {0x2206, 0x00AE}, {0x2206, 0x1115}, {0x2206, 0xE685}, + {0x2206, 0xC0E7}, {0x2206, 0x85C1}, {0x2206, 0xAE08}, {0x2206, 0xEE85}, + {0x2206, 0xC000}, {0x2206, 0xEE85}, {0x2206, 0xC100}, {0x2206, 0xFDFC}, + {0x2206, 0x0400}, {0x2205, 0xE142}, {0x2206, 0x0701}, {0x2205, 0xE140}, + {0x2206, 0x0405}, {0x220F, 0x0000}, {0x221F, 0x0000}, {0x133E, 0x000E}, + {0x133F, 0x0010}, {0x13EB, 0x11BB}, {0x207F, 0x0002}, {0x2073, 0x1D22}, + {0x207F, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, {0x2200, 0x1340}, + {0x133E, 0x000E}, {0x133F, 0x0010}, +}; + +static int rtl8367b_write_initvals(struct rtl8366_smi *smi, + const struct rtl8367b_initval *initvals, + int count) +{ + int err; + int i; + + for (i = 0; i < count; i++) + REG_WR(smi, initvals[i].reg, initvals[i].val); + + return 0; +} + +static int rtl8367b_read_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 *val) +{ + int timeout; + u32 data; + int err; + + if (phy_addr > RTL8367B_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367B_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if (data & RTL8367B_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* prepare address */ + REG_WR(smi, RTL8367B_IA_ADDRESS_REG, + RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send read command */ + REG_WR(smi, RTL8367B_IA_CTRL_REG, + RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_READ); + + timeout = 5; + do { + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy read timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + /* read data */ + REG_RD(smi, RTL8367B_IA_READ_DATA_REG, val); + + dev_dbg(smi->parent, "phy_read: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, *val); + return 0; +} + +static int rtl8367b_write_phy_reg(struct rtl8366_smi *smi, + u32 phy_addr, u32 phy_reg, u32 val) +{ + int timeout; + u32 data; + int err; + + dev_dbg(smi->parent, "phy_write: addr:%02x, reg:%02x, val:%04x\n", + phy_addr, phy_reg, val); + + if (phy_addr > RTL8367B_PHY_ADDR_MAX) + return -EINVAL; + + if (phy_reg > RTL8367B_PHY_REG_MAX) + return -EINVAL; + + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if (data & RTL8367B_IA_STATUS_PHY_BUSY) + return -ETIMEDOUT; + + /* preapre data */ + REG_WR(smi, RTL8367B_IA_WRITE_DATA_REG, val); + + /* prepare address */ + REG_WR(smi, RTL8367B_IA_ADDRESS_REG, + RTL8367B_INTERNAL_PHY_REG(phy_addr, phy_reg)); + + /* send write command */ + REG_WR(smi, RTL8367B_IA_CTRL_REG, + RTL8367B_IA_CTRL_CMD_MASK | RTL8367B_IA_CTRL_RW_WRITE); + + timeout = 5; + do { + REG_RD(smi, RTL8367B_IA_STATUS_REG, &data); + if ((data & RTL8367B_IA_STATUS_PHY_BUSY) == 0) + break; + + if (timeout--) { + dev_err(smi->parent, "phy write timed out\n"); + return -ETIMEDOUT; + } + + udelay(1); + } while (1); + + return 0; +} + +static int rtl8367b_init_regs(struct rtl8366_smi *smi) +{ + const struct rtl8367b_initval *initvals; + u32 chip_ver; + u32 rlvid; + int count; + int err; + + REG_WR(smi, RTL8367B_RTL_MAGIC_ID_REG, RTL8367B_RTL_MAGIC_ID_VAL); + REG_RD(smi, RTL8367B_CHIP_VER_REG, &chip_ver); + + rlvid = (chip_ver >> RTL8367B_CHIP_VER_RLVID_SHIFT) & + RTL8367B_CHIP_VER_RLVID_MASK; + + switch (rlvid) { + case 0: + initvals = rtl8367r_vb_initvals_0; + count = ARRAY_SIZE(rtl8367r_vb_initvals_0); + break; + + case 1: + initvals = rtl8367r_vb_initvals_1; + count = ARRAY_SIZE(rtl8367r_vb_initvals_1); + break; + + default: + dev_err(smi->parent, "unknow rlvid %u\n", rlvid); + return -ENODEV; + } + + /* TODO: disable RLTP */ + + return rtl8367b_write_initvals(smi, initvals, count); +} + +static int rtl8367b_reset_chip(struct rtl8366_smi *smi) +{ + int timeout = 10; + int err; + u32 data; + + REG_WR(smi, RTL8367B_CHIP_RESET_REG, RTL8367B_CHIP_RESET_HW); + msleep(RTL8367B_RESET_DELAY); + + do { + REG_RD(smi, RTL8367B_CHIP_RESET_REG, &data); + if (!(data & RTL8367B_CHIP_RESET_HW)) + break; + + msleep(1); + } while (--timeout); + + if (!timeout) { + dev_err(smi->parent, "chip reset timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id, + enum rtl8367_extif_mode mode) +{ + int err; + + /* set port mode */ + switch (mode) { + case RTL8367_EXTIF_MODE_RGMII: + REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, + RTL8367B_DEBUG0_SEL33(id), + RTL8367B_DEBUG0_SEL33(id)); + if (id <= 1) { + REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, + RTL8367B_DEBUG0_DRI(id) | + RTL8367B_DEBUG0_DRI_RG(id) | + RTL8367B_DEBUG0_SLR(id), + RTL8367B_DEBUG0_DRI_RG(id) | + RTL8367B_DEBUG0_SLR(id)); + REG_RMW(smi, RTL8367B_CHIP_DEBUG1_REG, + RTL8367B_DEBUG1_DN_MASK(id) | + RTL8367B_DEBUG1_DP_MASK(id), + (7 << RTL8367B_DEBUG1_DN_SHIFT(id)) | + (7 << RTL8367B_DEBUG1_DP_SHIFT(id))); + } else { + REG_RMW(smi, RTL8367B_CHIP_DEBUG2_REG, + RTL8367B_DEBUG2_DRI_EXT2 | + RTL8367B_DEBUG2_DRI_EXT2_RG | + RTL8367B_DEBUG2_SLR_EXT2 | + RTL8367B_DEBUG2_RG2_DN_MASK | + RTL8367B_DEBUG2_RG2_DP_MASK, + RTL8367B_DEBUG2_DRI_EXT2_RG | + RTL8367B_DEBUG2_SLR_EXT2 | + (7 << RTL8367B_DEBUG2_RG2_DN_SHIFT) | + (7 << RTL8367B_DEBUG2_RG2_DP_SHIFT)); + } + break; + + case RTL8367_EXTIF_MODE_TMII_MAC: + case RTL8367_EXTIF_MODE_TMII_PHY: + REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), BIT(id)); + break; + + case RTL8367_EXTIF_MODE_GMII: + REG_RMW(smi, RTL8367B_CHIP_DEBUG0_REG, + RTL8367B_DEBUG0_SEL33(id), + RTL8367B_DEBUG0_SEL33(id)); + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), BIT(6)); + break; + + case RTL8367_EXTIF_MODE_MII_MAC: + case RTL8367_EXTIF_MODE_MII_PHY: + case RTL8367_EXTIF_MODE_DISABLED: + REG_RMW(smi, RTL8367B_BYPASS_LINE_RATE_REG, BIT(id), 0); + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), BIT(6), 0); + break; + + default: + dev_err(smi->parent, + "invalid mode for external interface %d\n", id); + return -EINVAL; + } + + if (id <= 1) + REG_RMW(smi, RTL8367B_DIS_REG, + RTL8367B_DIS_RGMII_MASK << RTL8367B_DIS_RGMII_SHIFT(id), + mode << RTL8367B_DIS_RGMII_SHIFT(id)); + else + REG_RMW(smi, RTL8367B_DIS2_REG, + RTL8367B_DIS2_RGMII_MASK << RTL8367B_DIS2_RGMII_SHIFT, + mode << RTL8367B_DIS2_RGMII_SHIFT); + + return 0; +} + +static int rtl8367b_extif_set_force(struct rtl8366_smi *smi, int id, + struct rtl8367_port_ability *pa) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367B_DI_FORCE_MODE | + RTL8367B_DI_FORCE_NWAY | + RTL8367B_DI_FORCE_TXPAUSE | + RTL8367B_DI_FORCE_RXPAUSE | + RTL8367B_DI_FORCE_LINK | + RTL8367B_DI_FORCE_DUPLEX | + RTL8367B_DI_FORCE_SPEED_MASK); + + val = pa->speed; + val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0; + val |= pa->nway ? RTL8367B_DI_FORCE_NWAY : 0; + val |= pa->txpause ? RTL8367B_DI_FORCE_TXPAUSE : 0; + val |= pa->rxpause ? RTL8367B_DI_FORCE_RXPAUSE : 0; + val |= pa->link ? RTL8367B_DI_FORCE_LINK : 0; + val |= pa->duplex ? RTL8367B_DI_FORCE_DUPLEX : 0; + + REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val); + + return 0; +} + +static int rtl8367b_extif_set_rgmii_delay(struct rtl8366_smi *smi, int id, + unsigned txdelay, unsigned rxdelay) +{ + u32 mask; + u32 val; + int err; + + mask = (RTL8367B_EXT_RGMXF_RXDELAY_MASK | + (RTL8367B_EXT_RGMXF_TXDELAY_MASK << + RTL8367B_EXT_RGMXF_TXDELAY_SHIFT)); + + val = rxdelay; + val |= txdelay << RTL8367B_EXT_RGMXF_TXDELAY_SHIFT; + + REG_RMW(smi, RTL8367B_EXT_RGMXF_REG(id), mask, val); + + return 0; +} + +static int rtl8367b_extif_init(struct rtl8366_smi *smi, int id, + struct rtl8367_extif_config *cfg) +{ + enum rtl8367_extif_mode mode; + int err; + + mode = (cfg) ? cfg->mode : RTL8367_EXTIF_MODE_DISABLED; + + err = rtl8367b_extif_set_mode(smi, id, mode); + if (err) + return err; + + if (mode != RTL8367_EXTIF_MODE_DISABLED) { + err = rtl8367b_extif_set_force(smi, id, &cfg->ability); + if (err) + return err; + + err = rtl8367b_extif_set_rgmii_delay(smi, id, cfg->txdelay, + cfg->rxdelay); + if (err) + return err; + } + + return 0; +} + +#ifdef CONFIG_OF +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + struct rtl8367_extif_config *cfg; + const __be32 *prop; + int size; + int err; + + prop = of_get_property(smi->parent->of_node, name, &size); + if (!prop) + return rtl8367b_extif_init(smi, id, NULL); + + if (size != (9 * sizeof(*prop))) { + dev_err(smi->parent, "%s property is invalid\n", name); + return -EINVAL; + } + + cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->txdelay = be32_to_cpup(prop++); + cfg->rxdelay = be32_to_cpup(prop++); + cfg->mode = be32_to_cpup(prop++); + cfg->ability.force_mode = be32_to_cpup(prop++); + cfg->ability.txpause = be32_to_cpup(prop++); + cfg->ability.rxpause = be32_to_cpup(prop++); + cfg->ability.link = be32_to_cpup(prop++); + cfg->ability.duplex = be32_to_cpup(prop++); + cfg->ability.speed = be32_to_cpup(prop++); + + err = rtl8367b_extif_init(smi, id, cfg); + kfree(cfg); + + return err; +} +#else +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id, + const char *name) +{ + return -EINVAL; +} +#endif + +static int rtl8367b_setup(struct rtl8366_smi *smi) +{ + struct rtl8367_platform_data *pdata; + int err; + int i; + + pdata = smi->parent->platform_data; + + err = rtl8367b_init_regs(smi); + if (err) + return err; + + /* initialize external interfaces */ + if (smi->parent->of_node) { + err = rtl8367b_extif_init_of(smi, 0, "realtek,extif0"); + if (err) + return err; + + err = rtl8367b_extif_init_of(smi, 1, "realtek,extif1"); + if (err) + return err; + + err = rtl8367b_extif_init_of(smi, 2, "realtek,extif2"); + if (err) + return err; + } else { + err = rtl8367b_extif_init(smi, 0, pdata->extif0_cfg); + if (err) + return err; + + err = rtl8367b_extif_init(smi, 1, pdata->extif1_cfg); + if (err) + return err; + } + + /* set maximum packet length to 1536 bytes */ + REG_RMW(smi, RTL8367B_SWC0_REG, RTL8367B_SWC0_MAX_LENGTH_MASK, + RTL8367B_SWC0_MAX_LENGTH_1536); + + /* + * discard VLAN tagged packets if the port is not a member of + * the VLAN with which the packets is associated. + */ + REG_WR(smi, RTL8367B_VLAN_INGRESS_REG, RTL8367B_PORTS_ALL); + + /* + * Setup egress tag mode for each port. + */ + for (i = 0; i < RTL8367B_NUM_PORTS; i++) + REG_RMW(smi, + RTL8367B_PORT_MISC_CFG_REG(i), + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_MASK << + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT, + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_ORIGINAL << + RTL8367B_PORT_MISC_CFG_EGRESS_MODE_SHIFT); + + return 0; +} + +static int rtl8367b_get_mib_counter(struct rtl8366_smi *smi, int counter, + int port, unsigned long long *val) +{ + struct rtl8366_mib_counter *mib; + int offset; + int i; + int err; + u32 addr, data; + u64 mibvalue; + + if (port > RTL8367B_NUM_PORTS || + counter >= RTL8367B_NUM_MIB_COUNTERS) + return -EINVAL; + + mib = &rtl8367b_mib_counters[counter]; + addr = RTL8367B_MIB_COUNTER_PORT_OFFSET * port + mib->offset; + + /* + * Writing access counter address first + * then ASIC will prepare 64bits counter wait for being retrived + */ + REG_WR(smi, RTL8367B_MIB_ADDRESS_REG, addr >> 2); + + /* read MIB control register */ + REG_RD(smi, RTL8367B_MIB_CTRL0_REG(0), &data); + + if (data & RTL8367B_MIB_CTRL0_BUSY_MASK) + return -EBUSY; + + if (data & RTL8367B_MIB_CTRL0_RESET_MASK) + return -EIO; + + if (mib->length == 4) + offset = 3; + else + offset = (mib->offset + 1) % 4; + + mibvalue = 0; + for (i = 0; i < mib->length; i++) { + REG_RD(smi, RTL8367B_MIB_COUNTER_REG(offset - i), &data); + mibvalue = (mibvalue << 16) | (data & 0xFFFF); + } + + *val = mibvalue; + return 0; +} + +static int rtl8367b_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, + struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; + int err; + int i; + + memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); + + if (vid >= RTL8367B_NUM_VIDS) + return -EINVAL; + + /* write VID */ + REG_WR(smi, RTL8367B_TA_ADDR_REG, vid); + + /* write table access control word */ + REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_READ); + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367B_TA_RDDATA_REG(i), &data[i]); + + vlan4k->vid = vid; + vlan4k->member = (data[0] >> RTL8367B_TA_VLAN0_MEMBER_SHIFT) & + RTL8367B_TA_VLAN0_MEMBER_MASK; + vlan4k->untag = (data[0] >> RTL8367B_TA_VLAN0_UNTAG_SHIFT) & + RTL8367B_TA_VLAN0_UNTAG_MASK; + vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) & + RTL8367B_TA_VLAN1_FID_MASK; + + return 0; +} + +static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi, + const struct rtl8366_vlan_4k *vlan4k) +{ + u32 data[RTL8367B_TA_VLAN_NUM_WORDS]; + int err; + int i; + + if (vlan4k->vid >= RTL8367B_NUM_VIDS || + vlan4k->member > RTL8367B_TA_VLAN0_MEMBER_MASK || + vlan4k->untag > RTL8367B_UNTAG_MASK || + vlan4k->fid > RTL8367B_FIDMAX) + return -EINVAL; + + memset(data, 0, sizeof(data)); + + data[0] = (vlan4k->member & RTL8367B_TA_VLAN0_MEMBER_MASK) << + RTL8367B_TA_VLAN0_MEMBER_SHIFT; + data[0] |= (vlan4k->untag & RTL8367B_TA_VLAN0_UNTAG_MASK) << + RTL8367B_TA_VLAN0_UNTAG_SHIFT; + data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) << + RTL8367B_TA_VLAN1_FID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367B_TA_WRDATA_REG(i), data[i]); + + /* write VID */ + REG_WR(smi, RTL8367B_TA_ADDR_REG, + vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK); + + /* write table access control word */ + REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_WRITE); + + return 0; +} + +static int rtl8367b_get_vlan_mc(struct rtl8366_smi *smi, u32 index, + struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; + int err; + int i; + + memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); + + if (index >= RTL8367B_NUM_VLANS) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_RD(smi, RTL8367B_VLAN_MC_BASE(index) + i, &data[i]); + + vlanmc->member = (data[0] >> RTL8367B_VLAN_MC0_MEMBER_SHIFT) & + RTL8367B_VLAN_MC0_MEMBER_MASK; + vlanmc->fid = (data[1] >> RTL8367B_VLAN_MC1_FID_SHIFT) & + RTL8367B_VLAN_MC1_FID_MASK; + vlanmc->vid = (data[3] >> RTL8367B_VLAN_MC3_EVID_SHIFT) & + RTL8367B_VLAN_MC3_EVID_MASK; + + return 0; +} + +static int rtl8367b_set_vlan_mc(struct rtl8366_smi *smi, u32 index, + const struct rtl8366_vlan_mc *vlanmc) +{ + u32 data[RTL8367B_VLAN_MC_NUM_WORDS]; + int err; + int i; + + if (index >= RTL8367B_NUM_VLANS || + vlanmc->vid >= RTL8367B_NUM_VIDS || + vlanmc->priority > RTL8367B_PRIORITYMAX || + vlanmc->member > RTL8367B_VLAN_MC0_MEMBER_MASK || + vlanmc->untag > RTL8367B_UNTAG_MASK || + vlanmc->fid > RTL8367B_FIDMAX) + return -EINVAL; + + data[0] = (vlanmc->member & RTL8367B_VLAN_MC0_MEMBER_MASK) << + RTL8367B_VLAN_MC0_MEMBER_SHIFT; + data[1] = (vlanmc->fid & RTL8367B_VLAN_MC1_FID_MASK) << + RTL8367B_VLAN_MC1_FID_SHIFT; + data[2] = 0; + data[3] = (vlanmc->vid & RTL8367B_VLAN_MC3_EVID_MASK) << + RTL8367B_VLAN_MC3_EVID_SHIFT; + + for (i = 0; i < ARRAY_SIZE(data); i++) + REG_WR(smi, RTL8367B_VLAN_MC_BASE(index) + i, data[i]); + + return 0; +} + +static int rtl8367b_get_mc_index(struct rtl8366_smi *smi, int port, int *val) +{ + u32 data; + int err; + + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data); + + *val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) & + RTL8367B_VLAN_PVID_CTRL_MASK; + + return 0; +} + +static int rtl8367b_set_mc_index(struct rtl8366_smi *smi, int port, int index) +{ + if (port >= RTL8367B_NUM_PORTS || index >= RTL8367B_NUM_VLANS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), + RTL8367B_VLAN_PVID_CTRL_MASK << + RTL8367B_VLAN_PVID_CTRL_SHIFT(port), + (index & RTL8367B_VLAN_PVID_CTRL_MASK) << + RTL8367B_VLAN_PVID_CTRL_SHIFT(port)); +} + +static int rtl8367b_enable_vlan(struct rtl8366_smi *smi, int enable) +{ + return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_CTRL_REG, + RTL8367B_VLAN_CTRL_ENABLE, + (enable) ? RTL8367B_VLAN_CTRL_ENABLE : 0); +} + +static int rtl8367b_enable_vlan4k(struct rtl8366_smi *smi, int enable) +{ + return 0; +} + +static int rtl8367b_is_vlan_valid(struct rtl8366_smi *smi, unsigned vlan) +{ + unsigned max = RTL8367B_NUM_VLANS; + + if (smi->vlan4k_enabled) + max = RTL8367B_NUM_VIDS - 1; + + if (vlan == 0 || vlan >= max) + return 0; + + return 1; +} + +static int rtl8367b_enable_port(struct rtl8366_smi *smi, int port, int enable) +{ + int err; + + REG_WR(smi, RTL8367B_PORT_ISOLATION_REG(port), + (enable) ? RTL8367B_PORTS_ALL : 0); + + return 0; +} + +static int rtl8367b_sw_reset_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + + return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(0), 0, + RTL8367B_MIB_CTRL0_GLOBAL_RESET_MASK); +} + +static int rtl8367b_sw_get_port_link(struct switch_dev *dev, + int port, + struct switch_port_link *link) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data = 0; + u32 speed; + + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data); + + link->link = !!(data & RTL8367B_PORT_STATUS_LINK); + if (!link->link) + return 0; + + link->duplex = !!(data & RTL8367B_PORT_STATUS_DUPLEX); + link->rx_flow = !!(data & RTL8367B_PORT_STATUS_RXPAUSE); + link->tx_flow = !!(data & RTL8367B_PORT_STATUS_TXPAUSE); + link->aneg = !!(data & RTL8367B_PORT_STATUS_NWAY); + + speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK); + switch (speed) { + case 0: + link->speed = SWITCH_PORT_SPEED_10; + break; + case 1: + link->speed = SWITCH_PORT_SPEED_100; + break; + case 2: + link->speed = SWITCH_PORT_SPEED_1000; + break; + default: + link->speed = SWITCH_PORT_SPEED_UNKNOWN; + break; + } + + return 0; +} + +static int rtl8367b_sw_get_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 data; + + rtl8366_smi_read_reg(smi, RTL8367B_SWC0_REG, &data); + val->value.i = (data & RTL8367B_SWC0_MAX_LENGTH_MASK) >> + RTL8367B_SWC0_MAX_LENGTH_SHIFT; + + return 0; +} + +static int rtl8367b_sw_set_max_length(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + u32 max_len; + + switch (val->value.i) { + case 0: + max_len = RTL8367B_SWC0_MAX_LENGTH_1522; + break; + case 1: + max_len = RTL8367B_SWC0_MAX_LENGTH_1536; + break; + case 2: + max_len = RTL8367B_SWC0_MAX_LENGTH_1552; + break; + case 3: + max_len = RTL8367B_SWC0_MAX_LENGTH_16000; + break; + default: + return -EINVAL; + } + + return rtl8366_smi_rmwr(smi, RTL8367B_SWC0_REG, + RTL8367B_SWC0_MAX_LENGTH_MASK, max_len); +} + + +static int rtl8367b_sw_reset_port_mibs(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int port; + + port = val->port_vlan; + if (port >= RTL8367B_NUM_PORTS) + return -EINVAL; + + return rtl8366_smi_rmwr(smi, RTL8367B_MIB_CTRL0_REG(port / 8), 0, + RTL8367B_MIB_CTRL0_PORT_RESET_MASK(port % 8)); +} + +static int rtl8367b_sw_get_port_stats(struct switch_dev *dev, int port, + struct switch_port_stats *stats) +{ + return (rtl8366_sw_get_port_stats(dev, port, stats, + RTL8367B_MIB_TXB_ID, RTL8367B_MIB_RXB_ID)); +} + +static struct switch_attr rtl8367b_globals[] = { + { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan", + .description = "Enable VLAN mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 1 + }, { + .type = SWITCH_TYPE_INT, + .name = "enable_vlan4k", + .description = "Enable VLAN 4K mode", + .set = rtl8366_sw_set_vlan_enable, + .get = rtl8366_sw_get_vlan_enable, + .max = 1, + .ofs = 2 + }, { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mibs", + .description = "Reset all MIB counters", + .set = rtl8367b_sw_reset_mibs, + }, { + .type = SWITCH_TYPE_INT, + .name = "max_length", + .description = "Get/Set the maximum length of valid packets" + "(0:1522, 1:1536, 2:1552, 3:16000)", + .set = rtl8367b_sw_set_max_length, + .get = rtl8367b_sw_get_max_length, + .max = 3, + } +}; + +static struct switch_attr rtl8367b_port[] = { + { + .type = SWITCH_TYPE_NOVAL, + .name = "reset_mib", + .description = "Reset single port MIB counters", + .set = rtl8367b_sw_reset_port_mibs, + }, { + .type = SWITCH_TYPE_STRING, + .name = "mib", + .description = "Get MIB counters for port", + .max = 33, + .set = NULL, + .get = rtl8366_sw_get_port_mib, + }, +}; + +static struct switch_attr rtl8367b_vlan[] = { + { + .type = SWITCH_TYPE_STRING, + .name = "info", + .description = "Get vlan information", + .max = 1, + .set = NULL, + .get = rtl8366_sw_get_vlan_info, + }, +}; + +static const struct switch_dev_ops rtl8367b_sw_ops = { + .attr_global = { + .attr = rtl8367b_globals, + .n_attr = ARRAY_SIZE(rtl8367b_globals), + }, + .attr_port = { + .attr = rtl8367b_port, + .n_attr = ARRAY_SIZE(rtl8367b_port), + }, + .attr_vlan = { + .attr = rtl8367b_vlan, + .n_attr = ARRAY_SIZE(rtl8367b_vlan), + }, + + .get_vlan_ports = rtl8366_sw_get_vlan_ports, + .set_vlan_ports = rtl8366_sw_set_vlan_ports, + .get_port_pvid = rtl8366_sw_get_port_pvid, + .set_port_pvid = rtl8366_sw_set_port_pvid, + .reset_switch = rtl8366_sw_reset_switch, + .get_port_link = rtl8367b_sw_get_port_link, + .get_port_stats = rtl8367b_sw_get_port_stats, +}; + +static int rtl8367b_switch_init(struct rtl8366_smi *smi) +{ + struct switch_dev *dev = &smi->sw_dev; + int err; + + dev->name = "RTL8367B"; + dev->cpu_port = smi->cpu_port; + dev->ports = RTL8367B_NUM_PORTS; + dev->vlans = RTL8367B_NUM_VIDS; + dev->ops = &rtl8367b_sw_ops; + dev->alias = dev_name(smi->parent); + + err = register_switch(dev, NULL); + if (err) + dev_err(smi->parent, "switch registration failed\n"); + + return err; +} + +static void rtl8367b_switch_cleanup(struct rtl8366_smi *smi) +{ + unregister_switch(&smi->sw_dev); +} + +static int rtl8367b_mii_read(struct mii_bus *bus, int addr, int reg) +{ + struct rtl8366_smi *smi = bus->priv; + u32 val = 0; + int err; + + err = rtl8367b_read_phy_reg(smi, addr, reg, &val); + if (err) + return 0xffff; + + return val; +} + +static int rtl8367b_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) +{ + struct rtl8366_smi *smi = bus->priv; + u32 t; + int err; + + err = rtl8367b_write_phy_reg(smi, addr, reg, val); + if (err) + return err; + + /* flush write */ + (void) rtl8367b_read_phy_reg(smi, addr, reg, &t); + + return err; +} + +static int rtl8367b_detect(struct rtl8366_smi *smi) +{ + const char *chip_name; + u32 chip_num; + u32 chip_ver; + u32 chip_mode; + int ret; + + /* TODO: improve chip detection */ + rtl8366_smi_write_reg(smi, RTL8367B_RTL_MAGIC_ID_REG, + RTL8367B_RTL_MAGIC_ID_VAL); + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_NUMBER_REG, &chip_num); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip number"); + return ret; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_VER_REG, &chip_ver); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip version"); + return ret; + } + + ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_MODE_REG, &chip_mode); + if (ret) { + dev_err(smi->parent, "unable to read %s register\n", + "chip mode"); + return ret; + } + + switch (chip_ver) { + case 0x1000: + chip_name = "8367RB"; + break; + case 0x1010: + chip_name = "8367R-VB"; + break; + default: + dev_err(smi->parent, + "unknown chip num:%04x ver:%04x, mode:%04x\n", + chip_num, chip_ver, chip_mode); + return -ENODEV; + } + + dev_info(smi->parent, "RTL%s chip found\n", chip_name); + + return 0; +} + +static struct rtl8366_smi_ops rtl8367b_smi_ops = { + .detect = rtl8367b_detect, + .reset_chip = rtl8367b_reset_chip, + .setup = rtl8367b_setup, + + .mii_read = rtl8367b_mii_read, + .mii_write = rtl8367b_mii_write, + + .get_vlan_mc = rtl8367b_get_vlan_mc, + .set_vlan_mc = rtl8367b_set_vlan_mc, + .get_vlan_4k = rtl8367b_get_vlan_4k, + .set_vlan_4k = rtl8367b_set_vlan_4k, + .get_mc_index = rtl8367b_get_mc_index, + .set_mc_index = rtl8367b_set_mc_index, + .get_mib_counter = rtl8367b_get_mib_counter, + .is_vlan_valid = rtl8367b_is_vlan_valid, + .enable_vlan = rtl8367b_enable_vlan, + .enable_vlan4k = rtl8367b_enable_vlan4k, + .enable_port = rtl8367b_enable_port, +}; + +static int rtl8367b_probe(struct platform_device *pdev) +{ + struct rtl8366_smi *smi; + int err; + + smi = rtl8366_smi_probe(pdev); + if (IS_ERR(smi)) + return PTR_ERR(smi); + + smi->clk_delay = 1500; + smi->cmd_read = 0xb9; + smi->cmd_write = 0xb8; + smi->ops = &rtl8367b_smi_ops; + smi->num_ports = RTL8367B_NUM_PORTS; + if (of_property_read_u32(pdev->dev.of_node, "cpu_port", &smi->cpu_port) + || smi->cpu_port >= smi->num_ports) + smi->cpu_port = RTL8367B_CPU_PORT_NUM; + smi->num_vlan_mc = RTL8367B_NUM_VLANS; + smi->mib_counters = rtl8367b_mib_counters; + smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters); + + err = rtl8366_smi_init(smi); + if (err) + goto err_free_smi; + + platform_set_drvdata(pdev, smi); + + err = rtl8367b_switch_init(smi); + if (err) + goto err_clear_drvdata; + + return 0; + + err_clear_drvdata: + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + err_free_smi: + kfree(smi); + return err; +} + +static int rtl8367b_remove(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) { + rtl8367b_switch_cleanup(smi); + platform_set_drvdata(pdev, NULL); + rtl8366_smi_cleanup(smi); + kfree(smi); + } + + return 0; +} + +static void rtl8367b_shutdown(struct platform_device *pdev) +{ + struct rtl8366_smi *smi = platform_get_drvdata(pdev); + + if (smi) + rtl8367b_reset_chip(smi); +} + +#ifdef CONFIG_OF +static const struct of_device_id rtl8367b_match[] = { + { .compatible = "realtek,rtl8367b" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl8367b_match); +#endif + +static struct platform_driver rtl8367b_driver = { + .driver = { + .name = RTL8367B_DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(rtl8367b_match), +#endif + }, + .probe = rtl8367b_probe, + .remove = rtl8367b_remove, + .shutdown = rtl8367b_shutdown, +}; + +module_platform_driver(rtl8367b_driver); + +MODULE_DESCRIPTION("Realtek RTL8367B ethernet switch driver"); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" RTL8367B_DRIVER_NAME); + diff --git a/ipq806x/files-5.4/drivers/net/phy/swconfig.c b/ipq806x/files-5.4/drivers/net/phy/swconfig.c new file mode 100644 index 0000000..a734e57 --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/swconfig.c @@ -0,0 +1,1242 @@ +/* + * swconfig.c: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SWCONFIG_DEVNAME "switch%d" + +#include "swconfig_leds.c" + +MODULE_AUTHOR("Felix Fietkau "); +MODULE_LICENSE("GPL"); + +static int swdev_id; +static struct list_head swdevs; +static DEFINE_MUTEX(swdevs_lock); +struct swconfig_callback; + +struct swconfig_callback { + struct sk_buff *msg; + struct genlmsghdr *hdr; + struct genl_info *info; + int cmd; + + /* callback for filling in the message data */ + int (*fill)(struct swconfig_callback *cb, void *arg); + + /* callback for closing the message before sending it */ + int (*close)(struct swconfig_callback *cb, void *arg); + + struct nlattr *nest[4]; + int args[4]; +}; + +/* defaults */ + +static int +swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + int ret; + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + if (!dev->ops->get_vlan_ports) + return -EOPNOTSUPP; + + ret = dev->ops->get_vlan_ports(dev, val); + return ret; +} + +static int +swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct switch_port *ports = val->value.ports; + const struct switch_dev_ops *ops = dev->ops; + int i; + + if (val->port_vlan >= dev->vlans) + return -EINVAL; + + /* validate ports */ + if (val->len > dev->ports) + return -EINVAL; + + if (!ops->set_vlan_ports) + return -EOPNOTSUPP; + + for (i = 0; i < val->len; i++) { + if (ports[i].id >= dev->ports) + return -EINVAL; + + if (ops->set_port_pvid && + !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED))) + ops->set_port_pvid(dev, ports[i].id, val->port_vlan); + } + + return ops->set_vlan_ports(dev, val); +} + +static int +swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->set_port_pvid) + return -EOPNOTSUPP; + + return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i); +} + +static int +swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->get_port_pvid) + return -EOPNOTSUPP; + + return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i); +} + +static int +swconfig_set_link(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + if (!dev->ops->set_port_link) + return -EOPNOTSUPP; + + return dev->ops->set_port_link(dev, val->port_vlan, val->value.link); +} + +static int +swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + struct switch_port_link *link = val->value.link; + + if (val->port_vlan >= dev->ports) + return -EINVAL; + + if (!dev->ops->get_port_link) + return -EOPNOTSUPP; + + memset(link, 0, sizeof(*link)); + return dev->ops->get_port_link(dev, val->port_vlan, link); +} + +static int +swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + /* don't complain if not supported by the switch driver */ + if (!dev->ops->apply_config) + return 0; + + return dev->ops->apply_config(dev); +} + +static int +swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, + struct switch_val *val) +{ + /* don't complain if not supported by the switch driver */ + if (!dev->ops->reset_switch) + return 0; + + return dev->ops->reset_switch(dev); +} + +enum global_defaults { + GLOBAL_APPLY, + GLOBAL_RESET, +}; + +enum vlan_defaults { + VLAN_PORTS, +}; + +enum port_defaults { + PORT_PVID, + PORT_LINK, +}; + +static struct switch_attr default_global[] = { + [GLOBAL_APPLY] = { + .type = SWITCH_TYPE_NOVAL, + .name = "apply", + .description = "Activate changes in the hardware", + .set = swconfig_apply_config, + }, + [GLOBAL_RESET] = { + .type = SWITCH_TYPE_NOVAL, + .name = "reset", + .description = "Reset the switch", + .set = swconfig_reset_switch, + } +}; + +static struct switch_attr default_port[] = { + [PORT_PVID] = { + .type = SWITCH_TYPE_INT, + .name = "pvid", + .description = "Primary VLAN ID", + .set = swconfig_set_pvid, + .get = swconfig_get_pvid, + }, + [PORT_LINK] = { + .type = SWITCH_TYPE_LINK, + .name = "link", + .description = "Get port link information", + .set = swconfig_set_link, + .get = swconfig_get_link, + } +}; + +static struct switch_attr default_vlan[] = { + [VLAN_PORTS] = { + .type = SWITCH_TYPE_PORTS, + .name = "ports", + .description = "VLAN port mapping", + .set = swconfig_set_vlan_ports, + .get = swconfig_get_vlan_ports, + }, +}; + +static const struct switch_attr * +swconfig_find_attr_by_name(const struct switch_attrlist *alist, + const char *name) +{ + int i; + + for (i = 0; i < alist->n_attr; i++) + if (strcmp(name, alist->attr[i].name) == 0) + return &alist->attr[i]; + + return NULL; +} + +static void swconfig_defaults_init(struct switch_dev *dev) +{ + const struct switch_dev_ops *ops = dev->ops; + + dev->def_global = 0; + dev->def_vlan = 0; + dev->def_port = 0; + + if (ops->get_vlan_ports || ops->set_vlan_ports) + set_bit(VLAN_PORTS, &dev->def_vlan); + + if (ops->get_port_pvid || ops->set_port_pvid) + set_bit(PORT_PVID, &dev->def_port); + + if (ops->get_port_link && + !swconfig_find_attr_by_name(&ops->attr_port, "link")) + set_bit(PORT_LINK, &dev->def_port); + + /* always present, can be no-op */ + set_bit(GLOBAL_APPLY, &dev->def_global); + set_bit(GLOBAL_RESET, &dev->def_global); +} + + +static struct genl_family switch_fam; + +static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { + [SWITCH_ATTR_ID] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, + [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, + [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, + [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, +}; + +static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { + [SWITCH_PORT_ID] = { .type = NLA_U32 }, + [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, +}; + +static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = { + [SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG }, + [SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG }, + [SWITCH_LINK_SPEED] = { .type = NLA_U32 }, +}; + +static inline void +swconfig_lock(void) +{ + mutex_lock(&swdevs_lock); +} + +static inline void +swconfig_unlock(void) +{ + mutex_unlock(&swdevs_lock); +} + +static struct switch_dev * +swconfig_get_dev(struct genl_info *info) +{ + struct switch_dev *dev = NULL; + struct switch_dev *p; + int id; + + if (!info->attrs[SWITCH_ATTR_ID]) + goto done; + + id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); + swconfig_lock(); + list_for_each_entry(p, &swdevs, dev_list) { + if (id != p->id) + continue; + + dev = p; + break; + } + if (dev) + mutex_lock(&dev->sw_mutex); + else + pr_debug("device %d not found\n", id); + swconfig_unlock(); +done: + return dev; +} + +static inline void +swconfig_put_dev(struct switch_dev *dev) +{ + mutex_unlock(&dev->sw_mutex); +} + +static int +swconfig_dump_attr(struct swconfig_callback *cb, void *arg) +{ + struct switch_attr *op = arg; + struct genl_info *info = cb->info; + struct sk_buff *msg = cb->msg; + int id = cb->args[0]; + void *hdr; + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, + NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); + if (IS_ERR(hdr)) + return -1; + + if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name)) + goto nla_put_failure; + if (op->description) + if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION, + op->description)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + return msg->len; +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +/* spread multipart messages across multiple message buffers */ +static int +swconfig_send_multipart(struct swconfig_callback *cb, void *arg) +{ + struct genl_info *info = cb->info; + int restart = 0; + int err; + + do { + if (!cb->msg) { + cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (cb->msg == NULL) + goto error; + } + + if (!(cb->fill(cb, arg) < 0)) + break; + + /* fill failed, check if this was already the second attempt */ + if (restart) + goto error; + + /* try again in a new message, send the current one */ + restart = 1; + if (cb->close) { + if (cb->close(cb, arg) < 0) + goto error; + } + err = genlmsg_reply(cb->msg, info); + cb->msg = NULL; + if (err < 0) + goto error; + + } while (restart); + + return 0; + +error: + if (cb->msg) + nlmsg_free(cb->msg); + return -1; +} + +static int +swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attrlist *alist; + struct switch_dev *dev; + struct swconfig_callback cb; + int err = -EINVAL; + int i; + + /* defaults */ + struct switch_attr *def_list; + unsigned long *def_active; + int n_def; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + switch (hdr->cmd) { + case SWITCH_CMD_LIST_GLOBAL: + alist = &dev->ops->attr_global; + def_list = default_global; + def_active = &dev->def_global; + n_def = ARRAY_SIZE(default_global); + break; + case SWITCH_CMD_LIST_VLAN: + alist = &dev->ops->attr_vlan; + def_list = default_vlan; + def_active = &dev->def_vlan; + n_def = ARRAY_SIZE(default_vlan); + break; + case SWITCH_CMD_LIST_PORT: + alist = &dev->ops->attr_port; + def_list = default_port; + def_active = &dev->def_port; + n_def = ARRAY_SIZE(default_port); + break; + default: + WARN_ON(1); + goto out; + } + + memset(&cb, 0, sizeof(cb)); + cb.info = info; + cb.fill = swconfig_dump_attr; + for (i = 0; i < alist->n_attr; i++) { + if (alist->attr[i].disabled) + continue; + cb.args[0] = i; + err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]); + if (err < 0) + goto error; + } + + /* defaults */ + for (i = 0; i < n_def; i++) { + if (!test_bit(i, def_active)) + continue; + cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; + err = swconfig_send_multipart(&cb, (void *) &def_list[i]); + if (err < 0) + goto error; + } + swconfig_put_dev(dev); + + if (!cb.msg) + return 0; + + return genlmsg_reply(cb.msg, info); + +error: + if (cb.msg) + nlmsg_free(cb.msg); +out: + swconfig_put_dev(dev); + return err; +} + +static const struct switch_attr * +swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, + struct switch_val *val) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attrlist *alist; + const struct switch_attr *attr = NULL; + unsigned int attr_id; + + /* defaults */ + struct switch_attr *def_list; + unsigned long *def_active; + int n_def; + + if (!info->attrs[SWITCH_ATTR_OP_ID]) + goto done; + + switch (hdr->cmd) { + case SWITCH_CMD_SET_GLOBAL: + case SWITCH_CMD_GET_GLOBAL: + alist = &dev->ops->attr_global; + def_list = default_global; + def_active = &dev->def_global; + n_def = ARRAY_SIZE(default_global); + break; + case SWITCH_CMD_SET_VLAN: + case SWITCH_CMD_GET_VLAN: + alist = &dev->ops->attr_vlan; + def_list = default_vlan; + def_active = &dev->def_vlan; + n_def = ARRAY_SIZE(default_vlan); + if (!info->attrs[SWITCH_ATTR_OP_VLAN]) + goto done; + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); + if (val->port_vlan >= dev->vlans) + goto done; + break; + case SWITCH_CMD_SET_PORT: + case SWITCH_CMD_GET_PORT: + alist = &dev->ops->attr_port; + def_list = default_port; + def_active = &dev->def_port; + n_def = ARRAY_SIZE(default_port); + if (!info->attrs[SWITCH_ATTR_OP_PORT]) + goto done; + val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); + if (val->port_vlan >= dev->ports) + goto done; + break; + default: + WARN_ON(1); + goto done; + } + + if (!alist) + goto done; + + attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); + if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { + attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; + if (attr_id >= n_def) + goto done; + if (!test_bit(attr_id, def_active)) + goto done; + attr = &def_list[attr_id]; + } else { + if (attr_id >= alist->n_attr) + goto done; + attr = &alist->attr[attr_id]; + } + + if (attr->disabled) + attr = NULL; + +done: + if (!attr) + pr_debug("attribute lookup failed\n"); + val->attr = attr; + return attr; +} + +static int +swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, + struct switch_val *val, int max) +{ + struct nlattr *nla; + int rem; + + val->len = 0; + nla_for_each_nested(nla, head, rem) { + struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; + struct switch_port *port; + + if (val->len >= max) + return -EINVAL; + + port = &val->value.ports[val->len]; + + if (nla_parse_nested_deprecated(tb, SWITCH_PORT_ATTR_MAX, nla, + port_policy, NULL)) + return -EINVAL; + + if (!tb[SWITCH_PORT_ID]) + return -EINVAL; + + port->id = nla_get_u32(tb[SWITCH_PORT_ID]); + if (tb[SWITCH_PORT_FLAG_TAGGED]) + port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); + val->len++; + } + + return 0; +} + +static int +swconfig_parse_link(struct sk_buff *msg, struct nlattr *nla, + struct switch_port_link *link) +{ + struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1]; + + if (nla_parse_nested_deprecated(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy, NULL)) + return -EINVAL; + + link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX]; + link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG]; + link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]); + + return 0; +} + +static int +swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) +{ + const struct switch_attr *attr; + struct switch_dev *dev; + struct switch_val val; + int err = -EINVAL; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + memset(&val, 0, sizeof(val)); + attr = swconfig_lookup_attr(dev, info, &val); + if (!attr || !attr->set) + goto error; + + val.attr = attr; + switch (attr->type) { + case SWITCH_TYPE_NOVAL: + break; + case SWITCH_TYPE_INT: + if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) + goto error; + val.value.i = + nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); + break; + case SWITCH_TYPE_STRING: + if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) + goto error; + val.value.s = + nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); + break; + case SWITCH_TYPE_PORTS: + val.value.ports = dev->portbuf; + memset(dev->portbuf, 0, + sizeof(struct switch_port) * dev->ports); + + /* TODO: implement multipart? */ + if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { + err = swconfig_parse_ports(skb, + info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], + &val, dev->ports); + if (err < 0) + goto error; + } else { + val.len = 0; + err = 0; + } + break; + case SWITCH_TYPE_LINK: + val.value.link = &dev->linkbuf; + memset(&dev->linkbuf, 0, sizeof(struct switch_port_link)); + + if (info->attrs[SWITCH_ATTR_OP_VALUE_LINK]) { + err = swconfig_parse_link(skb, + info->attrs[SWITCH_ATTR_OP_VALUE_LINK], + val.value.link); + if (err < 0) + goto error; + } else { + val.len = 0; + err = 0; + } + break; + default: + goto error; + } + + err = attr->set(dev, attr, &val); +error: + swconfig_put_dev(dev); + return err; +} + +static int +swconfig_close_portlist(struct swconfig_callback *cb, void *arg) +{ + if (cb->nest[0]) + nla_nest_end(cb->msg, cb->nest[0]); + return 0; +} + +static int +swconfig_send_port(struct swconfig_callback *cb, void *arg) +{ + const struct switch_port *port = arg; + struct nlattr *p = NULL; + + if (!cb->nest[0]) { + cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); + if (!cb->nest[0]) + return -1; + } + + p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); + if (!p) + goto error; + + if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id)) + goto nla_put_failure; + if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { + if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED)) + goto nla_put_failure; + } + + nla_nest_end(cb->msg, p); + return 0; + +nla_put_failure: + nla_nest_cancel(cb->msg, p); +error: + nla_nest_cancel(cb->msg, cb->nest[0]); + return -1; +} + +static int +swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, + const struct switch_val *val) +{ + struct swconfig_callback cb; + int err = 0; + int i; + + if (!val->value.ports) + return -EINVAL; + + memset(&cb, 0, sizeof(cb)); + cb.cmd = attr; + cb.msg = *msg; + cb.info = info; + cb.fill = swconfig_send_port; + cb.close = swconfig_close_portlist; + + cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); + for (i = 0; i < val->len; i++) { + err = swconfig_send_multipart(&cb, &val->value.ports[i]); + if (err) + goto done; + } + err = val->len; + swconfig_close_portlist(&cb, NULL); + *msg = cb.msg; + +done: + return err; +} + +static int +swconfig_send_link(struct sk_buff *msg, struct genl_info *info, int attr, + const struct switch_port_link *link) +{ + struct nlattr *p = NULL; + int err = 0; + + p = nla_nest_start(msg, attr); + if (link->link) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_LINK)) + goto nla_put_failure; + } + if (link->duplex) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_DUPLEX)) + goto nla_put_failure; + } + if (link->aneg) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_ANEG)) + goto nla_put_failure; + } + if (link->tx_flow) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_TX_FLOW)) + goto nla_put_failure; + } + if (link->rx_flow) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_RX_FLOW)) + goto nla_put_failure; + } + if (nla_put_u32(msg, SWITCH_LINK_SPEED, link->speed)) + goto nla_put_failure; + if (link->eee & ADVERTISED_100baseT_Full) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_100BASET)) + goto nla_put_failure; + } + if (link->eee & ADVERTISED_1000baseT_Full) { + if (nla_put_flag(msg, SWITCH_LINK_FLAG_EEE_1000BASET)) + goto nla_put_failure; + } + nla_nest_end(msg, p); + + return err; + +nla_put_failure: + nla_nest_cancel(msg, p); + return -1; +} + +static int +swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) +{ + struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); + const struct switch_attr *attr; + struct switch_dev *dev; + struct sk_buff *msg = NULL; + struct switch_val val; + int err = -EINVAL; + int cmd = hdr->cmd; + + dev = swconfig_get_dev(info); + if (!dev) + return -EINVAL; + + memset(&val, 0, sizeof(val)); + attr = swconfig_lookup_attr(dev, info, &val); + if (!attr || !attr->get) + goto error; + + if (attr->type == SWITCH_TYPE_PORTS) { + val.value.ports = dev->portbuf; + memset(dev->portbuf, 0, + sizeof(struct switch_port) * dev->ports); + } else if (attr->type == SWITCH_TYPE_LINK) { + val.value.link = &dev->linkbuf; + memset(&dev->linkbuf, 0, sizeof(struct switch_port_link)); + } + + err = attr->get(dev, attr, &val); + if (err) + goto error; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto error; + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam, + 0, cmd); + if (IS_ERR(hdr)) + goto nla_put_failure; + + switch (attr->type) { + case SWITCH_TYPE_INT: + if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i)) + goto nla_put_failure; + break; + case SWITCH_TYPE_STRING: + if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s)) + goto nla_put_failure; + break; + case SWITCH_TYPE_PORTS: + err = swconfig_send_ports(&msg, info, + SWITCH_ATTR_OP_VALUE_PORTS, &val); + if (err < 0) + goto nla_put_failure; + break; + case SWITCH_TYPE_LINK: + err = swconfig_send_link(msg, info, + SWITCH_ATTR_OP_VALUE_LINK, val.value.link); + if (err < 0) + goto nla_put_failure; + break; + default: + pr_debug("invalid type in attribute\n"); + err = -EINVAL; + goto nla_put_failure; + } + genlmsg_end(msg, hdr); + err = msg->len; + if (err < 0) + goto nla_put_failure; + + swconfig_put_dev(dev); + return genlmsg_reply(msg, info); + +nla_put_failure: + if (msg) + nlmsg_free(msg); +error: + swconfig_put_dev(dev); + if (!err) + err = -ENOMEM; + return err; +} + +static int +swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, + const struct switch_dev *dev) +{ + struct nlattr *p = NULL, *m = NULL; + void *hdr; + int i; + + hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, + SWITCH_CMD_NEW_ATTR); + if (IS_ERR(hdr)) + return -1; + + if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias)) + goto nla_put_failure; + if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port)) + goto nla_put_failure; + + m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP); + if (!m) + goto nla_put_failure; + for (i = 0; i < dev->ports; i++) { + p = nla_nest_start(msg, SWITCH_ATTR_PORTS); + if (!p) + continue; + if (dev->portmap[i].s) { + if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT, + dev->portmap[i].s)) + goto nla_put_failure; + if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT, + dev->portmap[i].virt)) + goto nla_put_failure; + } + nla_nest_end(msg, p); + } + nla_nest_end(msg, m); + genlmsg_end(msg, hdr); + return msg->len; +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE; +} + +static int swconfig_dump_switches(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct switch_dev *dev; + int start = cb->args[0]; + int idx = 0; + + swconfig_lock(); + list_for_each_entry(dev, &swdevs, dev_list) { + if (++idx <= start) + continue; + if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + dev) < 0) + break; + } + swconfig_unlock(); + cb->args[0] = idx; + + return skb->len; +} + +static int +swconfig_done(struct netlink_callback *cb) +{ + return 0; +} + +static struct genl_ops swconfig_ops[] = { + { + .cmd = SWITCH_CMD_LIST_GLOBAL, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_list_attrs, + }, + { + .cmd = SWITCH_CMD_LIST_VLAN, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_list_attrs, + }, + { + .cmd = SWITCH_CMD_LIST_PORT, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_list_attrs, + }, + { + .cmd = SWITCH_CMD_GET_GLOBAL, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_get_attr, + }, + { + .cmd = SWITCH_CMD_GET_VLAN, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_get_attr, + }, + { + .cmd = SWITCH_CMD_GET_PORT, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = swconfig_get_attr, + }, + { + .cmd = SWITCH_CMD_SET_GLOBAL, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_ADMIN_PERM, + .doit = swconfig_set_attr, + }, + { + .cmd = SWITCH_CMD_SET_VLAN, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_ADMIN_PERM, + .doit = swconfig_set_attr, + }, + { + .cmd = SWITCH_CMD_SET_PORT, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_ADMIN_PERM, + .doit = swconfig_set_attr, + }, + { + .cmd = SWITCH_CMD_GET_SWITCH, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .dumpit = swconfig_dump_switches, + .done = swconfig_done, + } +}; + +static struct genl_family switch_fam = { + .name = "switch", + .hdrsize = 0, + .version = 1, + .maxattr = SWITCH_ATTR_MAX, + .policy = switch_policy, + .module = THIS_MODULE, + .ops = swconfig_ops, + .n_ops = ARRAY_SIZE(swconfig_ops), +}; + +#ifdef CONFIG_OF +void +of_switch_load_portmap(struct switch_dev *dev) +{ + struct device_node *port; + + if (!dev->of_node) + return; + + for_each_child_of_node(dev->of_node, port) { + const __be32 *prop; + const char *segment; + int size, phys; + + if (!of_device_is_compatible(port, "swconfig,port")) + continue; + + if (of_property_read_string(port, "swconfig,segment", &segment)) + continue; + + prop = of_get_property(port, "swconfig,portmap", &size); + if (!prop) + continue; + + if (size != (2 * sizeof(*prop))) { + pr_err("%s: failed to parse port mapping\n", + port->name); + continue; + } + + phys = be32_to_cpup(prop++); + if ((phys < 0) | (phys >= dev->ports)) { + pr_err("%s: physical port index out of range\n", + port->name); + continue; + } + + dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL); + dev->portmap[phys].virt = be32_to_cpup(prop); + pr_debug("Found port: %s, physical: %d, virtual: %d\n", + segment, phys, dev->portmap[phys].virt); + } +} +#endif + +int +register_switch(struct switch_dev *dev, struct net_device *netdev) +{ + struct switch_dev *sdev; + const int max_switches = 8 * sizeof(unsigned long); + unsigned long in_use = 0; + int err; + int i; + + INIT_LIST_HEAD(&dev->dev_list); + if (netdev) { + dev->netdev = netdev; + if (!dev->alias) + dev->alias = netdev->name; + } + BUG_ON(!dev->alias); + + /* Make sure swdev_id doesn't overflow */ + if (swdev_id == INT_MAX) { + return -ENOMEM; + } + + if (dev->ports > 0) { + dev->portbuf = kzalloc(sizeof(struct switch_port) * + dev->ports, GFP_KERNEL); + if (!dev->portbuf) + return -ENOMEM; + dev->portmap = kzalloc(sizeof(struct switch_portmap) * + dev->ports, GFP_KERNEL); + if (!dev->portmap) { + kfree(dev->portbuf); + return -ENOMEM; + } + } + swconfig_defaults_init(dev); + mutex_init(&dev->sw_mutex); + swconfig_lock(); + dev->id = ++swdev_id; + + list_for_each_entry(sdev, &swdevs, dev_list) { + if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i)) + continue; + if (i < 0 || i > max_switches) + continue; + + set_bit(i, &in_use); + } + i = find_first_zero_bit(&in_use, max_switches); + + if (i == max_switches) { + swconfig_unlock(); + return -ENFILE; + } + +#ifdef CONFIG_OF + if (dev->ports) + of_switch_load_portmap(dev); +#endif + + /* fill device name */ + snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i); + + list_add_tail(&dev->dev_list, &swdevs); + swconfig_unlock(); + + err = swconfig_create_led_trigger(dev); + if (err) + return err; + + return 0; +} +EXPORT_SYMBOL_GPL(register_switch); + +void +unregister_switch(struct switch_dev *dev) +{ + swconfig_destroy_led_trigger(dev); + kfree(dev->portbuf); + mutex_lock(&dev->sw_mutex); + swconfig_lock(); + list_del(&dev->dev_list); + swconfig_unlock(); + mutex_unlock(&dev->sw_mutex); +} +EXPORT_SYMBOL_GPL(unregister_switch); + +int +switch_generic_set_link(struct switch_dev *dev, int port, + struct switch_port_link *link) +{ + if (WARN_ON(!dev->ops->phy_write16)) + return -ENOTSUPP; + + /* Generic implementation */ + if (link->aneg) { + dev->ops->phy_write16(dev, port, MII_BMCR, 0x0000); + dev->ops->phy_write16(dev, port, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); + } else { + u16 bmcr = 0; + + if (link->duplex) + bmcr |= BMCR_FULLDPLX; + + switch (link->speed) { + case SWITCH_PORT_SPEED_10: + break; + case SWITCH_PORT_SPEED_100: + bmcr |= BMCR_SPEED100; + break; + case SWITCH_PORT_SPEED_1000: + bmcr |= BMCR_SPEED1000; + break; + default: + return -ENOTSUPP; + } + + dev->ops->phy_write16(dev, port, MII_BMCR, bmcr); + } + + return 0; +} +EXPORT_SYMBOL_GPL(switch_generic_set_link); + +static int __init +swconfig_init(void) +{ + INIT_LIST_HEAD(&swdevs); + + return genl_register_family(&switch_fam); +} + +static void __exit +swconfig_exit(void) +{ + genl_unregister_family(&switch_fam); +} + +module_init(swconfig_init); +module_exit(swconfig_exit); diff --git a/ipq806x/files-5.4/drivers/net/phy/swconfig_leds.c b/ipq806x/files-5.4/drivers/net/phy/swconfig_leds.c new file mode 100644 index 0000000..df53e5c --- /dev/null +++ b/ipq806x/files-5.4/drivers/net/phy/swconfig_leds.c @@ -0,0 +1,555 @@ +/* + * swconfig_led.c: LED trigger support for the switch configuration API + * + * Copyright (C) 2011 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + */ + +#ifdef CONFIG_SWCONFIG_LEDS + +#include +#include +#include +#include + +#define SWCONFIG_LED_TIMER_INTERVAL (HZ / 10) +#define SWCONFIG_LED_NUM_PORTS 32 + +#define SWCONFIG_LED_PORT_SPEED_NA 0x01 /* unknown speed */ +#define SWCONFIG_LED_PORT_SPEED_10 0x02 /* 10 Mbps */ +#define SWCONFIG_LED_PORT_SPEED_100 0x04 /* 100 Mbps */ +#define SWCONFIG_LED_PORT_SPEED_1000 0x08 /* 1000 Mbps */ +#define SWCONFIG_LED_PORT_SPEED_ALL (SWCONFIG_LED_PORT_SPEED_NA | \ + SWCONFIG_LED_PORT_SPEED_10 | \ + SWCONFIG_LED_PORT_SPEED_100 | \ + SWCONFIG_LED_PORT_SPEED_1000) + +#define SWCONFIG_LED_MODE_LINK 0x01 +#define SWCONFIG_LED_MODE_TX 0x02 +#define SWCONFIG_LED_MODE_RX 0x04 +#define SWCONFIG_LED_MODE_TXRX (SWCONFIG_LED_MODE_TX | \ + SWCONFIG_LED_MODE_RX) +#define SWCONFIG_LED_MODE_ALL (SWCONFIG_LED_MODE_LINK | \ + SWCONFIG_LED_MODE_TX | \ + SWCONFIG_LED_MODE_RX) + +struct switch_led_trigger { + struct led_trigger trig; + struct switch_dev *swdev; + + struct delayed_work sw_led_work; + u32 port_mask; + u32 port_link; + unsigned long long port_tx_traffic[SWCONFIG_LED_NUM_PORTS]; + unsigned long long port_rx_traffic[SWCONFIG_LED_NUM_PORTS]; + u8 link_speed[SWCONFIG_LED_NUM_PORTS]; +}; + +struct swconfig_trig_data { + struct led_classdev *led_cdev; + struct switch_dev *swdev; + + rwlock_t lock; + u32 port_mask; + + bool prev_link; + unsigned long prev_traffic; + enum led_brightness prev_brightness; + u8 mode; + u8 speed_mask; +}; + +static void +swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data, + enum led_brightness brightness) +{ + led_set_brightness(trig_data->led_cdev, brightness); + trig_data->prev_brightness = brightness; +} + +static void +swconfig_trig_update_port_mask(struct led_trigger *trigger) +{ + struct list_head *entry; + struct switch_led_trigger *sw_trig; + u32 port_mask; + + if (!trigger) + return; + + sw_trig = (void *) trigger; + + port_mask = 0; + read_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + struct swconfig_trig_data *trig_data; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + trig_data = led_cdev->trigger_data; + if (trig_data) { + read_lock(&trig_data->lock); + port_mask |= trig_data->port_mask; + read_unlock(&trig_data->lock); + } + } + read_unlock(&trigger->leddev_list_lock); + + sw_trig->port_mask = port_mask; + + if (port_mask) + schedule_delayed_work(&sw_trig->sw_led_work, + SWCONFIG_LED_TIMER_INTERVAL); + else + cancel_delayed_work_sync(&sw_trig->sw_led_work); +} + +static ssize_t +swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + unsigned long port_mask; + int ret; + bool changed; + + ret = kstrtoul(buf, 0, &port_mask); + if (ret) + return ret; + + write_lock(&trig_data->lock); + changed = (trig_data->port_mask != port_mask); + trig_data->port_mask = port_mask; + write_unlock(&trig_data->lock); + + if (changed) { + if (port_mask == 0) + swconfig_trig_set_brightness(trig_data, LED_OFF); + + swconfig_trig_update_port_mask(led_cdev->trigger); + } + + return size; +} + +static ssize_t +swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u32 port_mask; + + read_lock(&trig_data->lock); + port_mask = trig_data->port_mask; + read_unlock(&trig_data->lock); + + sprintf(buf, "%#x\n", port_mask); + + return strlen(buf) + 1; +} + +static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show, + swconfig_trig_port_mask_store); + +/* speed_mask file handler - display value */ +static ssize_t swconfig_trig_speed_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u8 speed_mask; + + read_lock(&trig_data->lock); + speed_mask = trig_data->speed_mask; + read_unlock(&trig_data->lock); + + sprintf(buf, "%#x\n", speed_mask); + + return strlen(buf) + 1; +} + +/* speed_mask file handler - store value */ +static ssize_t swconfig_trig_speed_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u8 speed_mask; + int ret; + + ret = kstrtou8(buf, 0, &speed_mask); + if (ret) + return ret; + + write_lock(&trig_data->lock); + trig_data->speed_mask = speed_mask & SWCONFIG_LED_PORT_SPEED_ALL; + write_unlock(&trig_data->lock); + + return size; +} + +/* speed_mask special file */ +static DEVICE_ATTR(speed_mask, 0644, swconfig_trig_speed_mask_show, + swconfig_trig_speed_mask_store); + +static ssize_t swconfig_trig_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + u8 mode; + + read_lock(&trig_data->lock); + mode = trig_data->mode; + read_unlock(&trig_data->lock); + + if (mode == 0) { + strcpy(buf, "none\n"); + } else { + if (mode & SWCONFIG_LED_MODE_LINK) + strcat(buf, "link "); + if (mode & SWCONFIG_LED_MODE_TX) + strcat(buf, "tx "); + if (mode & SWCONFIG_LED_MODE_RX) + strcat(buf, "rx "); + strcat(buf, "\n"); + } + + return strlen(buf)+1; +} + +static ssize_t swconfig_trig_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct swconfig_trig_data *trig_data = led_cdev->trigger_data; + char copybuf[128]; + int new_mode = -1; + char *p, *token; + + /* take a copy since we don't want to trash the inbound buffer when using strsep */ + strncpy(copybuf, buf, sizeof(copybuf)); + copybuf[sizeof(copybuf) - 1] = 0; + p = copybuf; + + while ((token = strsep(&p, " \t\n")) != NULL) { + if (!*token) + continue; + + if (new_mode < 0) + new_mode = 0; + + if (!strcmp(token, "none")) + new_mode = 0; + else if (!strcmp(token, "tx")) + new_mode |= SWCONFIG_LED_MODE_TX; + else if (!strcmp(token, "rx")) + new_mode |= SWCONFIG_LED_MODE_RX; + else if (!strcmp(token, "link")) + new_mode |= SWCONFIG_LED_MODE_LINK; + else + return -EINVAL; + } + + if (new_mode < 0) + return -EINVAL; + + write_lock(&trig_data->lock); + trig_data->mode = (u8)new_mode; + write_unlock(&trig_data->lock); + + return size; +} + +/* mode special file */ +static DEVICE_ATTR(mode, 0644, swconfig_trig_mode_show, + swconfig_trig_mode_store); + +static int +swconfig_trig_activate(struct led_classdev *led_cdev) +{ + struct switch_led_trigger *sw_trig; + struct swconfig_trig_data *trig_data; + int err; + + trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL); + if (!trig_data) + return -ENOMEM; + + sw_trig = (void *) led_cdev->trigger; + + rwlock_init(&trig_data->lock); + trig_data->led_cdev = led_cdev; + trig_data->swdev = sw_trig->swdev; + trig_data->speed_mask = SWCONFIG_LED_PORT_SPEED_ALL; + trig_data->mode = SWCONFIG_LED_MODE_ALL; + led_cdev->trigger_data = trig_data; + + err = device_create_file(led_cdev->dev, &dev_attr_port_mask); + if (err) + goto err_free; + + err = device_create_file(led_cdev->dev, &dev_attr_speed_mask); + if (err) + goto err_dev_free; + + err = device_create_file(led_cdev->dev, &dev_attr_mode); + if (err) + goto err_mode_free; + + return 0; + +err_mode_free: + device_remove_file(led_cdev->dev, &dev_attr_speed_mask); + +err_dev_free: + device_remove_file(led_cdev->dev, &dev_attr_port_mask); + +err_free: + led_cdev->trigger_data = NULL; + kfree(trig_data); + + return err; +} + +static void +swconfig_trig_deactivate(struct led_classdev *led_cdev) +{ + struct swconfig_trig_data *trig_data; + + swconfig_trig_update_port_mask(led_cdev->trigger); + + trig_data = (void *) led_cdev->trigger_data; + if (trig_data) { + device_remove_file(led_cdev->dev, &dev_attr_port_mask); + device_remove_file(led_cdev->dev, &dev_attr_speed_mask); + device_remove_file(led_cdev->dev, &dev_attr_mode); + kfree(trig_data); + } +} + +/* + * link off -> led off (can't be any other reason to turn it on) + * link on: + * mode link: led on by default only if speed matches, else off + * mode txrx: blink only if speed matches, else off + */ +static void +swconfig_trig_led_event(struct switch_led_trigger *sw_trig, + struct led_classdev *led_cdev) +{ + struct swconfig_trig_data *trig_data; + u32 port_mask; + bool link; + u8 speed_mask, mode; + enum led_brightness led_base, led_blink; + + trig_data = led_cdev->trigger_data; + if (!trig_data) + return; + + read_lock(&trig_data->lock); + port_mask = trig_data->port_mask; + speed_mask = trig_data->speed_mask; + mode = trig_data->mode; + read_unlock(&trig_data->lock); + + link = !!(sw_trig->port_link & port_mask); + if (!link) { + if (trig_data->prev_brightness != LED_OFF) + swconfig_trig_set_brightness(trig_data, LED_OFF); /* and stop */ + } + else { + unsigned long traffic; + int speedok; /* link speed flag */ + int i; + + led_base = LED_FULL; + led_blink = LED_OFF; + traffic = 0; + speedok = 0; + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { + if (port_mask & (1 << i)) { + if (sw_trig->link_speed[i] & speed_mask) { + traffic += ((mode & SWCONFIG_LED_MODE_TX) ? + sw_trig->port_tx_traffic[i] : 0) + + ((mode & SWCONFIG_LED_MODE_RX) ? + sw_trig->port_rx_traffic[i] : 0); + speedok = 1; + } + } + } + + if (speedok) { + /* At least one port speed matches speed_mask */ + if (!(mode & SWCONFIG_LED_MODE_LINK)) { + led_base = LED_OFF; + led_blink = LED_FULL; + } + + if (trig_data->prev_brightness != led_base) + swconfig_trig_set_brightness(trig_data, + led_base); + else if (traffic != trig_data->prev_traffic) + swconfig_trig_set_brightness(trig_data, + led_blink); + } else if (trig_data->prev_brightness != LED_OFF) + swconfig_trig_set_brightness(trig_data, LED_OFF); + + trig_data->prev_traffic = traffic; + } + + trig_data->prev_link = link; +} + +static void +swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) +{ + struct list_head *entry; + struct led_trigger *trigger; + + trigger = &sw_trig->trig; + read_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + swconfig_trig_led_event(sw_trig, led_cdev); + } + read_unlock(&trigger->leddev_list_lock); +} + +static void +swconfig_led_work_func(struct work_struct *work) +{ + struct switch_led_trigger *sw_trig; + struct switch_dev *swdev; + u32 port_mask; + u32 link; + int i; + + sw_trig = container_of(work, struct switch_led_trigger, + sw_led_work.work); + + port_mask = sw_trig->port_mask; + swdev = sw_trig->swdev; + + link = 0; + for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) { + u32 port_bit; + + sw_trig->link_speed[i] = 0; + + port_bit = BIT(i); + if ((port_mask & port_bit) == 0) + continue; + + if (swdev->ops->get_port_link) { + struct switch_port_link port_link; + + memset(&port_link, '\0', sizeof(port_link)); + swdev->ops->get_port_link(swdev, i, &port_link); + + if (port_link.link) { + link |= port_bit; + switch (port_link.speed) { + case SWITCH_PORT_SPEED_UNKNOWN: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_NA; + break; + case SWITCH_PORT_SPEED_10: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_10; + break; + case SWITCH_PORT_SPEED_100: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_100; + break; + case SWITCH_PORT_SPEED_1000: + sw_trig->link_speed[i] = + SWCONFIG_LED_PORT_SPEED_1000; + break; + } + } + } + + if (swdev->ops->get_port_stats) { + struct switch_port_stats port_stats; + + memset(&port_stats, '\0', sizeof(port_stats)); + swdev->ops->get_port_stats(swdev, i, &port_stats); + sw_trig->port_tx_traffic[i] = port_stats.tx_bytes; + sw_trig->port_rx_traffic[i] = port_stats.rx_bytes; + } + } + + sw_trig->port_link = link; + + swconfig_trig_update_leds(sw_trig); + + schedule_delayed_work(&sw_trig->sw_led_work, + SWCONFIG_LED_TIMER_INTERVAL); +} + +static int +swconfig_create_led_trigger(struct switch_dev *swdev) +{ + struct switch_led_trigger *sw_trig; + int err; + + if (!swdev->ops->get_port_link) + return 0; + + sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL); + if (!sw_trig) + return -ENOMEM; + + sw_trig->swdev = swdev; + sw_trig->trig.name = swdev->devname; + sw_trig->trig.activate = swconfig_trig_activate; + sw_trig->trig.deactivate = swconfig_trig_deactivate; + + INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func); + + err = led_trigger_register(&sw_trig->trig); + if (err) + goto err_free; + + swdev->led_trigger = sw_trig; + + return 0; + +err_free: + kfree(sw_trig); + return err; +} + +static void +swconfig_destroy_led_trigger(struct switch_dev *swdev) +{ + struct switch_led_trigger *sw_trig; + + sw_trig = swdev->led_trigger; + if (sw_trig) { + cancel_delayed_work_sync(&sw_trig->sw_led_work); + led_trigger_unregister(&sw_trig->trig); + kfree(sw_trig); + } +} + +#else /* SWCONFIG_LEDS */ +static inline int +swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; } + +static inline void +swconfig_destroy_led_trigger(struct switch_dev *swdev) { } +#endif /* CONFIG_SWCONFIG_LEDS */ diff --git a/ipq806x/files-5.4/drivers/platform/mikrotik/Kconfig b/ipq806x/files-5.4/drivers/platform/mikrotik/Kconfig new file mode 100644 index 0000000..7499ba1 --- /dev/null +++ b/ipq806x/files-5.4/drivers/platform/mikrotik/Kconfig @@ -0,0 +1,19 @@ +menuconfig MIKROTIK + bool "Platform support for MikroTik RouterBoard virtual devices" + default n + help + Say Y here to get to see options for the MikroTik RouterBoard platform. + This option alone does not add any kernel code. + + +if MIKROTIK + +config MIKROTIK_RB_SYSFS + tristate "RouterBoot sysfs support" + depends on MTD + select LZO_DECOMPRESS + select CRC32 + help + This driver exposes RouterBoot configuration in sysfs. + +endif # MIKROTIK diff --git a/ipq806x/files-5.4/drivers/platform/mikrotik/Makefile b/ipq806x/files-5.4/drivers/platform/mikrotik/Makefile new file mode 100644 index 0000000..a232e1a --- /dev/null +++ b/ipq806x/files-5.4/drivers/platform/mikrotik/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for MikroTik RouterBoard platform specific drivers +# +obj-$(CONFIG_MIKROTIK_RB_SYSFS) += routerboot.o rb_hardconfig.o rb_softconfig.o diff --git a/ipq806x/files-5.4/drivers/platform/mikrotik/rb_hardconfig.c b/ipq806x/files-5.4/drivers/platform/mikrotik/rb_hardconfig.c new file mode 100644 index 0000000..e6a6928 --- /dev/null +++ b/ipq806x/files-5.4/drivers/platform/mikrotik/rb_hardconfig.c @@ -0,0 +1,825 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for MikroTik RouterBoot hard config. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This driver exposes the data encoded in the "hard_config" flash segment of + * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder + * named "hard_config". The WLAN calibration data is available on demand via + * the 'wlan_data' sysfs file in that folder. + * + * This driver permanently allocates a chunk of RAM as large as the hard_config + * MTD partition, although it is technically possible to operate entirely from + * the MTD device without using a local buffer (except when requesting WLAN + * calibration data), at the cost of a performance penalty. + * + * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show + * routines need not check for output overflow. + * + * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "routerboot.h" + +#define RB_HARDCONFIG_VER "0.06" +#define RB_HC_PR_PFX "[rb_hardconfig] " + +/* ID values for hardware settings */ +#define RB_ID_FLASH_INFO 0x03 +#define RB_ID_MAC_ADDRESS_PACK 0x04 +#define RB_ID_BOARD_PRODUCT_CODE 0x05 +#define RB_ID_BIOS_VERSION 0x06 +#define RB_ID_SDRAM_TIMINGS 0x08 +#define RB_ID_DEVICE_TIMINGS 0x09 +#define RB_ID_SOFTWARE_ID 0x0A +#define RB_ID_SERIAL_NUMBER 0x0B +#define RB_ID_MEMORY_SIZE 0x0D +#define RB_ID_MAC_ADDRESS_COUNT 0x0E +#define RB_ID_HW_OPTIONS 0x15 +#define RB_ID_WLAN_DATA 0x16 +#define RB_ID_BOARD_IDENTIFIER 0x17 +#define RB_ID_PRODUCT_NAME 0x21 +#define RB_ID_DEFCONF 0x26 +#define RB_ID_BOARD_REVISION 0x27 + +/* Bit definitions for hardware options */ +#define RB_HW_OPT_NO_UART BIT(0) +#define RB_HW_OPT_HAS_VOLTAGE BIT(1) +#define RB_HW_OPT_HAS_USB BIT(2) +#define RB_HW_OPT_HAS_ATTINY BIT(3) +#define RB_HW_OPT_PULSE_DUTY_CYCLE BIT(9) +#define RB_HW_OPT_NO_NAND BIT(14) +#define RB_HW_OPT_HAS_LCD BIT(15) +#define RB_HW_OPT_HAS_POE_OUT BIT(16) +#define RB_HW_OPT_HAS_uSD BIT(17) +#define RB_HW_OPT_HAS_SIM BIT(18) +#define RB_HW_OPT_HAS_SFP BIT(20) +#define RB_HW_OPT_HAS_WIFI BIT(21) +#define RB_HW_OPT_HAS_TS_FOR_ADC BIT(22) +#define RB_HW_OPT_HAS_PLC BIT(29) + +/* + * Tag ID values for ERD data. + * Mikrotik used to pack all calibration data under a single tag id 0x1, but + * recently switched to a new scheme where each radio calibration gets a + * separate tag. The new scheme has tag id bit 15 always set and seems to be + * mutually exclusive with the old scheme. + */ +#define RB_WLAN_ERD_ID_SOLO 0x0001 +#define RB_WLAN_ERD_ID_MULTI_8001 0x8001 +#define RB_WLAN_ERD_ID_MULTI_8201 0x8201 + +static struct kobject *hc_kobj; +static u8 *hc_buf; // ro buffer after init(): no locking required +static size_t hc_buflen; + +/* + * For LZOR style WLAN data unpacking. + * This binary blob is prepended to the data encoded on some devices as + * RB_ID_WLAN_DATA, the result is then first decompressed with LZO, and then + * finally RLE-decoded. + * This binary blob has been extracted from RouterOS by + * https://forum.openwrt.org/u/ius + */ +static const u8 hc_lzor_prefix[] = { + 0x00, 0x05, 0x4c, 0x4c, 0x44, 0x00, 0x34, 0xfe, + 0xfe, 0x34, 0x11, 0x3c, 0x1e, 0x3c, 0x2e, 0x3c, + 0x4c, 0x34, 0x00, 0x52, 0x62, 0x92, 0xa2, 0xb2, + 0xc3, 0x2a, 0x14, 0x00, 0x00, 0x05, 0xfe, 0x6a, + 0x3c, 0x16, 0x32, 0x16, 0x11, 0x1e, 0x12, 0x46, + 0x32, 0x46, 0x11, 0x4e, 0x12, 0x36, 0x32, 0x36, + 0x11, 0x3e, 0x12, 0x5a, 0x9a, 0x64, 0x00, 0x04, + 0xfe, 0x10, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x28, + 0x0c, 0x00, 0x0f, 0xfe, 0x14, 0x00, 0x24, 0x24, + 0x23, 0x24, 0x24, 0x23, 0x25, 0x22, 0x21, 0x21, + 0x23, 0x22, 0x21, 0x22, 0x21, 0x2d, 0x38, 0x00, + 0x0c, 0x25, 0x25, 0x24, 0x25, 0x25, 0x24, 0x23, + 0x22, 0x21, 0x20, 0x23, 0x21, 0x21, 0x22, 0x21, + 0x2d, 0x38, 0x00, 0x28, 0xb0, 0x00, 0x00, 0x22, + 0x00, 0x00, 0xc0, 0xfe, 0x03, 0x00, 0xc0, 0x00, + 0x62, 0xff, 0x62, 0xff, 0xfe, 0x06, 0x00, 0xbb, + 0xff, 0xba, 0xff, 0xfe, 0x08, 0x00, 0x9e, 0xff, + 0xfe, 0x0a, 0x00, 0x53, 0xff, 0xfe, 0x02, 0x00, + 0x20, 0xff, 0xb1, 0xfe, 0xfe, 0xb2, 0xfe, 0xfe, + 0xed, 0xfe, 0xfe, 0xfe, 0x04, 0x00, 0x3a, 0xff, + 0x3a, 0xff, 0xde, 0xfd, 0x5f, 0x04, 0x33, 0xff, + 0x4c, 0x74, 0x03, 0x05, 0x05, 0xff, 0x6d, 0xfe, + 0xfe, 0x6d, 0xfe, 0xfe, 0xaf, 0x08, 0x63, 0xff, + 0x64, 0x6f, 0x08, 0xac, 0xff, 0xbf, 0x6d, 0x08, + 0x7a, 0x6d, 0x08, 0x96, 0x74, 0x04, 0x00, 0x08, + 0x79, 0xff, 0xda, 0xfe, 0xfe, 0xdb, 0xfe, 0xfe, + 0x56, 0xff, 0xfe, 0x04, 0x00, 0x5e, 0xff, 0x5e, + 0xff, 0x6c, 0xfe, 0xfe, 0xfe, 0x06, 0x00, 0x41, + 0xff, 0x7f, 0x74, 0x03, 0x00, 0x11, 0x44, 0xff, + 0xa9, 0xfe, 0xfe, 0xa9, 0xfe, 0xfe, 0xa5, 0x8f, + 0x01, 0x00, 0x08, 0x01, 0x01, 0x02, 0x04, 0x08, + 0x02, 0x04, 0x08, 0x08, 0x01, 0x01, 0xfe, 0x22, + 0x00, 0x4c, 0x60, 0x64, 0x8c, 0x90, 0xd0, 0xd4, + 0xd8, 0x5c, 0x10, 0x09, 0xd8, 0xff, 0xb0, 0xff, + 0x00, 0x00, 0xba, 0xff, 0x14, 0x00, 0xba, 0xff, + 0x64, 0x00, 0x00, 0x08, 0xfe, 0x06, 0x00, 0x74, + 0xff, 0x42, 0xff, 0xce, 0xff, 0x60, 0xff, 0x0a, + 0x00, 0xb4, 0x00, 0xa0, 0x00, 0xa0, 0xfe, 0x07, + 0x00, 0x0a, 0x00, 0xb0, 0xff, 0x96, 0x4d, 0x00, + 0x56, 0x57, 0x18, 0xa6, 0xff, 0x92, 0x70, 0x11, + 0x00, 0x12, 0x90, 0x90, 0x76, 0x5a, 0x54, 0x54, + 0x4c, 0x46, 0x38, 0x00, 0x10, 0x10, 0x08, 0xfe, + 0x05, 0x00, 0x38, 0x29, 0x25, 0x23, 0x22, 0x22, + 0x1f, 0x00, 0x00, 0x00, 0xf6, 0xe1, 0xdd, 0xf8, + 0xfe, 0x00, 0xfe, 0x15, 0x00, 0x00, 0xd0, 0x02, + 0x74, 0x02, 0x08, 0xf8, 0xe5, 0xde, 0x02, 0x04, + 0x04, 0xfd, 0x00, 0x00, 0x00, 0x07, 0x50, 0x2d, + 0x01, 0x90, 0x90, 0x76, 0x60, 0xb0, 0x07, 0x07, + 0x0c, 0x0c, 0x04, 0xfe, 0x05, 0x00, 0x66, 0x66, + 0x5a, 0x56, 0xbc, 0x01, 0x06, 0xfc, 0xfc, 0xf1, + 0xfe, 0x07, 0x00, 0x24, 0x95, 0x70, 0x64, 0x18, + 0x06, 0x2c, 0xff, 0xb5, 0xfe, 0xfe, 0xb5, 0xfe, + 0xfe, 0xe2, 0x8c, 0x24, 0x02, 0x2f, 0xff, 0x2f, + 0xff, 0xb4, 0x78, 0x02, 0x05, 0x73, 0xff, 0xed, + 0xfe, 0xfe, 0x4f, 0xff, 0x36, 0x74, 0x1e, 0x09, + 0x4f, 0xff, 0x50, 0xff, 0xfe, 0x16, 0x00, 0x70, + 0xac, 0x70, 0x8e, 0xac, 0x40, 0x0e, 0x01, 0x70, + 0x7f, 0x8e, 0xac, 0x6c, 0x00, 0x0b, 0xfe, 0x02, + 0x00, 0xfe, 0x0a, 0x2c, 0x2a, 0x2a, 0x28, 0x26, + 0x1e, 0x1e, 0xfe, 0x02, 0x20, 0x65, 0x20, 0x00, + 0x00, 0x05, 0x12, 0x00, 0x11, 0x1e, 0x11, 0x11, + 0x41, 0x1e, 0x41, 0x11, 0x31, 0x1e, 0x31, 0x11, + 0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93, + 0x98, 0x30, 0x20, 0x00, 0x02, 0x00, 0xfe, 0x06, + 0x3c, 0xbc, 0x32, 0x0c, 0x00, 0x00, 0x2a, 0x12, + 0x1e, 0x12, 0x2e, 0x12, 0xcc, 0x12, 0x11, 0x1a, + 0x1e, 0x1a, 0x2e, 0x1a, 0x4c, 0x10, 0x1e, 0x10, + 0x11, 0x18, 0x1e, 0x42, 0x1e, 0x42, 0x2e, 0x42, + 0xcc, 0x42, 0x11, 0x4a, 0x1e, 0x4a, 0x2e, 0x4a, + 0x4c, 0x40, 0x1e, 0x40, 0x11, 0x48, 0x1e, 0x32, + 0x1e, 0x32, 0x2e, 0x32, 0xcc, 0x32, 0x11, 0x3a, + 0x1e, 0x3a, 0x2e, 0x3a, 0x4c, 0x30, 0x1e, 0x30, + 0x11, 0x38, 0x1e, 0x27, 0x9a, 0x01, 0x9d, 0xa2, + 0x2f, 0x28, 0x00, 0x00, 0x46, 0xde, 0xc4, 0xbf, + 0xa6, 0x9d, 0x81, 0x7b, 0x5c, 0x61, 0x40, 0xc7, + 0xc0, 0xae, 0xa9, 0x8c, 0x83, 0x6a, 0x62, 0x50, + 0x3e, 0xce, 0xc2, 0xae, 0xa3, 0x8c, 0x7b, 0x6a, + 0x5a, 0x50, 0x35, 0xd7, 0xc2, 0xb7, 0xa4, 0x95, + 0x7e, 0x72, 0x5a, 0x59, 0x37, 0xfe, 0x02, 0xf8, + 0x8c, 0x95, 0x90, 0x8f, 0x00, 0xd7, 0xc0, 0xb7, + 0xa2, 0x95, 0x7b, 0x72, 0x56, 0x59, 0x32, 0xc7, + 0xc3, 0xae, 0xad, 0x8c, 0x85, 0x6a, 0x63, 0x50, + 0x3e, 0xce, 0xc3, 0xae, 0xa4, 0x8c, 0x7c, 0x6a, + 0x59, 0x50, 0x34, 0xd7, 0xc2, 0xb7, 0xa5, 0x95, + 0x7e, 0x72, 0x59, 0x59, 0x36, 0xfc, 0x05, 0x00, + 0x02, 0xce, 0xc5, 0xae, 0xa5, 0x95, 0x83, 0x72, + 0x5c, 0x59, 0x36, 0xbf, 0xc6, 0xa5, 0xab, 0x8c, + 0x8c, 0x6a, 0x67, 0x50, 0x41, 0x64, 0x07, 0x00, + 0x02, 0x95, 0x8c, 0x72, 0x65, 0x59, 0x3f, 0xce, + 0xc7, 0xae, 0xa8, 0x95, 0x86, 0x72, 0x5f, 0x59, + 0x39, 0xfe, 0x02, 0xf8, 0x8b, 0x7c, 0x0b, 0x09, + 0xb7, 0xc2, 0x9d, 0xa4, 0x83, 0x85, 0x6a, 0x6b, + 0x50, 0x44, 0xb7, 0xc1, 0x64, 0x01, 0x00, 0x06, + 0x61, 0x5d, 0x48, 0x3d, 0xae, 0xc4, 0x9d, 0xad, + 0x7b, 0x85, 0x61, 0x66, 0x48, 0x46, 0xae, 0xc3, + 0x95, 0xa3, 0x72, 0x7c, 0x59, 0x56, 0x38, 0x31, + 0x7c, 0x0b, 0x00, 0x0c, 0x96, 0x91, 0x8f, 0x00, + 0xb7, 0xc0, 0xa5, 0xab, 0x8c, 0x8a, 0x6a, 0x64, + 0x50, 0x3c, 0xb7, 0xc0, 0x9d, 0xa0, 0x83, 0x80, + 0x6a, 0x64, 0x50, 0x3d, 0xb7, 0xc5, 0x9d, 0xa5, + 0x83, 0x87, 0x6c, 0x08, 0x07, 0xae, 0xc0, 0x9d, + 0xa8, 0x83, 0x88, 0x6a, 0x6d, 0x50, 0x46, 0xfc, + 0x05, 0x00, 0x16, 0xbf, 0xc0, 0xa5, 0xa2, 0x8c, + 0x7f, 0x6a, 0x57, 0x50, 0x2f, 0xb7, 0xc7, 0xa5, + 0xb1, 0x8c, 0x8e, 0x72, 0x6d, 0x59, 0x45, 0xbf, + 0xc6, 0xa5, 0xa8, 0x8c, 0x87, 0x6a, 0x5f, 0x50, + 0x37, 0xbf, 0xc2, 0xa5, 0xa4, 0x8c, 0x83, 0x6a, + 0x5c, 0x50, 0x34, 0xbc, 0x05, 0x00, 0x0e, 0x90, + 0x00, 0xc7, 0xc2, 0xae, 0xaa, 0x95, 0x82, 0x7b, + 0x60, 0x61, 0x3f, 0xb7, 0xc6, 0xa5, 0xb1, 0x8c, + 0x8d, 0x72, 0x6b, 0x61, 0x51, 0xbf, 0xc4, 0xa5, + 0xa5, 0x8c, 0x82, 0x72, 0x61, 0x59, 0x39, 0x6c, + 0x26, 0x03, 0x95, 0x82, 0x7b, 0x61, 0x61, 0x40, + 0xfc, 0x05, 0x00, 0x00, 0x7e, 0xd7, 0xc3, 0xb7, + 0xa8, 0x9d, 0x80, 0x83, 0x5d, 0x6a, 0x3f, 0xbf, + 0xc7, 0xa5, 0xa8, 0x8c, 0x84, 0x72, 0x60, 0x61, + 0x46, 0xbf, 0xc2, 0xae, 0xb0, 0x9d, 0x92, 0x83, + 0x6f, 0x6a, 0x50, 0xd7, 0xc3, 0xb7, 0xa7, 0x9d, + 0x80, 0x83, 0x5e, 0x6a, 0x40, 0xfe, 0x02, 0xf8, + 0x8d, 0x96, 0x90, 0x90, 0xfe, 0x05, 0x00, 0x8a, + 0xc4, 0x63, 0xb8, 0x3c, 0xa6, 0x29, 0x97, 0x16, + 0x81, 0x84, 0xb7, 0x5b, 0xa9, 0x33, 0x94, 0x1e, + 0x83, 0x11, 0x70, 0xb8, 0xc2, 0x70, 0xb1, 0x4d, + 0xa3, 0x2a, 0x8d, 0x1b, 0x7b, 0xa8, 0xbc, 0x68, + 0xab, 0x47, 0x9d, 0x27, 0x87, 0x18, 0x75, 0xae, + 0xc6, 0x7d, 0xbb, 0x4d, 0xaa, 0x1c, 0x84, 0x11, + 0x72, 0xa3, 0xbb, 0x6e, 0xad, 0x3c, 0x97, 0x24, + 0x85, 0x16, 0x71, 0x80, 0xb2, 0x57, 0xa4, 0x30, + 0x8e, 0x1c, 0x7c, 0x10, 0x68, 0xbb, 0xbd, 0x75, + 0xac, 0x4f, 0x9e, 0x2b, 0x87, 0x1a, 0x76, 0x96, + 0xc5, 0x5e, 0xb5, 0x3e, 0xa5, 0x1f, 0x8c, 0x12, + 0x7a, 0xc1, 0xc6, 0x42, 0x9f, 0x27, 0x8c, 0x16, + 0x77, 0x0f, 0x67, 0x9d, 0xbc, 0x68, 0xad, 0x36, + 0x95, 0x20, 0x83, 0x11, 0x6d, 0x9b, 0xb8, 0x67, + 0xa8, 0x34, 0x90, 0x1f, 0x7c, 0x10, 0x67, 0x9e, + 0xc9, 0x6a, 0xbb, 0x37, 0xa4, 0x20, 0x90, 0x11, + 0x7b, 0xc6, 0xc8, 0x47, 0xa4, 0x2a, 0x90, 0x18, + 0x7b, 0x10, 0x6c, 0xae, 0xc4, 0x5d, 0xad, 0x37, + 0x9a, 0x1f, 0x85, 0x13, 0x75, 0x70, 0xad, 0x42, + 0x99, 0x25, 0x84, 0x17, 0x74, 0x0b, 0x56, 0x87, + 0xc8, 0x57, 0xb8, 0x2b, 0x9e, 0x19, 0x8a, 0x0d, + 0x74, 0xa7, 0xc8, 0x6e, 0xb9, 0x36, 0xa0, 0x1f, + 0x8b, 0x11, 0x75, 0x94, 0xbe, 0x4b, 0xa5, 0x2a, + 0x92, 0x18, 0x7c, 0x0f, 0x6b, 0xaf, 0xc0, 0x58, + 0xa8, 0x34, 0x94, 0x1d, 0x7d, 0x12, 0x6d, 0x82, + 0xc0, 0x52, 0xb0, 0x25, 0x94, 0x14, 0x7f, 0x0c, + 0x68, 0x84, 0xbf, 0x3e, 0xa4, 0x22, 0x8e, 0x10, + 0x76, 0x0b, 0x65, 0x88, 0xb6, 0x42, 0x9b, 0x26, + 0x87, 0x14, 0x70, 0x0c, 0x5f, 0xc5, 0xc2, 0x3e, + 0x97, 0x23, 0x83, 0x13, 0x6c, 0x0c, 0x5c, 0xb1, + 0xc9, 0x76, 0xbc, 0x4a, 0xaa, 0x20, 0x8d, 0x12, + 0x78, 0x93, 0xbf, 0x46, 0xa3, 0x26, 0x8d, 0x14, + 0x74, 0x0c, 0x62, 0xc8, 0xc4, 0x3b, 0x97, 0x21, + 0x82, 0x11, 0x6a, 0x0a, 0x59, 0xa3, 0xb9, 0x68, + 0xa9, 0x30, 0x8d, 0x1a, 0x78, 0x0f, 0x61, 0xa0, + 0xc9, 0x73, 0xbe, 0x50, 0xb1, 0x30, 0x9f, 0x14, + 0x80, 0x83, 0xb7, 0x3c, 0x9a, 0x20, 0x84, 0x0e, + 0x6a, 0x0a, 0x57, 0xac, 0xc2, 0x68, 0xb0, 0x2e, + 0x92, 0x19, 0x7c, 0x0d, 0x63, 0x93, 0xbe, 0x62, + 0xb0, 0x3c, 0x9e, 0x1a, 0x80, 0x0e, 0x6b, 0xbb, + 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x6f, 0x00, 0x75, + 0x00, 0x75, 0x00, 0x00, 0x00, 0xad, 0x02, 0xb3, + 0x02, 0x6f, 0x00, 0x87, 0x00, 0x85, 0xfe, 0x03, + 0x00, 0xc2, 0x02, 0x82, 0x4d, 0x92, 0x6e, 0x4d, + 0xb1, 0xa8, 0x84, 0x01, 0x00, 0x07, 0x7e, 0x00, + 0xa8, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xa2, 0x00, + 0xa6, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb4, 0x02, + 0xb4, 0x02, 0x92, 0x00, 0x96, 0x00, 0x96, 0x46, + 0x04, 0xb0, 0x02, 0x64, 0x02, 0x0a, 0x8c, 0x00, + 0x90, 0x02, 0x98, 0x02, 0x98, 0x02, 0x0e, 0x01, + 0x11, 0x01, 0x11, 0x50, 0xc3, 0x08, 0x88, 0x02, + 0x88, 0x02, 0x19, 0x01, 0x02, 0x01, 0x02, 0x01, + 0xf3, 0x2d, 0x00, 0x00 +}; + +/* Array of known hw_options bits with human-friendly parsing */ +static struct hc_hwopt { + const u32 bit; + const char *str; +} const hc_hwopts[] = { + { + .bit = RB_HW_OPT_NO_UART, + .str = "no UART\t\t", + }, { + .bit = RB_HW_OPT_HAS_VOLTAGE, + .str = "has Vreg\t", + }, { + .bit = RB_HW_OPT_HAS_USB, + .str = "has usb\t\t", + }, { + .bit = RB_HW_OPT_HAS_ATTINY, + .str = "has ATtiny\t", + }, { + .bit = RB_HW_OPT_NO_NAND, + .str = "no NAND\t\t", + }, { + .bit = RB_HW_OPT_HAS_LCD, + .str = "has LCD\t\t", + }, { + .bit = RB_HW_OPT_HAS_POE_OUT, + .str = "has POE out\t", + }, { + .bit = RB_HW_OPT_HAS_uSD, + .str = "has MicroSD\t", + }, { + .bit = RB_HW_OPT_HAS_SIM, + .str = "has SIM\t\t", + }, { + .bit = RB_HW_OPT_HAS_SFP, + .str = "has SFP\t\t", + }, { + .bit = RB_HW_OPT_HAS_WIFI, + .str = "has WiFi\t", + }, { + .bit = RB_HW_OPT_HAS_TS_FOR_ADC, + .str = "has TS ADC\t", + }, { + .bit = RB_HW_OPT_HAS_PLC, + .str = "has PLC\t\t", + }, +}; + +/* + * The MAC is stored network-endian on all devices, in 2 32-bit segments: + * . Kernel print has us covered. + */ +static ssize_t hc_tag_show_mac(const u8 *pld, u16 pld_len, char *buf) +{ + if (8 != pld_len) + return -EINVAL; + + return sprintf(buf, "%pM\n", pld); +} + +/* + * Print HW options in a human readable way: + * The raw number and in decoded form + */ +static ssize_t hc_tag_show_hwoptions(const u8 *pld, u16 pld_len, char *buf) +{ + char *out = buf; + u32 data; // cpu-endian + int i; + + if (sizeof(data) != pld_len) + return -EINVAL; + + data = *(u32 *)pld; + out += sprintf(out, "raw\t\t: 0x%08x\n\n", data); + + for (i = 0; i < ARRAY_SIZE(hc_hwopts); i++) + out += sprintf(out, "%s: %s\n", hc_hwopts[i].str, + (data & hc_hwopts[i].bit) ? "true" : "false"); + + return out - buf; +} + +static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count); + +static struct hc_wlan_attr { + const u16 erd_tag_id; + struct bin_attribute battr; + u16 pld_ofs; + u16 pld_len; +} hc_wd_multi_battrs[] = { + { + .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8001, + .battr = __BIN_ATTR(data_0, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), + }, { + .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8201, + .battr = __BIN_ATTR(data_2, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), + } +}; + +static struct hc_wlan_attr hc_wd_solo_battr = { + .erd_tag_id = RB_WLAN_ERD_ID_SOLO, + .battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0), +}; + +static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); + +/* Array of known tags to publish in sysfs */ +static struct hc_attr { + const u16 tag_id; + ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf); + struct kobj_attribute kattr; + u16 pld_ofs; + u16 pld_len; +} hc_attrs[] = { + { + .tag_id = RB_ID_FLASH_INFO, + .tshow = routerboot_tag_show_u32s, + .kattr = __ATTR(flash_info, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_MAC_ADDRESS_PACK, + .tshow = hc_tag_show_mac, + .kattr = __ATTR(mac_base, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_BOARD_PRODUCT_CODE, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_product_code, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_BIOS_VERSION, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(booter_version, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_SERIAL_NUMBER, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_serial, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_MEMORY_SIZE, + .tshow = routerboot_tag_show_u32s, + .kattr = __ATTR(mem_size, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_MAC_ADDRESS_COUNT, + .tshow = routerboot_tag_show_u32s, + .kattr = __ATTR(mac_count, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_HW_OPTIONS, + .tshow = hc_tag_show_hwoptions, + .kattr = __ATTR(hw_options, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_WLAN_DATA, + .tshow = NULL, + }, { + .tag_id = RB_ID_BOARD_IDENTIFIER, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_identifier, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_PRODUCT_NAME, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(product_name, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_DEFCONF, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(defconf, S_IRUSR, hc_attr_show, NULL), + }, { + .tag_id = RB_ID_BOARD_REVISION, + .tshow = routerboot_tag_show_string, + .kattr = __ATTR(board_revision, S_IRUSR, hc_attr_show, NULL), + } +}; + +/* + * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past + * that magic number the payload itself contains a routerboot tag node + * locating the LZO-compressed calibration data. So far this scheme is only + * known to use a single tag at id 0x1. + */ +static int hc_wlan_data_unpack_erd(const u16 tag_id, const u8 *inbuf, size_t inlen, + void *outbuf, size_t *outlen) +{ + u16 lzo_ofs, lzo_len; + int ret; + + /* Find embedded tag */ + ret = routerboot_tag_find(inbuf, inlen, tag_id, &lzo_ofs, &lzo_len); + if (ret) { + pr_debug(RB_HC_PR_PFX "no ERD data for id 0x%04x\n", tag_id); + goto fail; + } + + if (lzo_len > inlen) { + pr_debug(RB_HC_PR_PFX "Invalid ERD data length\n"); + ret = -EINVAL; + goto fail; + } + + ret = lzo1x_decompress_safe(inbuf+lzo_ofs, lzo_len, outbuf, outlen); + if (ret) + pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret); + +fail: + return ret; +} + +/* + * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_LZOR, then past + * that magic number is a payload that must be appended to the hc_lzor_prefix, + * the resulting blob is LZO-compressed. In the LZO decompression result, + * the RB_MAGIC_ERD magic number (aligned) must be located. Following that + * magic, there is one or more routerboot tag node(s) locating the RLE-encoded + * calibration data payload. + */ +static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, size_t inlen, + void *outbuf, size_t *outlen) +{ + u16 rle_ofs, rle_len; + const u32 *needle; + u8 *tempbuf; + size_t templen, lzo_len; + int ret; + + lzo_len = inlen + sizeof(hc_lzor_prefix); + if (lzo_len > *outlen) + return -EFBIG; + + /* Temporary buffer same size as the outbuf */ + templen = *outlen; + tempbuf = kmalloc(templen, GFP_KERNEL); + if (!tempbuf) + return -ENOMEM; + + /* Concatenate into the outbuf */ + memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); + memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); + + /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */ + ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen); + if (ret) { + if (LZO_E_INPUT_NOT_CONSUMED == ret) { + /* + * The tag length is always aligned thus the LZO payload may be padded, + * which can trigger a spurious error which we ignore here. + */ + pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n"); + } else { + pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret); + goto fail; + } + } + + /* + * Post decompression we have a blob (possibly byproduct of the lzo + * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to + * be 32bit-aligned in the decompression output. + */ + needle = (const u32 *)tempbuf; + while (RB_MAGIC_ERD != *needle++) { + if ((u8 *)needle >= tempbuf+templen) { + pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n"); + ret = -ENODATA; + goto fail; + } + }; + templen -= (u8 *)needle - tempbuf; + + /* Past magic. Look for tag node */ + ret = routerboot_tag_find((u8 *)needle, templen, tag_id, &rle_ofs, &rle_len); + if (ret) { + pr_debug(RB_HC_PR_PFX "LZOR: no RLE data for id 0x%04x\n", tag_id); + goto fail; + } + + if (rle_len > templen) { + pr_debug(RB_HC_PR_PFX "LZOR: Invalid RLE data length\n"); + ret = -EINVAL; + goto fail; + } + + /* RLE-decode tempbuf from needle back into the outbuf */ + ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen); + if (ret) + pr_debug(RB_HC_PR_PFX "LZOR: RLE decoding error (%d)\n", ret); + +fail: + kfree(tempbuf); + return ret; +} + +static int hc_wlan_data_unpack(const u16 tag_id, const size_t tofs, size_t tlen, + void *outbuf, size_t *outlen) +{ + const u8 *lbuf; + u32 magic; + int ret; + + /* Caller ensure tlen > 0. tofs is aligned */ + if ((tofs + tlen) > hc_buflen) + return -EIO; + + lbuf = hc_buf + tofs; + magic = *(u32 *)lbuf; + + ret = -ENODATA; + switch (magic) { + case RB_MAGIC_LZOR: + /* Skip magic */ + lbuf += sizeof(magic); + tlen -= sizeof(magic); + ret = hc_wlan_data_unpack_lzor(tag_id, lbuf, tlen, outbuf, outlen); + break; + case RB_MAGIC_ERD: + /* Skip magic */ + lbuf += sizeof(magic); + tlen -= sizeof(magic); + ret = hc_wlan_data_unpack_erd(tag_id, lbuf, tlen, outbuf, outlen); + break; + default: + /* + * If the RB_ID_WLAN_DATA payload doesn't start with a + * magic number, the payload itself is the raw RLE-encoded + * calibration data. Only RB_WLAN_ERD_ID_SOLO makes sense here. + */ + if (RB_WLAN_ERD_ID_SOLO == tag_id) { + ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen); + if (ret) + pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret); + } + break; + } + + return ret; +} + +static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const struct hc_attr *hc_attr; + const u8 *pld; + u16 pld_len; + + hc_attr = container_of(attr, typeof(*hc_attr), kattr); + + if (!hc_attr->pld_len) + return -ENOENT; + + pld = hc_buf + hc_attr->pld_ofs; + pld_len = hc_attr->pld_len; + + return hc_attr->tshow(pld, pld_len, buf); +} + +/* + * This function will allocate and free memory every time it is called. This + * is not the fastest way to do this, but since the data is rarely read (mainly + * at boot time to load wlan caldata), this makes it possible to save memory for + * the system. + */ +static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct hc_wlan_attr *hc_wattr; + size_t outlen; + void *outbuf; + int ret; + + hc_wattr = container_of(attr, typeof(*hc_wattr), battr); + + if (!hc_wattr->pld_len) + return -ENOENT; + + outlen = RB_ART_SIZE; + + /* Don't bother unpacking if the source is already too large */ + if (hc_wattr->pld_len > outlen) + return -EFBIG; + + outbuf = kmalloc(outlen, GFP_KERNEL); + if (!outbuf) + return -ENOMEM; + + ret = hc_wlan_data_unpack(hc_wattr->erd_tag_id, hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, &outlen); + if (ret) { + kfree(outbuf); + return ret; + } + + if (off >= outlen) { + kfree(outbuf); + return 0; + } + + if (off + count > outlen) + count = outlen - off; + + memcpy(buf, outbuf + off, count); + + kfree(outbuf); + return count; +} + +int __init rb_hardconfig_init(struct kobject *rb_kobj) +{ + struct kobject *hc_wlan_kobj; + struct mtd_info *mtd; + size_t bytes_read, buflen, outlen; + const u8 *buf; + void *outbuf; + int i, j, ret; + u32 magic; + + hc_buf = NULL; + hc_kobj = NULL; + hc_wlan_kobj = NULL; + + // TODO allow override + mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG); + if (IS_ERR(mtd)) + return -ENODEV; + + hc_buflen = mtd->size; + hc_buf = kmalloc(hc_buflen, GFP_KERNEL); + if (!hc_buf) { + put_mtd_device(mtd); + return -ENOMEM; + } + + ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf); + put_mtd_device(mtd); + + if (ret) + goto fail; + + if (bytes_read != hc_buflen) { + ret = -EIO; + goto fail; + } + + /* Check we have what we expect */ + magic = *(const u32 *)hc_buf; + if (RB_MAGIC_HARD != magic) { + ret = -EINVAL; + goto fail; + } + + /* Skip magic */ + buf = hc_buf + sizeof(magic); + buflen = hc_buflen - sizeof(magic); + + /* Populate sysfs */ + ret = -ENOMEM; + hc_kobj = kobject_create_and_add(RB_MTD_HARD_CONFIG, rb_kobj); + if (!hc_kobj) + goto fail; + + /* Locate and publish all known tags */ + for (i = 0; i < ARRAY_SIZE(hc_attrs); i++) { + ret = routerboot_tag_find(buf, buflen, hc_attrs[i].tag_id, + &hc_attrs[i].pld_ofs, &hc_attrs[i].pld_len); + if (ret) { + hc_attrs[i].pld_ofs = hc_attrs[i].pld_len = 0; + continue; + } + + /* Account for skipped magic */ + hc_attrs[i].pld_ofs += sizeof(magic); + + /* + * Special case RB_ID_WLAN_DATA to prep and create the binary attribute. + * We first check if the data is "old style" within a single tag (or no tag at all): + * If it is we publish this single blob as a binary attribute child of hc_kobj to + * preserve backward compatibility. + * If it isn't and instead uses multiple ERD tags, we create a subfolder and + * publish the known ones there. + */ + if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && hc_attrs[i].pld_len) { + outlen = RB_ART_SIZE; + outbuf = kmalloc(outlen, GFP_KERNEL); + if (!outbuf) { + pr_warn(RB_HC_PR_PFX "Out of memory parsing WLAN tag\n"); + continue; + } + + /* Test ID_SOLO first, if found: done */ + ret = hc_wlan_data_unpack(RB_WLAN_ERD_ID_SOLO, hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); + if (!ret) { + hc_wd_solo_battr.pld_ofs = hc_attrs[i].pld_ofs; + hc_wd_solo_battr.pld_len = hc_attrs[i].pld_len; + + ret = sysfs_create_bin_file(hc_kobj, &hc_wd_solo_battr.battr); + if (ret) + pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n", + hc_wd_solo_battr.battr.attr.name, ret); + } + /* Otherwise, create "wlan_data" subtree and publish known data */ + else { + hc_wlan_kobj = kobject_create_and_add("wlan_data", hc_kobj); + if (!hc_wlan_kobj) { + kfree(outbuf); + pr_warn(RB_HC_PR_PFX "Could not create wlan_data sysfs folder\n"); + continue; + } + + for (j = 0; j < ARRAY_SIZE(hc_wd_multi_battrs); j++) { + outlen = RB_ART_SIZE; + ret = hc_wlan_data_unpack(hc_wd_multi_battrs[j].erd_tag_id, + hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen); + if (ret) { + hc_wd_multi_battrs[j].pld_ofs = hc_wd_multi_battrs[j].pld_len = 0; + continue; + } + + hc_wd_multi_battrs[j].pld_ofs = hc_attrs[i].pld_ofs; + hc_wd_multi_battrs[j].pld_len = hc_attrs[i].pld_len; + + ret = sysfs_create_bin_file(hc_wlan_kobj, &hc_wd_multi_battrs[j].battr); + if (ret) + pr_warn(RB_HC_PR_PFX "Could not create wlan_data/%s sysfs entry (%d)\n", + hc_wd_multi_battrs[j].battr.attr.name, ret); + } + } + + kfree(outbuf); + } + /* All other tags are published via standard attributes */ + else { + ret = sysfs_create_file(hc_kobj, &hc_attrs[i].kattr.attr); + if (ret) + pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n", + hc_attrs[i].kattr.attr.name, ret); + } + } + + pr_info("MikroTik RouterBOARD hardware configuration sysfs driver v" RB_HARDCONFIG_VER "\n"); + + return 0; + +fail: + kfree(hc_buf); + hc_buf = NULL; + return ret; +} + +void __exit rb_hardconfig_exit(void) +{ + kobject_put(hc_kobj); + kfree(hc_buf); +} diff --git a/ipq806x/files-5.4/drivers/platform/mikrotik/rb_softconfig.c b/ipq806x/files-5.4/drivers/platform/mikrotik/rb_softconfig.c new file mode 100644 index 0000000..070bd32 --- /dev/null +++ b/ipq806x/files-5.4/drivers/platform/mikrotik/rb_softconfig.c @@ -0,0 +1,806 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for MikroTik RouterBoot soft config. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This driver exposes the data encoded in the "soft_config" flash segment of + * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder + * named "soft_config". The data is presented in a user/machine-friendly way + * with just as much parsing as can be generalized across mikrotik platforms + * (as inferred from reverse-engineering). + * + * The known soft_config tags are presented in the "soft_config" sysfs folder, + * with the addition of one specific file named "commit", which is only + * available if the driver supports writes to the mtd device: no modifications + * made to any of the other attributes are actually written back to flash media + * until a true value is input into this file (e.g. [Yy1]). This is to avoid + * unnecessary flash wear, and to permit to revert all changes by issuing a + * false value ([Nn0]). Reading the content of this file shows the current + * status of the driver: if the data in sysfs matches the content of the + * soft_config partition, the file will read "clean". Otherwise, it will read + * "dirty". + * + * The writeable sysfs files presented by this driver will accept only inputs + * which are in a valid range for the given tag. As a design choice, the driver + * will not assess whether the inputs are identical to the existing data. + * + * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show + * routines need not check for output overflow. + * + * Some constant defines extracted from rbcfg.h by Gabor Juhos + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATH79 + #include +#endif + +#include "routerboot.h" + +#define RB_SOFTCONFIG_VER "0.03" +#define RB_SC_PR_PFX "[rb_softconfig] " + +/* + * mtd operations before 4.17 are asynchronous, not handled by this code + * Also make the driver act read-only if 4K_SECTORS are not enabled, since they + * are require to handle partial erasing of the small soft_config partition. + */ +#if defined(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS) + #define RB_SC_HAS_WRITE_SUPPORT true + #define RB_SC_WMODE S_IWUSR + #define RB_SC_RMODE S_IRUSR +#else + #define RB_SC_HAS_WRITE_SUPPORT false + #define RB_SC_WMODE 0 + #define RB_SC_RMODE S_IRUSR +#endif + +/* ID values for software settings */ +#define RB_SCID_UART_SPEED 0x01 // u32*1 +#define RB_SCID_BOOT_DELAY 0x02 // u32*1 +#define RB_SCID_BOOT_DEVICE 0x03 // u32*1 +#define RB_SCID_BOOT_KEY 0x04 // u32*1 +#define RB_SCID_CPU_MODE 0x05 // u32*1 +#define RB_SCID_BIOS_VERSION 0x06 // str +#define RB_SCID_BOOT_PROTOCOL 0x09 // u32*1 +#define RB_SCID_CPU_FREQ_IDX 0x0C // u32*1 +#define RB_SCID_BOOTER 0x0D // u32*1 +#define RB_SCID_SILENT_BOOT 0x0F // u32*1 +/* + * protected_routerboot seems to use tag 0x1F. It only works in combination with + * RouterOS, resulting in a wiped board otherwise, so it's not implemented here. + * The tag values are as follows: + * - off: 0x0 + * - on: the lower halfword encodes the max value in s for the reset feature, + * the higher halfword encodes the min value in s for the reset feature. + * Default value when on: 0x00140258: 0x14 = 20s / 0x258= 600s + * See details here: https://wiki.mikrotik.com/wiki/Manual:RouterBOARD_settings#Protected_bootloader + */ + +/* Tag values */ + +#define RB_UART_SPEED_115200 0 +#define RB_UART_SPEED_57600 1 +#define RB_UART_SPEED_38400 2 +#define RB_UART_SPEED_19200 3 +#define RB_UART_SPEED_9600 4 +#define RB_UART_SPEED_4800 5 +#define RB_UART_SPEED_2400 6 +#define RB_UART_SPEED_1200 7 +#define RB_UART_SPEED_OFF 8 + +/* valid boot delay: 1 - 9s in 1s increment */ +#define RB_BOOT_DELAY_MIN 1 +#define RB_BOOT_DELAY_MAX 9 + +#define RB_BOOT_DEVICE_ETHER 0 // "boot over Ethernet" +#define RB_BOOT_DEVICE_NANDETH 1 // "boot from NAND, if fail then Ethernet" +#define RB_BOOT_DEVICE_CFCARD 2 // (not available in rbcfg) +#define RB_BOOT_DEVICE_ETHONCE 3 // "boot Ethernet once, then NAND" +#define RB_BOOT_DEVICE_NANDONLY 5 // "boot from NAND only" +#define RB_BOOT_DEVICE_FLASHCFG 7 // "boot in flash configuration mode" +#define RB_BOOT_DEVICE_FLSHONCE 8 // "boot in flash configuration mode once, then NAND" + +/* + * ATH79 9xxx CPU frequency indices. + * It is unknown if they apply to all ATH79 RBs, and some do not seem to feature + * the upper levels (QCA955x), while F is presumably AR9344-only. + */ +#define RB_CPU_FREQ_IDX_ATH79_9X_A (0 << 3) +#define RB_CPU_FREQ_IDX_ATH79_9X_B (1 << 3) // 0x8 +#define RB_CPU_FREQ_IDX_ATH79_9X_C (2 << 3) // 0x10 - factory freq for many devices +#define RB_CPU_FREQ_IDX_ATH79_9X_D (3 << 3) // 0x18 +#define RB_CPU_FREQ_IDX_ATH79_9X_E (4 << 3) // 0x20 +#define RB_CPU_FREQ_IDX_ATH79_9X_F (5 << 3) // 0x28 + +#define RB_CPU_FREQ_IDX_ATH79_9X_MIN 0 // all devices support lowest setting +#define RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX 5 // stops at F +#define RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX 4 // stops at E +#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX 2 // stops at C +#define RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX 3 // stops at D + +/* ATH79 7xxx CPU frequency indices. */ +#define RB_CPU_FREQ_IDX_ATH79_7X_A ((0 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_B ((1 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_C ((2 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_D ((3 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_E ((4 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_F ((5 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_G ((6 * 9) << 4) +#define RB_CPU_FREQ_IDX_ATH79_7X_H ((7 * 9) << 4) + +#define RB_CPU_FREQ_IDX_ATH79_7X_MIN 0 // all devices support lowest setting +#define RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX 3 // stops at D +#define RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX 7 // stops at H - check if applies to all AR71xx devices + +#define RB_SC_CRC32_OFFSET 4 // located right after magic + +static struct kobject *sc_kobj; +static u8 *sc_buf; +static size_t sc_buflen; +static rwlock_t sc_bufrwl; // rw lock to sc_buf + +/* MUST be used with lock held */ +#define RB_SC_CLRCRC() *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = 0 +#define RB_SC_GETCRC() *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) +#define RB_SC_SETCRC(_crc) *(u32 *)(sc_buf + RB_SC_CRC32_OFFSET) = (_crc) + +struct sc_u32tvs { + const u32 val; + const char *str; +}; + +#define RB_SC_TVS(_val, _str) { \ + .val = (_val), \ + .str = (_str), \ +} + +static ssize_t sc_tag_show_u32tvs(const u8 *pld, u16 pld_len, char *buf, + const struct sc_u32tvs tvs[], const int tvselmts) +{ + const char *fmt; + char *out = buf; + u32 data; // cpu-endian + int i; + + // fallback to raw hex output if we can't handle the input + if (tvselmts < 0) + return routerboot_tag_show_u32s(pld, pld_len, buf); + + if (sizeof(data) != pld_len) + return -EINVAL; + + read_lock(&sc_bufrwl); + data = *(u32 *)pld; // pld aliases sc_buf + read_unlock(&sc_bufrwl); + + for (i = 0; i < tvselmts; i++) { + fmt = (tvs[i].val == data) ? "[%s] " : "%s "; + out += sprintf(out, fmt, tvs[i].str); + } + + out += sprintf(out, "\n"); + return out - buf; +} + +static ssize_t sc_tag_store_u32tvs(const u8 *pld, u16 pld_len, const char *buf, size_t count, + const struct sc_u32tvs tvs[], const int tvselmts) +{ + int i; + + if (tvselmts < 0) + return tvselmts; + + if (sizeof(u32) != pld_len) + return -EINVAL; + + for (i = 0; i < tvselmts; i++) { + if (sysfs_streq(buf, tvs[i].str)) { + write_lock(&sc_bufrwl); + *(u32 *)pld = tvs[i].val; // pld aliases sc_buf + RB_SC_CLRCRC(); + write_unlock(&sc_bufrwl); + return count; + } + } + + return -EINVAL; +} + +struct sc_boolts { + const char *strfalse; + const char *strtrue; +}; + +static ssize_t sc_tag_show_boolts(const u8 *pld, u16 pld_len, char *buf, + const struct sc_boolts *bts) +{ + const char *fmt; + char *out = buf; + u32 data; // cpu-endian + + if (sizeof(data) != pld_len) + return -EINVAL; + + read_lock(&sc_bufrwl); + data = *(u32 *)pld; // pld aliases sc_buf + read_unlock(&sc_bufrwl); + + fmt = (data) ? "%s [%s]\n" : "[%s] %s\n"; + out += sprintf(out, fmt, bts->strfalse, bts->strtrue); + + return out - buf; +} + +static ssize_t sc_tag_store_boolts(const u8 *pld, u16 pld_len, const char *buf, size_t count, + const struct sc_boolts *bts) +{ + u32 data; // cpu-endian + + if (sizeof(data) != pld_len) + return -EINVAL; + + if (sysfs_streq(buf, bts->strfalse)) + data = 0; + else if (sysfs_streq(buf, bts->strtrue)) + data = 1; + else + return -EINVAL; + + write_lock(&sc_bufrwl); + *(u32 *)pld = data; // pld aliases sc_buf + RB_SC_CLRCRC(); + write_unlock(&sc_bufrwl); + + return count; +} +static struct sc_u32tvs const sc_uartspeeds[] = { + RB_SC_TVS(RB_UART_SPEED_OFF, "off"), + RB_SC_TVS(RB_UART_SPEED_1200, "1200"), + RB_SC_TVS(RB_UART_SPEED_2400, "2400"), + RB_SC_TVS(RB_UART_SPEED_4800, "4800"), + RB_SC_TVS(RB_UART_SPEED_9600, "9600"), + RB_SC_TVS(RB_UART_SPEED_19200, "19200"), + RB_SC_TVS(RB_UART_SPEED_38400, "38400"), + RB_SC_TVS(RB_UART_SPEED_57600, "57600"), + RB_SC_TVS(RB_UART_SPEED_115200, "115200"), +}; + +/* + * While the defines are carried over from rbcfg, use strings that more clearly + * show the actual setting purpose (especially since the NAND* settings apply + * to both nand- and nor-based devices). "cfcard" was disabled in rbcfg: disable + * it here too. + */ +static struct sc_u32tvs const sc_bootdevices[] = { + RB_SC_TVS(RB_BOOT_DEVICE_ETHER, "eth"), + RB_SC_TVS(RB_BOOT_DEVICE_NANDETH, "flasheth"), + //RB_SC_TVS(RB_BOOT_DEVICE_CFCARD, "cfcard"), + RB_SC_TVS(RB_BOOT_DEVICE_ETHONCE, "ethonce"), + RB_SC_TVS(RB_BOOT_DEVICE_NANDONLY, "flash"), + RB_SC_TVS(RB_BOOT_DEVICE_FLASHCFG, "cfg"), + RB_SC_TVS(RB_BOOT_DEVICE_FLSHONCE, "cfgonce"), +}; + +static struct sc_boolts const sc_bootkey = { + .strfalse = "any", + .strtrue = "del", +}; + +static struct sc_boolts const sc_cpumode = { + .strfalse = "powersave", + .strtrue = "regular", +}; + +static struct sc_boolts const sc_bootproto = { + .strfalse = "bootp", + .strtrue = "dhcp", +}; + +static struct sc_boolts const sc_booter = { + .strfalse = "regular", + .strtrue = "backup", +}; + +static struct sc_boolts const sc_silent_boot = { + .strfalse = "off", + .strtrue = "on", +}; + +#define SC_TAG_SHOW_STORE_U32TVS_FUNCS(_name) \ +static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf) \ +{ \ + return sc_tag_show_u32tvs(pld, pld_len, buf, sc_##_name, ARRAY_SIZE(sc_##_name)); \ +} \ +static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count) \ +{ \ + return sc_tag_store_u32tvs(pld, pld_len, buf, count, sc_##_name, ARRAY_SIZE(sc_##_name)); \ +} + +#define SC_TAG_SHOW_STORE_BOOLTS_FUNCS(_name) \ +static ssize_t sc_tag_show_##_name(const u8 *pld, u16 pld_len, char *buf) \ +{ \ + return sc_tag_show_boolts(pld, pld_len, buf, &sc_##_name); \ +} \ +static ssize_t sc_tag_store_##_name(const u8 *pld, u16 pld_len, const char *buf, size_t count) \ +{ \ + return sc_tag_store_boolts(pld, pld_len, buf, count, &sc_##_name); \ +} + +SC_TAG_SHOW_STORE_U32TVS_FUNCS(uartspeeds) +SC_TAG_SHOW_STORE_U32TVS_FUNCS(bootdevices) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootkey) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(cpumode) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(bootproto) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(booter) +SC_TAG_SHOW_STORE_BOOLTS_FUNCS(silent_boot) + +static ssize_t sc_tag_show_bootdelays(const u8 *pld, u16 pld_len, char *buf) +{ + const char *fmt; + char *out = buf; + u32 data; // cpu-endian + int i; + + if (sizeof(data) != pld_len) + return -EINVAL; + + read_lock(&sc_bufrwl); + data = *(u32 *)pld; // pld aliases sc_buf + read_unlock(&sc_bufrwl); + + for (i = RB_BOOT_DELAY_MIN; i <= RB_BOOT_DELAY_MAX; i++) { + fmt = (i == data) ? "[%d] " : "%d "; + out += sprintf(out, fmt, i); + } + + out += sprintf(out, "\n"); + return out - buf; +} + +static ssize_t sc_tag_store_bootdelays(const u8 *pld, u16 pld_len, const char *buf, size_t count) +{ + u32 data; // cpu-endian + int ret; + + if (sizeof(data) != pld_len) + return -EINVAL; + + ret = kstrtou32(buf, 10, &data); + if (ret) + return ret; + + if ((data < RB_BOOT_DELAY_MIN) || (RB_BOOT_DELAY_MAX < data)) + return -EINVAL; + + write_lock(&sc_bufrwl); + *(u32 *)pld = data; // pld aliases sc_buf + RB_SC_CLRCRC(); + write_unlock(&sc_bufrwl); + + return count; +} + +/* Support CPU frequency accessors only when the tag format has been asserted */ +#if defined(CONFIG_ATH79) +/* Use the same letter-based nomenclature as RouterBOOT */ +static struct sc_u32tvs const sc_cpufreq_indexes_ath79_9x[] = { + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_A, "a"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_B, "b"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_C, "c"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_D, "d"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_E, "e"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_9X_F, "f"), +}; + +static struct sc_u32tvs const sc_cpufreq_indexes_ath79_7x[] = { + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_A, "a"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_B, "b"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_C, "c"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_D, "d"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_E, "e"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_F, "f"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_G, "g"), + RB_SC_TVS(RB_CPU_FREQ_IDX_ATH79_7X_H, "h"), +}; + +static int sc_tag_cpufreq_ath79_arraysize(void) +{ + int idx_max; + + if (ATH79_SOC_AR7161 == ath79_soc) + idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR7161_MAX+1; + else if (soc_is_ar724x()) + idx_max = RB_CPU_FREQ_IDX_ATH79_7X_AR724X_MAX+1; + else if (soc_is_ar9344()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_AR9334_MAX+1; + else if (soc_is_qca953x()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA953X_MAX+1; + else if (soc_is_qca9556()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9556_MAX+1; + else if (soc_is_qca9558()) + idx_max = RB_CPU_FREQ_IDX_ATH79_9X_QCA9558_MAX+1; + else + idx_max = -EOPNOTSUPP; + + return idx_max; +} + +static ssize_t sc_tag_show_cpufreq_indexes(const u8 *pld, u16 pld_len, char *buf) +{ + const struct sc_u32tvs *tvs; + + if (soc_is_ar71xx() || soc_is_ar724x()) + tvs = sc_cpufreq_indexes_ath79_7x; + else + tvs = sc_cpufreq_indexes_ath79_9x; + + return sc_tag_show_u32tvs(pld, pld_len, buf, tvs, sc_tag_cpufreq_ath79_arraysize()); +} + +static ssize_t sc_tag_store_cpufreq_indexes(const u8 *pld, u16 pld_len, const char *buf, size_t count) +{ + const struct sc_u32tvs *tvs; + + if (soc_is_ar71xx() || soc_is_ar724x()) + tvs = sc_cpufreq_indexes_ath79_7x; + else + tvs = sc_cpufreq_indexes_ath79_9x; + + return sc_tag_store_u32tvs(pld, pld_len, buf, count, tvs, sc_tag_cpufreq_ath79_arraysize()); +} +#else + /* By default we only show the raw value to help with reverse-engineering */ + #define sc_tag_show_cpufreq_indexes routerboot_tag_show_u32s + #define sc_tag_store_cpufreq_indexes NULL +#endif + +static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf); +static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count); + +/* Array of known tags to publish in sysfs */ +static struct sc_attr { + const u16 tag_id; + /* sysfs tag show attribute. Must lock sc_buf when dereferencing pld */ + ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf); + /* sysfs tag store attribute. Must lock sc_buf when dereferencing pld */ + ssize_t (* const tstore)(const u8 *pld, u16 pld_len, const char *buf, size_t count); + struct kobj_attribute kattr; + u16 pld_ofs; + u16 pld_len; +} sc_attrs[] = { + { + .tag_id = RB_SCID_UART_SPEED, + .tshow = sc_tag_show_uartspeeds, + .tstore = sc_tag_store_uartspeeds, + .kattr = __ATTR(uart_speed, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOT_DELAY, + .tshow = sc_tag_show_bootdelays, + .tstore = sc_tag_store_bootdelays, + .kattr = __ATTR(boot_delay, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOT_DEVICE, + .tshow = sc_tag_show_bootdevices, + .tstore = sc_tag_store_bootdevices, + .kattr = __ATTR(boot_device, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOT_KEY, + .tshow = sc_tag_show_bootkey, + .tstore = sc_tag_store_bootkey, + .kattr = __ATTR(boot_key, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_CPU_MODE, + .tshow = sc_tag_show_cpumode, + .tstore = sc_tag_store_cpumode, + .kattr = __ATTR(cpu_mode, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BIOS_VERSION, + .tshow = routerboot_tag_show_string, + .tstore = NULL, + .kattr = __ATTR(bios_version, RB_SC_RMODE, sc_attr_show, NULL), + }, { + .tag_id = RB_SCID_BOOT_PROTOCOL, + .tshow = sc_tag_show_bootproto, + .tstore = sc_tag_store_bootproto, + .kattr = __ATTR(boot_proto, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_CPU_FREQ_IDX, + .tshow = sc_tag_show_cpufreq_indexes, + .tstore = sc_tag_store_cpufreq_indexes, + .kattr = __ATTR(cpufreq_index, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_BOOTER, + .tshow = sc_tag_show_booter, + .tstore = sc_tag_store_booter, + .kattr = __ATTR(booter, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, { + .tag_id = RB_SCID_SILENT_BOOT, + .tshow = sc_tag_show_silent_boot, + .tstore = sc_tag_store_silent_boot, + .kattr = __ATTR(silent_boot, RB_SC_RMODE|RB_SC_WMODE, sc_attr_show, sc_attr_store), + }, +}; + +static ssize_t sc_attr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const struct sc_attr *sc_attr; + const u8 *pld; + u16 pld_len; + + sc_attr = container_of(attr, typeof(*sc_attr), kattr); + + if (!sc_attr->pld_len) + return -ENOENT; + + pld = sc_buf + sc_attr->pld_ofs; // pld aliases sc_buf -> lock! + pld_len = sc_attr->pld_len; + + return sc_attr->tshow(pld, pld_len, buf); +} + +static ssize_t sc_attr_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + const struct sc_attr *sc_attr; + const u8 *pld; + u16 pld_len; + + if (!RB_SC_HAS_WRITE_SUPPORT) + return -EOPNOTSUPP; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + sc_attr = container_of(attr, typeof(*sc_attr), kattr); + + if (!sc_attr->tstore) + return -EOPNOTSUPP; + + if (!sc_attr->pld_len) + return -ENOENT; + + pld = sc_buf + sc_attr->pld_ofs; // pld aliases sc_buf -> lock! + pld_len = sc_attr->pld_len; + + return sc_attr->tstore(pld, pld_len, buf, count); +} + +/* + * Shows the current buffer status: + * "clean": the buffer is in sync with the mtd data + * "dirty": the buffer is out of sync with the mtd data + */ +static ssize_t sc_commit_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const char *str; + char *out = buf; + u32 crc; + + read_lock(&sc_bufrwl); + crc = RB_SC_GETCRC(); + read_unlock(&sc_bufrwl); + + str = (crc) ? "clean" : "dirty"; + out += sprintf(out, "%s\n", str); + + return out - buf; +} + +/* + * Performs buffer flushing: + * This routine expects an input compatible with kstrtobool(). + * - a "false" input discards the current changes and reads data back from mtd. + * - a "true" input commits the current changes to mtd. + * If there is no pending changes, this routine is a no-op. + * Handling failures is left as an exercise to userspace. + */ +static ssize_t sc_commit_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct mtd_info *mtd; + struct erase_info ei; + size_t bytes_rw, ret = count; + bool flush; + u32 crc; + + if (!RB_SC_HAS_WRITE_SUPPORT) + return -EOPNOTSUPP; + + read_lock(&sc_bufrwl); + crc = RB_SC_GETCRC(); + read_unlock(&sc_bufrwl); + + if (crc) + return count; // NO-OP + + ret = kstrtobool(buf, &flush); + if (ret) + return ret; + + mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG); // TODO allow override + if (IS_ERR(mtd)) + return -ENODEV; + + write_lock(&sc_bufrwl); + if (!flush) // reread + ret = mtd_read(mtd, 0, mtd->size, &bytes_rw, sc_buf); + else { // crc32 + commit + /* + * CRC32 is computed on the entire buffer, excluding the CRC + * value itself. CRC is already null when we reach this point, + * so we can compute the CRC32 on the buffer as is. + * The expected CRC32 is Ethernet FCS style, meaning the seed is + * ~0 and the final result is also bitflipped. + */ + + crc = ~crc32(~0, sc_buf, sc_buflen); + RB_SC_SETCRC(crc); + + /* + * The soft_config partition is assumed to be entirely contained + * in a single eraseblock. + */ + + ei.addr = 0; + ei.len = mtd->size; + ret = mtd_erase(mtd, &ei); + if (!ret) + ret = mtd_write(mtd, 0, mtd->size, &bytes_rw, sc_buf); + + /* + * Handling mtd_write() failure here is a tricky situation. The + * proposed approach is to let userspace deal with retrying, + * with the caveat that it must try to flush the buffer again as + * rereading the mtd contents could potentially read garbage. + * The rationale is: even if we keep a shadow buffer of the + * original content, there is no guarantee that we will ever be + * able to write it anyway. + * Regardless, it appears that RouterBOOT will ignore an invalid + * soft_config (including a completely wiped segment) and will + * write back factory defaults when it happens. + */ + } + write_unlock(&sc_bufrwl); + + put_mtd_device(mtd); + + if (ret) + goto mtdfail; + + if (bytes_rw != sc_buflen) { + ret = -EIO; + goto mtdfail; + } + + return count; + +mtdfail: + RB_SC_CLRCRC(); // mark buffer content as dirty/invalid + return ret; +} + +static struct kobj_attribute sc_kattrcommit = __ATTR(commit, RB_SC_RMODE|RB_SC_WMODE, sc_commit_show, sc_commit_store); + +int __init rb_softconfig_init(struct kobject *rb_kobj) +{ + struct mtd_info *mtd; + size_t bytes_read, buflen; + const u8 *buf; + int i, ret; + u32 magic; + + sc_buf = NULL; + sc_kobj = NULL; + + // TODO allow override + mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG); + if (IS_ERR(mtd)) + return -ENODEV; + + sc_buflen = mtd->size; + sc_buf = kmalloc(sc_buflen, GFP_KERNEL); + if (!sc_buf) { + put_mtd_device(mtd); + return -ENOMEM; + } + + ret = mtd_read(mtd, 0, sc_buflen, &bytes_read, sc_buf); + put_mtd_device(mtd); + + if (ret) + goto fail; + + if (bytes_read != sc_buflen) { + ret = -EIO; + goto fail; + } + + /* Check we have what we expect */ + magic = *(const u32 *)sc_buf; + if (RB_MAGIC_SOFT != magic) { + ret = -EINVAL; + goto fail; + } + + /* Skip magic and 32bit CRC located immediately after */ + buf = sc_buf + (sizeof(magic) + sizeof(u32)); + buflen = sc_buflen - (sizeof(magic) + sizeof(u32)); + + /* Populate sysfs */ + ret = -ENOMEM; + sc_kobj = kobject_create_and_add(RB_MTD_SOFT_CONFIG, rb_kobj); + if (!sc_kobj) + goto fail; + + rwlock_init(&sc_bufrwl); + + /* Locate and publish all known tags */ + for (i = 0; i < ARRAY_SIZE(sc_attrs); i++) { + ret = routerboot_tag_find(buf, buflen, sc_attrs[i].tag_id, + &sc_attrs[i].pld_ofs, &sc_attrs[i].pld_len); + if (ret) { + sc_attrs[i].pld_ofs = sc_attrs[i].pld_len = 0; + continue; + } + + /* Account for skipped magic and crc32 */ + sc_attrs[i].pld_ofs += sizeof(magic) + sizeof(u32); + + ret = sysfs_create_file(sc_kobj, &sc_attrs[i].kattr.attr); + if (ret) + pr_warn(RB_SC_PR_PFX "Could not create %s sysfs entry (%d)\n", + sc_attrs[i].kattr.attr.name, ret); + } + + /* Finally add the 'commit' attribute */ + if (RB_SC_HAS_WRITE_SUPPORT) { + ret = sysfs_create_file(sc_kobj, &sc_kattrcommit.attr); + if (ret) { + pr_err(RB_SC_PR_PFX "Could not create %s sysfs entry (%d), aborting!\n", + sc_kattrcommit.attr.name, ret); + goto sysfsfail; // required attribute + } + } + + pr_info("MikroTik RouterBOARD software configuration sysfs driver v" RB_SOFTCONFIG_VER "\n"); + + return 0; + +sysfsfail: + kobject_put(sc_kobj); + sc_kobj = NULL; +fail: + kfree(sc_buf); + sc_buf = NULL; + return ret; +} + +void __exit rb_softconfig_exit(void) +{ + kobject_put(sc_kobj); + kfree(sc_buf); +} diff --git a/ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.c b/ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.c new file mode 100644 index 0000000..4c8c0bf --- /dev/null +++ b/ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for MikroTik RouterBoot flash data. Common routines. + * + * Copyright (C) 2020 Thibaut VARÈNE + * + * 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. + */ + +#include +#include +#include +#include + +#include "routerboot.h" + +static struct kobject *rb_kobj; + +/** + * routerboot_tag_find() - Locate a given tag in routerboot config data. + * @bufhead: the buffer to look into. Must start with a tag node. + * @buflen: size of bufhead + * @tag_id: the tag identifier to look for + * @pld_ofs: will be updated with tag payload offset in bufhead, if tag found + * @pld_len: will be updated with tag payload size, if tag found + * + * This incarnation of tag_find() does only that: it finds a specific routerboot + * tag node in the input buffer. Routerboot tag nodes are u32 values: + * - The low nibble is the tag identification number, + * - The high nibble is the tag payload length (node excluded) in bytes. + * The payload immediately follows the tag node. Tag nodes are 32bit-aligned. + * The returned pld_ofs will always be aligned. pld_len may not end on 32bit + * boundary (the only known case is when parsing ERD data). + * The nodes are cpu-endian on the flash media. The payload is cpu-endian when + * applicable. Tag nodes are not ordered (by ID) on flash. + * + * Return: 0 on success (tag found) or errno + */ +int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, + u16 *pld_ofs, u16 *pld_len) +{ + const u32 *datum, *bufend; + u32 node; + u16 id, len; + int ret; + + if (!bufhead || !tag_id) + return -EINVAL; + + ret = -ENOENT; + datum = (const u32 *)bufhead; + bufend = (const u32 *)(bufhead + buflen); + + while (datum < bufend) { + node = *datum++; + + /* Tag list ends with null node */ + if (!node) + break; + + id = node & 0xFFFF; + len = node >> 16; + + if (tag_id == id) { + if (datum >= bufend) + break; + + if (pld_ofs) + *pld_ofs = (u16)((u8 *)datum - bufhead); + if (pld_len) + *pld_len = len; + + ret = 0; + break; + } + + /* + * The only known situation where len may not end on 32bit + * boundary is within ERD data. Since we're only extracting + * one tag (the first and only one) from that data, we should + * never need to forcefully ALIGN(). Do it anyway, this is not a + * performance path. + */ + len = ALIGN(len, sizeof(*datum)); + datum += len / sizeof(*datum); + } + + return ret; +} + +/** + * routerboot_rle_decode() - Simple RLE (MikroTik variant) decoding routine. + * @in: input buffer to decode + * @inlen: size of in + * @out: output buffer to write decoded data to + * @outlen: pointer to out size when function is called, will be updated with + * size of decoded output on return + * + * MikroTik's variant of RLE operates as follows, considering a signed run byte: + * - positive run => classic RLE + * - negative run => the next - bytes must be copied verbatim + * The API is matched to the lzo1x routines for convenience. + * + * NB: The output buffer cannot overlap with the input buffer. + * + * Return: 0 on success or errno + */ +int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen) +{ + int ret, run, nbytes; // use native types for speed + u8 byte; + + if (!in || (inlen < 2) || !out) + return -EINVAL; + + ret = -ENOSPC; + nbytes = 0; + while (inlen >= 2) { + run = *in++; + inlen--; + + /* Verbatim copies */ + if (run & 0x80) { + /* Invert run byte sign */ + run = ~run & 0xFF; + run++; + + if (run > inlen) + goto fail; + + inlen -= run; + + nbytes += run; + if (nbytes > *outlen) + goto fail; + + /* Basic memcpy */ + while (run-- > 0) + *out++ = *in++; + } + /* Stream of half-words RLE: . run == 0 is ignored */ + else { + byte = *in++; + inlen--; + + nbytes += run; + if (nbytes > *outlen) + goto fail; + + while (run-- > 0) + *out++ = byte; + } + } + + ret = 0; +fail: + *outlen = nbytes; + return ret; +} + +static int __init routerboot_init(void) +{ + rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj); + if (!rb_kobj) + return -ENOMEM; + + /* + * We ignore the following return values and always register. + * These init() routines are designed so that their failed state is + * always manageable by the corresponding exit() calls. + */ + rb_hardconfig_init(rb_kobj); + rb_softconfig_init(rb_kobj); + + return 0; +} + +static void __exit routerboot_exit(void) +{ + rb_softconfig_exit(); + rb_hardconfig_exit(); + kobject_put(rb_kobj); // recursive afaict +} + +/* Common routines */ + +ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf) +{ + return scnprintf(buf, pld_len+1, "%s\n", pld); +} + +ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf) +{ + char *out = buf; + u32 *data; // cpu-endian + + /* Caller ensures pld_len > 0 */ + if (pld_len % sizeof(*data)) + return -EINVAL; + + data = (u32 *)pld; + + do { + out += sprintf(out, "0x%08x\n", *data); + data++; + } while ((pld_len -= sizeof(*data))); + + return out - buf; +} + +module_init(routerboot_init); +module_exit(routerboot_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MikroTik RouterBoot sysfs support"); +MODULE_AUTHOR("Thibaut VARENE"); diff --git a/ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.h b/ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.h new file mode 100644 index 0000000..67d8980 --- /dev/null +++ b/ipq806x/files-5.4/drivers/platform/mikrotik/routerboot.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Common definitions for MikroTik RouterBoot data. + * + * Copyright (C) 2020 Thibaut VARÈNE + */ + + +#ifndef _ROUTERBOOT_H_ +#define _ROUTERBOOT_H_ + +#include + +// these magic values are stored in cpu-endianness on flash +#define RB_MAGIC_HARD (('H') | ('a' << 8) | ('r' << 16) | ('d' << 24)) +#define RB_MAGIC_SOFT (('S') | ('o' << 8) | ('f' << 16) | ('t' << 24)) +#define RB_MAGIC_LZOR (('L') | ('Z' << 8) | ('O' << 16) | ('R' << 24)) +#define RB_MAGIC_ERD (('E' << 16) | ('R' << 8) | ('D')) + +#define RB_ART_SIZE 0x10000 + +#define RB_MTD_HARD_CONFIG "hard_config" +#define RB_MTD_SOFT_CONFIG "soft_config" + +int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, u16 *pld_ofs, u16 *pld_len); +int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen); + +int __init rb_hardconfig_init(struct kobject *rb_kobj); +void __exit rb_hardconfig_exit(void); + +int __init rb_softconfig_init(struct kobject *rb_kobj); +void __exit rb_softconfig_exit(void); + +ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf); +ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf); + +#endif /* _ROUTERBOOT_H_ */ diff --git a/ipq806x/files-5.4/include/dt-bindings/mtd/partitions/uimage.h b/ipq806x/files-5.4/include/dt-bindings/mtd/partitions/uimage.h new file mode 100644 index 0000000..43d5f7b --- /dev/null +++ b/ipq806x/files-5.4/include/dt-bindings/mtd/partitions/uimage.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * *** IMPORTANT *** + * This file is not only included from C-code but also from devicetree source + * files. As such this file MUST only contain comments and defines. + * + * Based on image.h from U-Boot which is + * (C) Copyright 2008 Semihalf + * (C) Copyright 2000-2005 Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#ifndef __UIMAGE_H__ +#define __UIMAGE_H__ + +/* + * Operating System Codes + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_OS_INVALID 0 /* Invalid OS */ +#define IH_OS_OPENBSD 1 /* OpenBSD */ +#define IH_OS_NETBSD 2 /* NetBSD */ +#define IH_OS_FREEBSD 3 /* FreeBSD */ +#define IH_OS_4_4BSD 4 /* 4.4BSD */ +#define IH_OS_LINUX 5 /* Linux */ +#define IH_OS_SVR4 6 /* SVR4 */ +#define IH_OS_ESIX 7 /* Esix */ +#define IH_OS_SOLARIS 8 /* Solaris */ +#define IH_OS_IRIX 9 /* Irix */ +#define IH_OS_SCO 10 /* SCO */ +#define IH_OS_DELL 11 /* Dell */ +#define IH_OS_NCR 12 /* NCR */ +#define IH_OS_LYNXOS 13 /* LynxOS */ +#define IH_OS_VXWORKS 14 /* VxWorks */ +#define IH_OS_PSOS 15 /* pSOS */ +#define IH_OS_QNX 16 /* QNX */ +#define IH_OS_U_BOOT 17 /* Firmware */ +#define IH_OS_RTEMS 18 /* RTEMS */ +#define IH_OS_ARTOS 19 /* ARTOS */ +#define IH_OS_UNITY 20 /* Unity OS */ +#define IH_OS_INTEGRITY 21 /* INTEGRITY */ +#define IH_OS_OSE 22 /* OSE */ +#define IH_OS_PLAN9 23 /* Plan 9 */ +#define IH_OS_OPENRTOS 24 /* OpenRTOS */ +#define IH_OS_ARM_TRUSTED_FIRMWARE 25 /* ARM Trusted Firmware */ +#define IH_OS_TEE 26 /* Trusted Execution Environment */ +#define IH_OS_OPENSBI 27 /* RISC-V OpenSBI */ +#define IH_OS_EFI 28 /* EFI Firmware (e.g. GRUB2) */ + +/* + * CPU Architecture Codes (supported by Linux) + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_ARCH_INVALID 0 /* Invalid CPU */ +#define IH_ARCH_ALPHA 1 /* Alpha */ +#define IH_ARCH_ARM 2 /* ARM */ +#define IH_ARCH_I386 3 /* Intel x86 */ +#define IH_ARCH_IA64 4 /* IA64 */ +#define IH_ARCH_MIPS 5 /* MIPS */ +#define IH_ARCH_MIPS64 6 /* MIPS 64 Bit */ +#define IH_ARCH_PPC 7 /* PowerPC */ +#define IH_ARCH_S390 8 /* IBM S390 */ +#define IH_ARCH_SH 9 /* SuperH */ +#define IH_ARCH_SPARC 10 /* Sparc */ +#define IH_ARCH_SPARC64 11 /* Sparc 64 Bit */ +#define IH_ARCH_M68K 12 /* M68K */ +#define IH_ARCH_NIOS 13 /* Nios-32 */ +#define IH_ARCH_MICROBLAZE 14 /* MicroBlaze */ +#define IH_ARCH_NIOS2 15 /* Nios-II */ +#define IH_ARCH_BLACKFIN 16 /* Blackfin */ +#define IH_ARCH_AVR32 17 /* AVR32 */ +#define IH_ARCH_ST200 18 /* STMicroelectronics ST200 */ +#define IH_ARCH_SANDBOX 19 /* Sandbox architecture (test only) */ +#define IH_ARCH_NDS32 20 /* ANDES Technology - NDS32 */ +#define IH_ARCH_OPENRISC 21 /* OpenRISC 1000 */ +#define IH_ARCH_ARM64 22 /* ARM64 */ +#define IH_ARCH_ARC 23 /* Synopsys DesignWare ARC */ +#define IH_ARCH_X86_64 24 /* AMD x86_64, Intel and Via */ +#define IH_ARCH_XTENSA 25 /* Xtensa */ +#define IH_ARCH_RISCV 26 /* RISC-V */ + +/* + * Image Types + * + * "Standalone Programs" are directly runnable in the environment + * provided by U-Boot; it is expected that (if they behave + * well) you can continue to work in U-Boot after return from + * the Standalone Program. + * "OS Kernel Images" are usually images of some Embedded OS which + * will take over control completely. Usually these programs + * will install their own set of exception handlers, device + * drivers, set up the MMU, etc. - this means, that you cannot + * expect to re-enter U-Boot except by resetting the CPU. + * "RAMDisk Images" are more or less just data blocks, and their + * parameters (address, size) are passed to an OS kernel that is + * being started. + * "Multi-File Images" contain several images, typically an OS + * (Linux) kernel image and one or more data images like + * RAMDisks. This construct is useful for instance when you want + * to boot over the network using BOOTP etc., where the boot + * server provides just a single image file, but you want to get + * for instance an OS kernel and a RAMDisk image. + * + * "Multi-File Images" start with a list of image sizes, each + * image size (in bytes) specified by an "uint32_t" in network + * byte order. This list is terminated by an "(uint32_t)0". + * Immediately after the terminating 0 follow the images, one by + * one, all aligned on "uint32_t" boundaries (size rounded up to + * a multiple of 4 bytes - except for the last file). + * + * "Firmware Images" are binary images containing firmware (like + * U-Boot or FPGA images) which usually will be programmed to + * flash memory. + * + * "Script files" are command sequences that will be executed by + * U-Boot's command interpreter; this feature is especially + * useful when you configure U-Boot to use a real shell (hush) + * as command interpreter (=> Shell Scripts). + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_TYPE_INVALID 0 /* Invalid Image */ +#define IH_TYPE_STANDALONE 1 /* Standalone Program */ +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ +#define IH_TYPE_MULTI 4 /* Multi-File Image */ +#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ +#define IH_TYPE_SCRIPT 6 /* Script file */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ +#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ +#define IH_TYPE_KWBIMAGE 9 /* Kirkwood Boot Image */ +#define IH_TYPE_IMXIMAGE 10 /* Freescale IMXBoot Image */ +#define IH_TYPE_UBLIMAGE 11 /* Davinci UBL Image */ +#define IH_TYPE_OMAPIMAGE 12 /* TI OMAP Config Header Image */ +#define IH_TYPE_AISIMAGE 13 /* TI Davinci AIS Image */ + /* OS Kernel Image, can run from any load address */ +#define IH_TYPE_KERNEL_NOLOAD 14 +#define IH_TYPE_PBLIMAGE 15 /* Freescale PBL Boot Image */ +#define IH_TYPE_MXSIMAGE 16 /* Freescale MXSBoot Image */ +#define IH_TYPE_GPIMAGE 17 /* TI Keystone GPHeader Image */ +#define IH_TYPE_ATMELIMAGE 18 /* ATMEL ROM bootable Image */ +#define IH_TYPE_SOCFPGAIMAGE 19 /* Altera SOCFPGA CV/AV Preloader */ +#define IH_TYPE_X86_SETUP 20 /* x86 setup.bin Image */ +#define IH_TYPE_LPC32XXIMAGE 21 /* x86 setup.bin Image */ +#define IH_TYPE_LOADABLE 22 /* A list of typeless images */ +#define IH_TYPE_RKIMAGE 23 /* Rockchip Boot Image */ +#define IH_TYPE_RKSD 24 /* Rockchip SD card */ +#define IH_TYPE_RKSPI 25 /* Rockchip SPI image */ +#define IH_TYPE_ZYNQIMAGE 26 /* Xilinx Zynq Boot Image */ +#define IH_TYPE_ZYNQMPIMAGE 27 /* Xilinx ZynqMP Boot Image */ +#define IH_TYPE_ZYNQMPBIF 28 /* Xilinx ZynqMP Boot Image (bif) */ +#define IH_TYPE_FPGA 29 /* FPGA Image */ +#define IH_TYPE_VYBRIDIMAGE 30 /* VYBRID .vyb Image */ +#define IH_TYPE_TEE 31 /* Trusted Execution Environment OS Image */ +#define IH_TYPE_FIRMWARE_IVT 32 /* Firmware Image with HABv4 IVT */ +#define IH_TYPE_PMMC 33 /* TI Power Management Micro-Controller Firmware */ +#define IH_TYPE_STM32IMAGE 34 /* STMicroelectronics STM32 Image */ +#define IH_TYPE_SOCFPGAIMAGE_V1 35 /* Altera SOCFPGA A10 Preloader */ +#define IH_TYPE_MTKIMAGE 36 /* MediaTek BootROM loadable Image */ +#define IH_TYPE_IMX8MIMAGE 37 /* Freescale IMX8MBoot Image */ +#define IH_TYPE_IMX8IMAGE 38 /* Freescale IMX8Boot Image */ +#define IH_TYPE_COPRO 39 /* Coprocessor Image for remoteproc*/ + + +/* + * Compression Types + * + * The following are exposed to uImage header. + * New IDs *MUST* be appended at the end of the list and *NEVER* + * inserted for backward compatibility. + */ +#define IH_COMP_NONE 0 /* No Compression Used */ +#define IH_COMP_GZIP 1 /* gzip Compression Used */ +#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ +#define IH_COMP_LZMA 3 /* lzma Compression Used */ +#define IH_COMP_LZO 4 /* lzo Compression Used */ +#define IH_COMP_LZ4 5 /* lz4 Compression Used */ + + +#define LZ4F_MAGIC 0x184D2204 /* LZ4 Magic Number */ +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +/* + * Magic values specific to "openwrt,uimage" partitions + */ +#define IH_MAGIC_OKLI 0x4f4b4c49 /* 'OKLI' */ +#define FW_EDIMAX_OFFSET 20 /* Edimax Firmware Offset */ +#define FW_MAGIC_EDIMAX 0x43535953 /* Edimax Firmware Magic Number */ + +#endif /* __UIMAGE_H__ */ diff --git a/ipq806x/files-5.4/include/linux/ar8216_platform.h b/ipq806x/files-5.4/include/linux/ar8216_platform.h new file mode 100644 index 0000000..24bc442 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/ar8216_platform.h @@ -0,0 +1,133 @@ +/* + * AR8216 switch driver platform data + * + * Copyright (C) 2012 Gabor Juhos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef AR8216_PLATFORM_H +#define AR8216_PLATFORM_H + +enum ar8327_pad_mode { + AR8327_PAD_NC = 0, + AR8327_PAD_MAC2MAC_MII, + AR8327_PAD_MAC2MAC_GMII, + AR8327_PAD_MAC_SGMII, + AR8327_PAD_MAC2PHY_MII, + AR8327_PAD_MAC2PHY_GMII, + AR8327_PAD_MAC_RGMII, + AR8327_PAD_PHY_GMII, + AR8327_PAD_PHY_RGMII, + AR8327_PAD_PHY_MII, +}; + +enum ar8327_clk_delay_sel { + AR8327_CLK_DELAY_SEL0 = 0, + AR8327_CLK_DELAY_SEL1, + AR8327_CLK_DELAY_SEL2, + AR8327_CLK_DELAY_SEL3, +}; + +struct ar8327_pad_cfg { + enum ar8327_pad_mode mode; + bool rxclk_sel; + bool txclk_sel; + bool pipe_rxclk_sel; + bool txclk_delay_en; + bool rxclk_delay_en; + bool sgmii_delay_en; + enum ar8327_clk_delay_sel txclk_delay_sel; + enum ar8327_clk_delay_sel rxclk_delay_sel; + bool mac06_exchange_dis; +}; + +enum ar8327_port_speed { + AR8327_PORT_SPEED_10 = 0, + AR8327_PORT_SPEED_100, + AR8327_PORT_SPEED_1000, +}; + +struct ar8327_port_cfg { + int force_link:1; + enum ar8327_port_speed speed; + int txpause:1; + int rxpause:1; + int duplex:1; +}; + +struct ar8327_sgmii_cfg { + u32 sgmii_ctrl; + bool serdes_aen; +}; + +struct ar8327_led_cfg { + u32 led_ctrl0; + u32 led_ctrl1; + u32 led_ctrl2; + u32 led_ctrl3; + bool open_drain; +}; + +enum ar8327_led_num { + AR8327_LED_PHY0_0 = 0, + AR8327_LED_PHY0_1, + AR8327_LED_PHY0_2, + AR8327_LED_PHY1_0, + AR8327_LED_PHY1_1, + AR8327_LED_PHY1_2, + AR8327_LED_PHY2_0, + AR8327_LED_PHY2_1, + AR8327_LED_PHY2_2, + AR8327_LED_PHY3_0, + AR8327_LED_PHY3_1, + AR8327_LED_PHY3_2, + AR8327_LED_PHY4_0, + AR8327_LED_PHY4_1, + AR8327_LED_PHY4_2, +}; + +enum ar8327_led_mode { + AR8327_LED_MODE_HW = 0, + AR8327_LED_MODE_SW, +}; + +struct ar8327_led_info { + const char *name; + const char *default_trigger; + bool active_low; + enum ar8327_led_num led_num; + enum ar8327_led_mode mode; +}; + +#define AR8327_LED_INFO(_led, _mode, _name) { \ + .name = (_name), \ + .led_num = AR8327_LED_ ## _led, \ + .mode = AR8327_LED_MODE_ ## _mode \ +} + +struct ar8327_platform_data { + struct ar8327_pad_cfg *pad0_cfg; + struct ar8327_pad_cfg *pad5_cfg; + struct ar8327_pad_cfg *pad6_cfg; + struct ar8327_sgmii_cfg *sgmii_cfg; + struct ar8327_port_cfg port0_cfg; + struct ar8327_port_cfg port6_cfg; + struct ar8327_led_cfg *led_cfg; + + int (*get_port_link)(unsigned port); + + unsigned num_leds; + const struct ar8327_led_info *leds; +}; + +#endif /* AR8216_PLATFORM_H */ + diff --git a/ipq806x/files-5.4/include/linux/ath5k_platform.h b/ipq806x/files-5.4/include/linux/ath5k_platform.h new file mode 100644 index 0000000..ec85224 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/ath5k_platform.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos + * Copyright (c) 2009 Imre Kaloz + * Copyright (c) 2010 Daniel Golle + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LINUX_ATH5K_PLATFORM_H +#define _LINUX_ATH5K_PLATFORM_H + +#define ATH5K_PLAT_EEP_MAX_WORDS 2048 + +struct ath5k_platform_data { + u16 *eeprom_data; + u8 *macaddr; +}; + +#endif /* _LINUX_ATH5K_PLATFORM_H */ diff --git a/ipq806x/files-5.4/include/linux/ath9k_platform.h b/ipq806x/files-5.4/include/linux/ath9k_platform.h new file mode 100644 index 0000000..e210108 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/ath9k_platform.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * Copyright (c) 2009 Gabor Juhos + * Copyright (c) 2009 Imre Kaloz + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LINUX_ATH9K_PLATFORM_H +#define _LINUX_ATH9K_PLATFORM_H + +#define ATH9K_PLAT_EEP_MAX_WORDS 2048 + +struct ath9k_platform_data { + const char *eeprom_name; + + u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; + u8 *macaddr; + + int led_pin; + u32 gpio_mask; + u32 gpio_val; + + u32 bt_active_pin; + u32 bt_priority_pin; + u32 wlan_active_pin; + + bool endian_check; + bool is_clk_25mhz; + bool tx_gain_buffalo; + bool disable_2ghz; + bool disable_5ghz; + bool led_active_high; + + int (*get_mac_revision)(void); + int (*external_reset)(void); + + bool use_eeprom; + + int num_leds; + const struct gpio_led *leds; + + unsigned num_btns; + const struct gpio_keys_button *btns; + unsigned btn_poll_interval; +}; + +#endif /* _LINUX_ATH9K_PLATFORM_H */ diff --git a/ipq806x/files-5.4/include/linux/myloader.h b/ipq806x/files-5.4/include/linux/myloader.h new file mode 100644 index 0000000..d89e415 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/myloader.h @@ -0,0 +1,121 @@ +/* + * Compex's MyLoader specific definitions + * + * Copyright (C) 2006-2008 Gabor Juhos + * + * 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. + * + */ + +#ifndef _MYLOADER_H_ +#define _MYLOADER_H_ + +/* Myloader specific magic numbers */ +#define MYLO_MAGIC_SYS_PARAMS 0x20021107 +#define MYLO_MAGIC_PARTITIONS 0x20021103 +#define MYLO_MAGIC_BOARD_PARAMS 0x20021103 + +/* Vendor ID's (seems to be same as the PCI vendor ID's) */ +#define VENID_COMPEX 0x11F6 + +/* Devices based on the ADM5120 */ +#define DEVID_COMPEX_NP27G 0x0078 +#define DEVID_COMPEX_NP28G 0x044C +#define DEVID_COMPEX_NP28GHS 0x044E +#define DEVID_COMPEX_WP54Gv1C 0x0514 +#define DEVID_COMPEX_WP54G 0x0515 +#define DEVID_COMPEX_WP54AG 0x0546 +#define DEVID_COMPEX_WPP54AG 0x0550 +#define DEVID_COMPEX_WPP54G 0x0555 + +/* Devices based on the Atheros AR2317 */ +#define DEVID_COMPEX_NP25G 0x05E6 +#define DEVID_COMPEX_WPE53G 0x05DC + +/* Devices based on the Atheros AR71xx */ +#define DEVID_COMPEX_WP543 0x0640 +#define DEVID_COMPEX_WPE72 0x0672 + +/* Devices based on the IXP422 */ +#define DEVID_COMPEX_WP18 0x047E +#define DEVID_COMPEX_NP18A 0x0489 + +/* Other devices */ +#define DEVID_COMPEX_NP26G8M 0x03E8 +#define DEVID_COMPEX_NP26G16M 0x03E9 + +struct mylo_partition { + uint16_t flags; /* partition flags */ + uint16_t type; /* type of the partition */ + uint32_t addr; /* relative address of the partition from the + flash start */ + uint32_t size; /* size of the partition in bytes */ + uint32_t param; /* if this is the active partition, the + MyLoader load code to this address */ +}; + +#define PARTITION_FLAG_ACTIVE 0x8000 /* this is the active partition, + * MyLoader loads firmware from here */ +#define PARTITION_FLAG_ISRAM 0x2000 /* FIXME: this is a RAM partition? */ +#define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */ +#define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM + * before decompression */ +#define PARTITION_FLAG_LZMA 0x0100 /* partition data compressed by LZMA */ +#define PARTITION_FLAG_HAVEHDR 0x0002 /* the partition data have a header */ + +#define PARTITION_TYPE_FREE 0 +#define PARTITION_TYPE_USED 1 + +#define MYLO_MAX_PARTITIONS 8 /* maximum number of partitions in the + partition table */ + +struct mylo_partition_table { + uint32_t magic; /* must be MYLO_MAGIC_PARTITIONS */ + uint32_t res0; /* unknown/unused */ + uint32_t res1; /* unknown/unused */ + uint32_t res2; /* unknown/unused */ + struct mylo_partition partitions[MYLO_MAX_PARTITIONS]; +}; + +struct mylo_partition_header { + uint32_t len; /* length of the partition data */ + uint32_t crc; /* CRC value of the partition data */ +}; + +struct mylo_system_params { + uint32_t magic; /* must be MYLO_MAGIC_SYS_PARAMS */ + uint32_t res0; + uint32_t res1; + uint32_t mylo_ver; + uint16_t vid; /* Vendor ID */ + uint16_t did; /* Device ID */ + uint16_t svid; /* Sub Vendor ID */ + uint16_t sdid; /* Sub Device ID */ + uint32_t rev; /* device revision */ + uint32_t fwhi; + uint32_t fwlo; + uint32_t tftp_addr; + uint32_t prog_start; + uint32_t flash_size; /* size of boot FLASH in bytes */ + uint32_t dram_size; /* size of onboard RAM in bytes */ +}; + +struct mylo_eth_addr { + uint8_t mac[6]; + uint8_t csum[2]; +}; + +#define MYLO_ETHADDR_COUNT 8 /* maximum number of ethernet address + in the board parameters */ + +struct mylo_board_params { + uint32_t magic; /* must be MYLO_MAGIC_BOARD_PARAMS */ + uint32_t res0; + uint32_t res1; + uint32_t res2; + struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT]; +}; + +#endif /* _MYLOADER_H_*/ diff --git a/ipq806x/files-5.4/include/linux/platform_data/adm6996-gpio.h b/ipq806x/files-5.4/include/linux/platform_data/adm6996-gpio.h new file mode 100644 index 0000000..d5af9bb --- /dev/null +++ b/ipq806x/files-5.4/include/linux/platform_data/adm6996-gpio.h @@ -0,0 +1,29 @@ +/* + * ADM6996 GPIO platform data + * + * Copyright (C) 2013 Hauke Mehrtens + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License v2 as published by the + * Free Software Foundation + */ + +#ifndef __PLATFORM_ADM6996_GPIO_H +#define __PLATFORM_ADM6996_GPIO_H + +#include + +enum adm6996_model { + ADM6996FC = 1, + ADM6996M = 2, + ADM6996L = 3, +}; + +struct adm6996_gpio_platform_data { + u8 eecs; + u8 eesk; + u8 eedi; + enum adm6996_model model; +}; + +#endif diff --git a/ipq806x/files-5.4/include/linux/routerboot.h b/ipq806x/files-5.4/include/linux/routerboot.h new file mode 100644 index 0000000..3cda858 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/routerboot.h @@ -0,0 +1,106 @@ +/* + * Mikrotik's RouterBOOT definitions + * + * Copyright (C) 2007-2008 Gabor Juhos + * + * 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. + * + */ + +#ifndef _ROUTERBOOT_H +#define _ROUTERBOOT_H + +#define RB_MAC_SIZE 6 + +/* + * Magic numbers + */ +#define RB_MAGIC_HARD 0x64726148 /* "Hard" */ +#define RB_MAGIC_SOFT 0x74666F53 /* "Soft" */ +#define RB_MAGIC_DAWN 0x6E776144 /* "Dawn" */ + +#define RB_ID_TERMINATOR 0 + +/* + * ID values for Hardware settings + */ +#define RB_ID_HARD_01 1 +#define RB_ID_HARD_02 2 +#define RB_ID_FLASH_INFO 3 +#define RB_ID_MAC_ADDRESS_PACK 4 +#define RB_ID_BOARD_NAME 5 +#define RB_ID_BIOS_VERSION 6 +#define RB_ID_HARD_07 7 +#define RB_ID_SDRAM_TIMINGS 8 +#define RB_ID_DEVICE_TIMINGS 9 +#define RB_ID_SOFTWARE_ID 10 +#define RB_ID_SERIAL_NUMBER 11 +#define RB_ID_HARD_12 12 +#define RB_ID_MEMORY_SIZE 13 +#define RB_ID_MAC_ADDRESS_COUNT 14 +#define RB_ID_HW_OPTIONS 21 +#define RB_ID_WLAN_DATA 22 + +/* + * ID values for Software settings + */ +#define RB_ID_UART_SPEED 1 +#define RB_ID_BOOT_DELAY 2 +#define RB_ID_BOOT_DEVICE 3 +#define RB_ID_BOOT_KEY 4 +#define RB_ID_CPU_MODE 5 +#define RB_ID_FW_VERSION 6 +#define RB_ID_SOFT_07 7 +#define RB_ID_SOFT_08 8 +#define RB_ID_BOOT_PROTOCOL 9 +#define RB_ID_SOFT_10 10 +#define RB_ID_SOFT_11 11 + +/* + * UART_SPEED values + */ +#define RB_UART_SPEED_115200 0 +#define RB_UART_SPEED_57600 1 +#define RB_UART_SPEED_38400 2 +#define RB_UART_SPEED_19200 3 +#define RB_UART_SPEED_9600 4 +#define RB_UART_SPEED_4800 5 +#define RB_UART_SPEED_2400 6 +#define RB_UART_SPEED_1200 7 + +/* + * BOOT_DELAY values + */ +#define RB_BOOT_DELAY_0SEC 0 +#define RB_BOOT_DELAY_1SEC 1 +#define RB_BOOT_DELAY_2SEC 2 + +/* + * BOOT_DEVICE values + */ +#define RB_BOOT_DEVICE_ETHER 0 +#define RB_BOOT_DEVICE_NANDETH 1 +#define RB_BOOT_DEVICE_ETHONCE 2 +#define RB_BOOT_DEVICE_NANDONLY 3 + +/* + * BOOT_KEY values + */ +#define RB_BOOT_KEY_ANY 0 +#define RB_BOOT_KEY_DEL 1 + +/* + * CPU_MODE values + */ +#define RB_CPU_MODE_POWERSAVE 0 +#define RB_CPU_MODE_REGULAR 1 + +/* + * BOOT_PROTOCOL values + */ +#define RB_BOOT_PROTOCOL_BOOTP 0 +#define RB_BOOT_PROTOCOL_DHCP 1 + +#endif /* _ROUTERBOOT_H */ diff --git a/ipq806x/files-5.4/include/linux/rt2x00_platform.h b/ipq806x/files-5.4/include/linux/rt2x00_platform.h new file mode 100644 index 0000000..e10377e --- /dev/null +++ b/ipq806x/files-5.4/include/linux/rt2x00_platform.h @@ -0,0 +1,23 @@ +/* + * Platform data definition for the rt2x00 driver + * + * Copyright (C) 2011 Gabor Juhos + * + * 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. + * + */ + +#ifndef _RT2X00_PLATFORM_H +#define _RT2X00_PLATFORM_H + +struct rt2x00_platform_data { + char *eeprom_file_name; + const u8 *mac_address; + + int disable_2ghz; + int disable_5ghz; +}; + +#endif /* _RT2X00_PLATFORM_H */ diff --git a/ipq806x/files-5.4/include/linux/rtl8366.h b/ipq806x/files-5.4/include/linux/rtl8366.h new file mode 100644 index 0000000..e3ce8f5 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/rtl8366.h @@ -0,0 +1,42 @@ +/* + * Platform data definition for the Realtek RTL8366RB/S ethernet switch driver + * + * Copyright (C) 2009-2010 Gabor Juhos + * + * 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. + */ + +#ifndef _RTL8366_H +#define _RTL8366_H + +#define RTL8366_DRIVER_NAME "rtl8366" +#define RTL8366S_DRIVER_NAME "rtl8366s" +#define RTL8366RB_DRIVER_NAME "rtl8366rb" + +struct rtl8366_smi; + +enum rtl8366_type { + RTL8366_TYPE_UNKNOWN, + RTL8366_TYPE_S, + RTL8366_TYPE_RB, +}; + +struct rtl8366_initval { + unsigned reg; + u16 val; +}; + +struct rtl8366_platform_data { + unsigned gpio_sda; + unsigned gpio_sck; + void (*hw_reset)(struct rtl8366_smi *smi, bool active); + + unsigned num_initvals; + struct rtl8366_initval *initvals; +}; + +enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata); + +#endif /* _RTL8366_H */ diff --git a/ipq806x/files-5.4/include/linux/rtl8367.h b/ipq806x/files-5.4/include/linux/rtl8367.h new file mode 100644 index 0000000..1415039 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/rtl8367.h @@ -0,0 +1,63 @@ +/* + * Platform data definition for the Realtek RTL8367 ethernet switch driver + * + * Copyright (C) 2011 Gabor Juhos + * + * 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. + */ + +#ifndef _RTL8367_H +#define _RTL8367_H + +#define RTL8367_DRIVER_NAME "rtl8367" +#define RTL8367B_DRIVER_NAME "rtl8367b" + +enum rtl8367_port_speed { + RTL8367_PORT_SPEED_10 = 0, + RTL8367_PORT_SPEED_100, + RTL8367_PORT_SPEED_1000, +}; + +struct rtl8367_port_ability { + int force_mode; + int nway; + int txpause; + int rxpause; + int link; + int duplex; + enum rtl8367_port_speed speed; +}; + +enum rtl8367_extif_mode { + RTL8367_EXTIF_MODE_DISABLED = 0, + RTL8367_EXTIF_MODE_RGMII, + RTL8367_EXTIF_MODE_MII_MAC, + RTL8367_EXTIF_MODE_MII_PHY, + RTL8367_EXTIF_MODE_TMII_MAC, + RTL8367_EXTIF_MODE_TMII_PHY, + RTL8367_EXTIF_MODE_GMII, + RTL8367_EXTIF_MODE_RGMII_33V, + RTL8367B_EXTIF_MODE_RMII_MAC = 7, + RTL8367B_EXTIF_MODE_RMII_PHY, + RTL8367B_EXTIF_MODE_RGMII_33V, +}; + +struct rtl8367_extif_config { + unsigned int txdelay; + unsigned int rxdelay; + enum rtl8367_extif_mode mode; + struct rtl8367_port_ability ability; +}; + +struct rtl8367_platform_data { + unsigned gpio_sda; + unsigned gpio_sck; + void (*hw_reset)(bool active); + + struct rtl8367_extif_config *extif0_cfg; + struct rtl8367_extif_config *extif1_cfg; +}; + +#endif /* _RTL8367_H */ diff --git a/ipq806x/files-5.4/include/linux/switch.h b/ipq806x/files-5.4/include/linux/switch.h new file mode 100644 index 0000000..4e62384 --- /dev/null +++ b/ipq806x/files-5.4/include/linux/switch.h @@ -0,0 +1,179 @@ +/* + * switch.h: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _LINUX_SWITCH_H +#define _LINUX_SWITCH_H + +#include +#include + +struct switch_dev; +struct switch_op; +struct switch_val; +struct switch_attr; +struct switch_attrlist; +struct switch_led_trigger; + +int register_switch(struct switch_dev *dev, struct net_device *netdev); +void unregister_switch(struct switch_dev *dev); + +/** + * struct switch_attrlist - attribute list + * + * @n_attr: number of attributes + * @attr: pointer to the attributes array + */ +struct switch_attrlist { + int n_attr; + const struct switch_attr *attr; +}; + +enum switch_port_speed { + SWITCH_PORT_SPEED_UNKNOWN = 0, + SWITCH_PORT_SPEED_10 = 10, + SWITCH_PORT_SPEED_100 = 100, + SWITCH_PORT_SPEED_1000 = 1000, +}; + +struct switch_port_link { + bool link; + bool duplex; + bool aneg; + bool tx_flow; + bool rx_flow; + enum switch_port_speed speed; + /* in ethtool adv_t format */ + u32 eee; +}; + +struct switch_port_stats { + unsigned long long tx_bytes; + unsigned long long rx_bytes; +}; + +/** + * struct switch_dev_ops - switch driver operations + * + * @attr_global: global switch attribute list + * @attr_port: port attribute list + * @attr_vlan: vlan attribute list + * + * Callbacks: + * + * @get_vlan_ports: read the port list of a VLAN + * @set_vlan_ports: set the port list of a VLAN + * + * @get_port_pvid: get the primary VLAN ID of a port + * @set_port_pvid: set the primary VLAN ID of a port + * + * @apply_config: apply all changed settings to the switch + * @reset_switch: resetting the switch + */ +struct switch_dev_ops { + struct switch_attrlist attr_global, attr_port, attr_vlan; + + int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val); + + int (*get_port_pvid)(struct switch_dev *dev, int port, int *val); + int (*set_port_pvid)(struct switch_dev *dev, int port, int val); + + int (*apply_config)(struct switch_dev *dev); + int (*reset_switch)(struct switch_dev *dev); + + int (*get_port_link)(struct switch_dev *dev, int port, + struct switch_port_link *link); + int (*set_port_link)(struct switch_dev *dev, int port, + struct switch_port_link *link); + int (*get_port_stats)(struct switch_dev *dev, int port, + struct switch_port_stats *stats); + + int (*phy_read16)(struct switch_dev *dev, int addr, u8 reg, u16 *value); + int (*phy_write16)(struct switch_dev *dev, int addr, u8 reg, u16 value); +}; + +struct switch_dev { + struct device_node *of_node; + const struct switch_dev_ops *ops; + /* will be automatically filled */ + char devname[IFNAMSIZ]; + + const char *name; + /* NB: either alias or netdev must be set */ + const char *alias; + struct net_device *netdev; + + unsigned int ports; + unsigned int vlans; + unsigned int cpu_port; + + /* the following fields are internal for swconfig */ + unsigned int id; + struct list_head dev_list; + unsigned long def_global, def_port, def_vlan; + + struct mutex sw_mutex; + struct switch_port *portbuf; + struct switch_portmap *portmap; + struct switch_port_link linkbuf; + + char buf[128]; + +#ifdef CONFIG_SWCONFIG_LEDS + struct switch_led_trigger *led_trigger; +#endif +}; + +struct switch_port { + u32 id; + u32 flags; +}; + +struct switch_portmap { + u32 virt; + const char *s; +}; + +struct switch_val { + const struct switch_attr *attr; + unsigned int port_vlan; + unsigned int len; + union { + const char *s; + u32 i; + struct switch_port *ports; + struct switch_port_link *link; + } value; +}; + +struct switch_attr { + int disabled; + int type; + const char *name; + const char *description; + + int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); + int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val); + + /* for driver internal use */ + int id; + int ofs; + int max; +}; + +int switch_generic_set_link(struct switch_dev *dev, int port, + struct switch_port_link *link); + +#endif /* _LINUX_SWITCH_H */ diff --git a/ipq806x/files-5.4/include/uapi/linux/switch.h b/ipq806x/files-5.4/include/uapi/linux/switch.h new file mode 100644 index 0000000..ea44965 --- /dev/null +++ b/ipq806x/files-5.4/include/uapi/linux/switch.h @@ -0,0 +1,119 @@ +/* + * switch.h: Switch configuration API + * + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UAPI_LINUX_SWITCH_H +#define _UAPI_LINUX_SWITCH_H + +#include +#include +#include +#include +#ifndef __KERNEL__ +#include +#include +#include +#endif + +/* main attributes */ +enum { + SWITCH_ATTR_UNSPEC, + /* global */ + SWITCH_ATTR_TYPE, + /* device */ + SWITCH_ATTR_ID, + SWITCH_ATTR_DEV_NAME, + SWITCH_ATTR_ALIAS, + SWITCH_ATTR_NAME, + SWITCH_ATTR_VLANS, + SWITCH_ATTR_PORTS, + SWITCH_ATTR_PORTMAP, + SWITCH_ATTR_CPU_PORT, + /* attributes */ + SWITCH_ATTR_OP_ID, + SWITCH_ATTR_OP_TYPE, + SWITCH_ATTR_OP_NAME, + SWITCH_ATTR_OP_PORT, + SWITCH_ATTR_OP_VLAN, + SWITCH_ATTR_OP_VALUE_INT, + SWITCH_ATTR_OP_VALUE_STR, + SWITCH_ATTR_OP_VALUE_PORTS, + SWITCH_ATTR_OP_VALUE_LINK, + SWITCH_ATTR_OP_DESCRIPTION, + /* port lists */ + SWITCH_ATTR_PORT, + SWITCH_ATTR_MAX +}; + +enum { + /* port map */ + SWITCH_PORTMAP_PORTS, + SWITCH_PORTMAP_SEGMENT, + SWITCH_PORTMAP_VIRT, + SWITCH_PORTMAP_MAX +}; + +/* commands */ +enum { + SWITCH_CMD_UNSPEC, + SWITCH_CMD_GET_SWITCH, + SWITCH_CMD_NEW_ATTR, + SWITCH_CMD_LIST_GLOBAL, + SWITCH_CMD_GET_GLOBAL, + SWITCH_CMD_SET_GLOBAL, + SWITCH_CMD_LIST_PORT, + SWITCH_CMD_GET_PORT, + SWITCH_CMD_SET_PORT, + SWITCH_CMD_LIST_VLAN, + SWITCH_CMD_GET_VLAN, + SWITCH_CMD_SET_VLAN +}; + +/* data types */ +enum switch_val_type { + SWITCH_TYPE_UNSPEC, + SWITCH_TYPE_INT, + SWITCH_TYPE_STRING, + SWITCH_TYPE_PORTS, + SWITCH_TYPE_LINK, + SWITCH_TYPE_NOVAL, +}; + +/* port nested attributes */ +enum { + SWITCH_PORT_UNSPEC, + SWITCH_PORT_ID, + SWITCH_PORT_FLAG_TAGGED, + SWITCH_PORT_ATTR_MAX +}; + +/* link nested attributes */ +enum { + SWITCH_LINK_UNSPEC, + SWITCH_LINK_FLAG_LINK, + SWITCH_LINK_FLAG_DUPLEX, + SWITCH_LINK_FLAG_ANEG, + SWITCH_LINK_FLAG_TX_FLOW, + SWITCH_LINK_FLAG_RX_FLOW, + SWITCH_LINK_SPEED, + SWITCH_LINK_FLAG_EEE_100BASET, + SWITCH_LINK_FLAG_EEE_1000BASET, + SWITCH_LINK_ATTR_MAX, +}; + +#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000 + + +#endif /* _UAPI_LINUX_SWITCH_H */ diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts new file mode 100644 index 0000000..c6feb71 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8062.dtsi" +#include + +/delete-node/ &nand_pins; + +/ { + model = "NEC Platforms Aterm WG2600HP3"; + compatible = "nec,wg2600hp3", "qcom,ipq8062", "qcom,ipq8064"; + + memory { + device_type = "memory"; + reg = <0x42000000 0x1e000000>; + }; + + aliases { + label-mac-device = &gmac2; + + led-boot = &led_power_green; + led-failsafe = &led_power_red; + led-running = &led_power_green; + led-upgrade = &led_power_red; + }; + + keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&buttons_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + mode0 { + label = "mode0"; + gpios = <&qcom_pinmux 40 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + mode1 { + label = "mode1"; + gpios = <&qcom_pinmux 41 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-0 = <&leds_pins>; + pinctrl-names = "default"; + + led_power_green: power_green { + label = "green:power"; + gpios = <&qcom_pinmux 14 GPIO_ACTIVE_HIGH>; + }; + + led_power_red: power_red { + label = "red:power"; + gpios = <&qcom_pinmux 35 GPIO_ACTIVE_HIGH>; + }; + + active_green { + label = "green:active"; + gpios = <&qcom_pinmux 42 GPIO_ACTIVE_HIGH>; + }; + + active_red { + label = "red:active"; + gpios = <&qcom_pinmux 38 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "green:wlan2g"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy1tpt"; + }; + + wlan2g_red { + label = "red:wlan2g"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_green { + label = "green:wlan5g"; + gpios = <&qcom_pinmux 57 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tpt"; + }; + + wlan5g_red { + label = "red:wlan5g"; + gpios = <&qcom_pinmux 58 GPIO_ACTIVE_HIGH>; + }; + + tv_green { + label = "green:tv"; + gpios = <&qcom_pinmux 46 GPIO_ACTIVE_HIGH>; + }; + + tv_red { + label = "red:tv"; + gpios = <&qcom_pinmux 36 GPIO_ACTIVE_HIGH>; + }; + + converter_green { + label = "green:converter"; + gpios = <&qcom_pinmux 43 GPIO_ACTIVE_HIGH>; + }; + + converter_red { + label = "red:converter"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + pinctrl-0 = <&akro_pins>; + pinctrl-names = "default"; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + buttons_pins: buttons_pins { + mux { + pins = "gpio22", "gpio24", "gpio40", + "gpio41"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + leds_pins: leds_pins { + mux { + pins = "gpio14", "gpio15", "gpio35", + "gpio36", "gpio38", "gpio42", + "gpio43", "gpio46", "gpio55", + "gpio56", "gpio57", "gpio58"; + function = "gpio"; + bias-pull-down; + }; + + akro2 { + pins = "gpio15", "gpio35", "gpio38", + "gpio42", "gpio43", "gpio46", + "gpio55", "gpio56", "gpio57", + "gpio58"; + drive-strength = <2>; + }; + + akro4 { + pins = "gpio14", "gpio36"; + drive-strength = <4>; + }; + }; + + /* + * Stock firmware has the following settings, so let's do the same. + * I don't sure why these are required. + */ + akro_pins: akro_pinmux { + akro { + pins = "gpio17", "gpio26", "gpio47"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + reset { + pins = "gpio45"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-low; + }; + + gmac0_rgmii { + pins = "gpio25"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + }; +}; + +&gsbi5 { + status = "okay"; + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0000000 0x0020000>; + read-only; + }; + + partition@20000 { + label = "MIBIB"; + reg = <0x0020000 0x0020000>; + read-only; + }; + + partition@40000 { + label = "SBL2"; + reg = <0x0040000 0x0040000>; + read-only; + }; + + partition@80000 { + label = "SBL3"; + reg = <0x0080000 0x0080000>; + read-only; + }; + + partition@100000 { + label = "DDRCONFIG"; + reg = <0x0100000 0x0010000>; + read-only; + }; + + partition@110000 { + label = "SSD"; + reg = <0x0110000 0x0010000>; + read-only; + }; + + partition@120000 { + label = "TZ"; + reg = <0x0120000 0x0080000>; + read-only; + }; + + partition@1a0000 { + label = "RPM"; + reg = <0x01a0000 0x0080000>; + read-only; + }; + + partition@220000 { + label = "APPSBL"; + reg = <0x0220000 0x0080000>; + read-only; + }; + + partition@2a0000 { + label = "APPSBLENV"; + reg = <0x02a0000 0x0010000>; + read-only; + }; + + factory: partition@2b0000 { + label = "PRODUCTDATA"; + reg = <0x02b0000 0x0030000>; + read-only; + }; + + partition@2e0000 { + label = "ART"; + reg = <0x02e0000 0x0040000>; + read-only; + }; + + partition@320000 { + label = "TP"; + reg = <0x0320000 0x0040000>; + read-only; + }; + + partition@360000 { + label = "TINY"; + reg = <0x0360000 0x0500000>; + read-only; + }; + + partition@860000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x0860000 0x17a0000>; + }; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + reg = <0x00010000 0 0 0 0>; + + qcom,ath10k-calibration-variant = "NEC-Platforms-WG2600HP3"; + }; + }; +}; + +&pcie1 { + status = "okay"; + force_gen1 = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + reg = <0x00010000 0 0 0 0>; + + ieee80211-freq-limit = <2400000 2483000>; + qcom,ath10k-calibration-variant = "NEC-Platforms-WG2600HP3"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x04 0x80080080 /* PAD0_MODE */ + 0x0c 0x06000000 /* PAD6_MODE */ + 0x10 0x002613a0 /* PWS_REG */ + 0x50 0xcc36cc36 /* LED_CTRL0 */ + 0x54 0xca36ca36 /* LED_CTRL1 */ + 0x58 0xc936c936 /* LED_CTRL2 */ + 0x5c 0x03ffff00 /* LED_CTRL3 */ + 0x7c 0x0000004e /* PORT0_STATUS */ + 0x94 0x0000004e /* PORT6_STATUS */ + 0xe0 0xc74164de /* SGMII_CTRL */ + 0xe4 0x0006a545 /* MAC_PWR_SEL */ + >; + }; +}; + +&gmac1 { + status = "okay"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + phy-mode = "rgmii"; + qcom,id = <1>; + mdiobus = <&mdio0>; + nvmem-cells = <&macaddr_factory_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + mdiobus = <&mdio0>; + nvmem-cells = <&macaddr_factory_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&factory { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_factory_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi new file mode 100644 index 0000000..4b00713 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8062.dtsi @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "qcom-ipq8064.dtsi" + +/ { + model = "Qualcomm IPQ8062"; + compatible = "qcom,ipq8062", "qcom,ipq8064"; + + aliases { + serial0 = &gsbi4_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; +}; + +&gsbi4 { + qcom,mode = ; + status = "okay"; + + serial@16340000 { + status = "okay"; + }; + /* + * The i2c device on gsbi4 should not be enabled. + * On ipq806x designs gsbi4 i2c is meant for exclusive + * RPM usage. Turning this on in kernel manifests as + * i2c failure for the RPM. + */ +}; + +&opp_table0 { + /delete-node/opp-1200000000; + /delete-node/opp-1400000000; + + opp-384000000 { + opp-microvolt-speed0-pvs0-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs1-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs2-v0 = <807500 850000 892500>; + opp-microvolt-speed0-pvs3-v0 = <760000 800000 840000>; + }; + + opp-600000000 { + opp-microvolt-speed0-pvs0-v0 = <950000 1000000 1050000>; + opp-microvolt-speed0-pvs1-v0 = <945000 950000 955000>; + opp-microvolt-speed0-pvs2-v0 = <895000 900000 905000>; + opp-microvolt-speed0-pvs3-v0 = <845000 850000 855000>; + }; + + opp-800000000 { + opp-microvolt-speed0-pvs0-v0 = <997500 1050000 1102500>; + opp-microvolt-speed0-pvs1-v0 = < 995000 1000000 1005000>; + opp-microvolt-speed0-pvs2-v0 = < 945000 950000 955000>; + opp-microvolt-speed0-pvs3-v0 = < 895000 900000 905000>; + }; + + opp-1000000000 { + opp-microvolt-speed0-pvs0-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs1-v0 = <997500 1050000 1102500>; + opp-microvolt-speed0-pvs2-v0 = < 995000 1000000 1005000>; + opp-microvolt-speed0-pvs3-v0 = < 945000 950000 955000>; + }; +}; + +&pcie0 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&pcie1 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&pcie2 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&smb208_s2a { + regulator-max-microvolt = <1150000>; +}; + +&smb208_s2b { + regulator-max-microvolt = <1150000>; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi new file mode 100644 index 0000000..daa7b14 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-v2.0.dtsi" + +#include + +/ { + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + label-mac-device = &gmac2; + }; +}; + +&qcom_pinmux { + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + usb0_pwr_en_pin: usb0_pwr_en_pin { + mux { + pins = "gpio25"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + usb1_pwr_en_pin: usb1_pwr_en_pin { + mux { + pins = "gpio23"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + partition@20000 { + label = "MIBIB"; + reg = <0x20000 0x20000>; + read-only; + }; + + partition@40000 { + label = "SBL2"; + reg = <0x40000 0x20000>; + read-only; + }; + + partition@60000 { + label = "SBL3"; + reg = <0x60000 0x30000>; + read-only; + }; + + partition@90000 { + label = "DDRCONFIG"; + reg = <0x90000 0x10000>; + read-only; + }; + + partition@a0000 { + label = "SSD"; + reg = <0xa0000 0x10000>; + read-only; + }; + + partition@b0000 { + label = "TZ"; + reg = <0xb0000 0x30000>; + read-only; + }; + + partition@e0000 { + label = "RPM"; + reg = <0xe0000 0x20000>; + read-only; + }; + + partition@100000 { + label = "fs-uboot"; + reg = <0x100000 0x70000>; + read-only; + }; + + partition@170000 { + label = "uboot-env"; + reg = <0x170000 0x40000>; + read-only; + }; + + partition@1b0000 { + label = "radio"; + reg = <0x1b0000 0x40000>; + read-only; + }; + + partition@1f0000 { + label = "os-image"; + reg = <0x1f0000 0x400000>; + }; + + partition@5f0000 { + label = "rootfs"; + reg = <0x5f0000 0x1900000>; + }; + + defaultmac: partition@1ef0000 { + label = "default-mac"; + reg = <0x1ef0000 0x00200>; + read-only; + }; + + partition@1ef0200 { + label = "pin"; + reg = <0x1ef0200 0x00200>; + read-only; + }; + + partition@1ef0400 { + label = "product-info"; + reg = <0x1ef0400 0x0fc00>; + read-only; + }; + + partition@1f00000 { + label = "partition-table"; + reg = <0x1f00000 0x10000>; + read-only; + }; + + partition@1f10000 { + label = "soft-version"; + reg = <0x1f10000 0x10000>; + read-only; + }; + + partition@1f20000 { + label = "support-list"; + reg = <0x1f20000 0x10000>; + read-only; + }; + + partition@1f30000 { + label = "profile"; + reg = <0x1f30000 0x10000>; + read-only; + }; + + partition@1f40000 { + label = "default-config"; + reg = <0x1f40000 0x10000>; + read-only; + }; + + partition@1f50000 { + label = "user-config"; + reg = <0x1f50000 0x40000>; + read-only; + }; + + partition@1f90000 { + label = "qos-db"; + reg = <0x1f90000 0x40000>; + read-only; + }; + + partition@1fd0000 { + label = "usb-config"; + reg = <0x1fd0000 0x10000>; + read-only; + }; + + partition@1fe0000 { + label = "log"; + reg = <0x1fe0000 0x20000>; + read-only; + }; + }; + }; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pin>; + pinctrl-names = "default"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pin>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_defaultmac_8>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_defaultmac_8>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&defaultmac { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_defaultmac_8: macaddr@8 { + reg = <0x8 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts new file mode 100644 index 0000000..6cb21fc --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-ad7200-c2600.dtsi" + +/ { + model = "TP-Link Talon AD7200"; + compatible = "tplink,ad7200", "qcom,ipq8064"; + + aliases { + led-boot = &led_status; + led-failsafe = &led_status; + led-running = &led_status; + led-upgrade = &led_status; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + led_enable { + label = "led-enable"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + lan { + label = "blue:lan"; + gpios = <&qcom_pinmux 2 GPIO_ACTIVE_HIGH>; + }; + + usb1 { + label = "blue:usb1"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + wlan5g { + label = "blue:wlan5g"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_HIGH>; + }; + + usb3 { + label = "blue:usb3"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "blue:wlan2g"; + gpios = <&qcom_pinmux 17 GPIO_ACTIVE_HIGH>; + }; + + wan_orange { + label = "orange:wan"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + wan_blue { + label = "blue:wan"; + gpios = <&qcom_pinmux 33 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "blue:wps"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + }; + + wlan60g { + label = "blue:wlan60g"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + led_status: status { + label = "blue:status"; + gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio53", "gpio54", "gpio67"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio2", "gpio8", "gpio15", "gpio16", "gpio17", "gpio26", + "gpio33", "gpio55", "gpio56", "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&pcie2 { + status = "okay"; + max-link-speed = <1>; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts new file mode 100644 index 0000000..29476e3 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap148.dts @@ -0,0 +1,121 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. IPQ8064/AP-148"; + compatible = "qcom,ipq8064-ap148", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&flash { + partitions { + compatible = "qcom,smem-part"; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts new file mode 100644 index 0000000..914c370 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ap161.dts @@ -0,0 +1,159 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +/ { + model = "Qualcomm IPQ8064/AP161"; + compatible = "qcom,ipq8064-ap161", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + }; +}; + +&qcom_pinmux { + rgmii2_pins: rgmii2_pins { + mux { + pins = "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32", + "gpio51", "gpio52", "gpio59", + "gpio60", "gpio61", "gpio62", + "gpio2", "gpio66"; + }; + }; +}; + +&flash { + partitions { + compatible = "qcom,smem-part"; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&pcie2 { + status = "okay"; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x20080 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + qca,phy-rgmii-en; + qca,txclk-delay-en; + qca,rxclk-delay-en; + }; + + phy3: ethernet-phy@3 { + device_type = "ethernet-phy"; + reg = <3>; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts new file mode 100644 index 0000000..cef1aba --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-c2600.dts @@ -0,0 +1,119 @@ +#include "qcom-ipq8064-ad7200-c2600.dtsi" + +/ { + model = "TP-Link Archer C2600"; + compatible = "tplink,c2600", "qcom,ipq8064"; + + aliases { + led-boot = &power; + led-failsafe = &general; + led-running = &power; + led-upgrade = &general; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 49 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + ledswitch { + label = "ledswitch"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + lan { + label = "white:lan"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_HIGH>; + }; + + usb4 { + label = "white:usb_4"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb_2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 33 GPIO_ACTIVE_LOW>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + general: general { + label = "white:general"; + gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio16", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6", "gpio7", "gpio8", "gpio9", "gpio26", "gpio33", + "gpio53", "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts new file mode 100644 index 0000000..6e022ce --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-d7800.dts @@ -0,0 +1,339 @@ +#include "qcom-ipq8064-v2.0.dtsi" + +#include + +/ { + model = "Netgear Nighthawk X4 D7800"; + compatible = "netgear,d7800", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0xe000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power_white; + led-failsafe = &power_amber; + led-running = &power_white; + led-upgrade = &power_amber; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + power_amber: power_amber { + label = "amber:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + power_white: power_white { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23", + "gpio24","gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio15"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio16", "gpio68"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + }; + + artbak: art@1340000 { + label = "artbak"; + reg = <0x1340000 0x0140000>; + read-only; + }; + + kernel@1480000 { + label = "kernel"; + reg = <0x1480000 0x0400000>; + }; + + ubi@1880000 { + label = "ubi"; + reg = <0x1880000 0x1C00000>; + }; + + netgear@3480000 { + label = "netgear"; + reg = <0x3480000 0x4480000>; + read-only; + }; + + reserve@7900000 { + label = "reserve"; + reg = <0x7900000 0x0700000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&art { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-db149.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-db149.dts new file mode 100644 index 0000000..8e8d942 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-db149.dts @@ -0,0 +1,163 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +/ { + model = "Qualcomm IPQ8064/DB149"; + compatible = "qcom,ipq8064-db149", "qcom,ipq8064"; + + aliases { + serial0 = &gsbi2_serial; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; +}; + +&qcom_pinmux { + rgmii0_pins: rgmii0_pins { + mux { + pins = "gpio2", "gpio66"; + drive-strength = <8>; + bias-disable; + }; + }; +}; + +&gsbi2 { + qcom,mode = ; + status = "okay"; + + gsbi2_serial: serial@12490000 { + status = "okay"; + }; +}; + +&gsbi4 { + status = "disabled"; +}; + +&gsbi4_serial { + status = "disabled"; +}; + +&flash { + m25p,fast-read; + + partition@0 { + label = "lowlevel_init"; + reg = <0x0 0x1b0000>; + }; + + partition@1 { + label = "u-boot"; + reg = <0x1b0000 0x80000>; + }; + + partition@2 { + label = "u-boot-env"; + reg = <0x230000 0x40000>; + }; + + partition@3 { + label = "caldata"; + reg = <0x270000 0x40000>; + }; + + partition@4 { + label = "firmware"; + reg = <0x2b0000 0x1d50000>; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie2 { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; + + phy6: ethernet-phy@6 { + reg = <6>; + }; + + phy7: ethernet-phy@7 { + reg = <7>; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + phy-handle = <&phy4>; + + pinctrl-0 = <&rgmii0_pins>; + pinctrl-names = "default"; +}; + +&gmac1 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + phy-handle = <&phy6>; +}; + +&gmac3 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <3>; + phy-handle = <&phy7>; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts new file mode 100644 index 0000000..9d82d52 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-eax500.dtsi" + +/ { + model = "Linksys EA7500 V1 WiFi Router"; + compatible = "linksys,ea7500-v1", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0xe000000>; + device_type = "memory"; + }; + + aliases { + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + }; + + chosen { + /* look for root deviceblock nbr in this bootarg */ + find-rootblock = "ubi.mtd="; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power: power { + label = "white:power"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + default-state = "keep"; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio65", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&partitions { + partition@5f80000 { + label = "sysdiag"; + reg = <0x5f80000 0x100000>; + }; + + partition@6080000 { + label = "syscfg"; + reg = <0x6080000 0x1f80000>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts new file mode 100644 index 0000000..1c6a4bd --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts @@ -0,0 +1,128 @@ +#include "qcom-ipq8064-eax500.dtsi" + +/ { + model = "Linksys EA8500 WiFi Router"; + compatible = "linksys,ea8500", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + wps { + label = "green:wps"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + + led_power: power { + label = "white:power"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + default-state = "keep"; + }; + + wifi { + label = "green:wifi"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio65", "gpio67", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6", "gpio53", "gpio54"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&partitions { + partition@5f80000 { + label = "syscfg"; + reg = <0x5f80000 0x2080000>; + }; +}; + +&mdio0 { + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <1>; + qcom,rgmii_delay = <0>; + qcom,emulation = <0>; +}; + +/* LAN */ +&gmac2 { + qcom,phy_mdio_addr = <0>; /* none */ + qcom,poll_required = <0>; /* no polling */ + qcom,rgmii_delay = <0>; + qcom,emulation = <0>; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi new file mode 100644 index 0000000..98c4b2d --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-v2.0.dtsi" + +#include + +/ { + chosen { + bootargs = "console=ttyMSM0,115200n8"; + /* append to bootargs adding the root deviceblock nbr from bootloader */ + append-rootblock = "ubi.mtd="; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + max-link-speed = <1>; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie2 { + status = "okay"; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot_pages_size = <0x0c80000>; + + partitions: partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + + partition@40000 { + label = "MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + + partition@180000 { + label = "SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + + partition@2c0000 { + label = "SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + + partition@540000 { + label = "DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + + partition@660000 { + label = "SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + + partition@780000 { + label = "TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + + partition@a00000 { + label = "RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + + art: partition@c80000 { + label = "art"; + reg = <0x0c80000 0x0140000>; + read-only; + }; + + partition@dc0000 { + label = "APPSBL"; + reg = <0x0dc0000 0x0100000>; + read-only; + }; + + partition@ec0000 { + label = "u_env"; + reg = <0x0ec0000 0x0040000>; + }; + + partition@f00000 { + label = "s_env"; + reg = <0x0f00000 0x0040000>; + }; + + partition@f40000 { + label = "devinfo"; + reg = <0x0f40000 0x0040000>; + }; + + partition@f80000 { + label = "kernel1"; + reg = <0x0f80000 0x2800000>; /* 3 MB spill to rootfs */ + }; + + partition@1280000 { + label = "rootfs1"; + reg = <0x1280000 0x2500000>; + }; + + partition@3780000 { + label = "kernel2"; + reg = <0x3780000 0x2800000>; + }; + + partition@3a80000 { + label = "rootfs2"; + reg = <0x3a80000 0x2500000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x00010 0x2613a0 /* PWS_REG */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts new file mode 100644 index 0000000..45efb2b --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-g10.dts @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "qcom-ipq8064-v2.0.dtsi" + +#include +#include + +/ { + compatible = "asrock,g10", "qcom,ipq8064"; + model = "ASRock G10"; + + aliases { + ethernet0 = &gmac1; + ethernet1 = &gmac0; + + led-boot = &led_status_blue; + led-failsafe = &led_status_amber; + led-running = &led_status_blue; + led-upgrade = &led_status_amber; + }; + + chosen { + bootargs-override = "console=ttyMSM0,115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + /* + * this is a bit misleading. Because there are about seven + * multicolor LEDs connected all wired together in parallel. + */ + + status_yellow { + label = "yellow:status"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + led_status_amber: status_amber { + label = "amber:status"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + led_status_blue: status_blue { + label = "blue:status"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + /* + * LED is declared in vendors boardfile but it's not + * working and the manual doesn't mention anything + * about the LED being white. + + status_white { + label = "white:status"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + */ + }; + + i2c-gpio { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "i2c-gpio"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>, /* sda */ + <&qcom_pinmux 54 GPIO_ACTIVE_HIGH>; /* scl */ + i2c-gpio,delay-us = <5>; + i2c-gpio,scl-output-only; + + mcu@50 { + reg = <0x50>; + compatible = "sonix,sn8f25e21"; + }; + }; + + keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + ir-remote { + label = "ir-remote"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps5g { + label = "wps5g"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps2g { + label = "wps2g"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&gmac1 { + status = "okay"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi4_serial { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + +&qcom_pinmux { + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio26"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio15", "gpio16", "gpio64", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart0_pins: uart0_pins { + mux { + pins = "gpio10", "gpio11"; + function = "gsbi4"; + drive-strength = <10>; + bias-disable; + }; + }; +}; + +&rpm { + pinctrl-0 = <&i2c4_pins>; + pinctrl-names = "default"; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&tcsr { + qcom,usb-ctrl-select = ; +}; + +/delete-node/ &pcie2_pins; +/delete-node/ &pcie2; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts new file mode 100644 index 0000000..c7d26a0 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500.dts @@ -0,0 +1,316 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +#include +#include + +/ { + model = "Netgear Nighthawk X4 R7500"; + compatible = "netgear,r7500", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0xe000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power_white; + led-failsafe = &power_amber; + led-running = &power_white; + led-upgrade = &power_amber; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + power_amber: power_amber { + label = "amber:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + power_white: power_white { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23", + "gpio24","gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&gsbi5 { + status = "disabled"; + + spi@1a280000 { + status = "disabled"; + }; +}; + +&usb3_0 { + clocks = <&gcc USB30_1_MASTER_CLK>; + status = "okay"; +}; + +&usb3_1 { + clocks = <&gcc USB30_0_MASTER_CLK>; + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + }; + + kernel@1340000 { + label = "kernel"; + reg = <0x1340000 0x0400000>; + }; + + ubi@1740000 { + label = "ubi"; + reg = <0x1740000 0x1600000>; + }; + + netgear@2d40000 { + label = "netgear"; + reg = <0x2d40000 0x0c00000>; + read-only; + }; + + reserve@3940000 { + label = "reserve"; + reg = <0x3940000 0x46c0000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&tcsr { + qcom,usb-ctrl-select = ; + compatible = "qcom,tcsr"; +}; + +&adm_dma { + status = "okay"; +}; + +&art { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts new file mode 100644 index 0000000..0f22480 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts @@ -0,0 +1,337 @@ +#include "qcom-ipq8064-v2.0.dtsi" + +#include + +/ { + model = "Netgear Nighthawk X4 R7500v2"; + compatible = "netgear,r7500v2", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + rsvd@5fe00000 { + reg = <0x5fe00000 0x200000>; + reusable; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb1 { + label = "amber:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb3 { + label = "amber:usb3"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + status { + label = "amber:status"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + internet { + label = "white:internet"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan { + label = "white:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23", + "gpio24","gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio15"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio16", "gpio68"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + }; + + artbak: art@1340000 { + label = "artbak"; + reg = <0x1340000 0x0140000>; + read-only; + }; + + kernel@1480000 { + label = "kernel"; + reg = <0x1480000 0x0400000>; + }; + + ubi@1880000 { + label = "ubi"; + reg = <0x1880000 0x6080000>; + }; + + reserve@7900000 { + label = "reserve"; + reg = <0x7900000 0x0700000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&art { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts new file mode 100644 index 0000000..a50204f --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-v2.0.dtsi" + +#include +#include + +/ { + model = "Ubiquiti UniFi AC HD"; + compatible = "ubnt,unifi-ac-hd", "qcom,ipq8064"; + + aliases { + label-mac-device = &gmac2; + led-boot = &led_dome_white; + led-failsafe = &led_dome_white; + led-running = &led_dome_blue; + led-upgrade = &led_dome_blue; + mdio-gpio0 = &mdio0; + ethernet0 = &gmac2; + ethernet1 = &gmac1; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_dome_blue: dome_blue { + label = "blue:dome"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + led_dome_white: dome_white { + label = "white:dome"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio9", "gpio53"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + drive-strength = <10>; + bias-none; + }; + + cs { + pins = "gpio20"; + drive-strength = <12>; + }; + }; +}; + +&CPU_SPC { + status = "disabled"; +}; + +&gsbi5 { + status = "okay"; + + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + cs-gpios = <&qcom_pinmux 20 0>; + + flash@0 { + compatible = "mx25u25635f", "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + partition@20000 { + label = "MIBIB"; + reg = <0x20000 0x10000>; + read-only; + }; + + partition@30000 { + label = "SBL2"; + reg = <0x30000 0x20000>; + read-only; + }; + + partition@50000 { + label = "SBL3"; + reg = <0x50000 0x30000>; + read-only; + }; + + partition@80000 { + label = "DDRCONFIG"; + reg = <0x80000 0x10000>; + read-only; + }; + + partition@90000 { + label = "SSD"; + reg = <0x90000 0x10000>; + read-only; + }; + + partition@a0000 { + label = "TZ"; + reg = <0xa0000 0x30000>; + read-only; + }; + + partition@d0000 { + label = "RPM"; + reg = <0xd0000 0x20000>; + read-only; + }; + + partition@f0000 { + label = "APPSBL"; + reg = <0xf0000 0xc0000>; + read-only; + }; + + partition@1b0000 { + label = "APPSBLENV"; + reg = <0x1b0000 0x10000>; + read-only; + }; + + eeprom: partition@1c0000 { + label = "EEPROM"; + reg = <0x1c0000 0x10000>; + read-only; + }; + + partition@1d0000 { + label = "bootselect"; + reg = <0x1d0000 0x10000>; + }; + + partition@1e0000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x1e0000 0xe70000>; + }; + + partition@1050000 { + label = "kernel1"; + reg = <0x1050000 0xe70000>; + read-only; + }; + + partition@1ec0000 { + label = "debug"; + reg = <0x1ec0000 0x100000>; + read-only; + }; + + partition@1fc0000 { + label = "cfg"; + reg = <0x1fc0000 0x40000>; + read-only; + }; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + nand-ecc-strength = <4>; + nand-bus-width = <8>; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy4: ethernet-phy@4 { + reg = <4>; + }; + + phy5: ethernet-phy@5 { + reg = <5>; + }; +}; + +&gmac1 { + status = "okay"; + + mdiobus = <&mdio0>; + phy-handle = <&phy5>; + phy-mode = "sgmii"; + qcom,id = <1>; + + nvmem-cells = <&macaddr_eeprom_6>; + nvmem-cell-names = "mac-address"; +}; + +&gmac2 { + status = "okay"; + + mdiobus = <&mdio0>; + phy-handle = <&phy4>; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_eeprom_0>; + nvmem-cell-names = "mac-address"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + +&tcsr { + status = "okay"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&eeprom { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_eeprom_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_eeprom_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi new file mode 100644 index 0000000..b9ee86a --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi @@ -0,0 +1,69 @@ +#include "qcom-ipq8064.dtsi" + +/ { + aliases { + serial0 = &gsbi4_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; +}; + +&gsbi4 { + qcom,mode = ; + status = "okay"; + + serial@16340000 { + status = "okay"; + }; + /* + * The i2c device on gsbi4 should not be enabled. + * On ipq806x designs gsbi4 i2c is meant for exclusive + * RPM usage. Turning this on in kernel manifests as + * i2c failure for the RPM. + */ +}; + +&CPU_SPC { + status = "okay"; +}; + +&pcie0 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&pcie1 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&pcie2 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&sata { + ports-implemented = <0x1>; +}; + +&ss_phy_0 { + qcom,rx-eq = <2>; + qcom,tx-deamp_3_5db = <32>; + qcom,mpll = <5>; +}; + +&ss_phy_1 { + qcom,rx-eq = <2>; + qcom,tx-deamp_3_5db = <32>; + qcom,mpll = <5>; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts new file mode 100644 index 0000000..54ae075 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts @@ -0,0 +1,362 @@ +#include "qcom-ipq8064-v2.0.dtsi" + +#include + +/ { + model = "TP-Link Archer VR2600v"; + compatible = "tplink,vr2600v", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power; + led-failsafe = &general; + led-running = &power; + led-upgrade = &general; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + dect { + label = "dect"; + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + ledswitch { + label = "ledswitch"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + dsl { + label = "white:dsl"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb { + label = "white:usb"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + lan { + label = "white:lan"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "white:wlan2g"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + wlan5g { + label = "white:wlan5g"; + gpios = <&qcom_pinmux 17 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + phone { + label = "white:phone"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + + wan { + label = "white:wan"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + general: general { + label = "white:general"; + gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio16", "gpio17", + "gpio26", "gpio53", "gpio56", "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio54", "gpio64", "gpio65", "gpio67", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + W25Q128@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + MIBIB@20000 { + label = "MIBIB"; + reg = <0x20000 0x20000>; + read-only; + }; + + SBL2@40000 { + label = "SBL2"; + reg = <0x40000 0x40000>; + read-only; + }; + + SBL3@80000 { + label = "SBL3"; + reg = <0x80000 0x80000>; + read-only; + }; + + DDRCONFIG@100000 { + label = "DDRCONFIG"; + reg = <0x100000 0x10000>; + read-only; + }; + + SSD@110000 { + label = "SSD"; + reg = <0x110000 0x10000>; + read-only; + }; + + TZ@120000 { + label = "TZ"; + reg = <0x120000 0x80000>; + read-only; + }; + + RPM@1a0000 { + label = "RPM"; + reg = <0x1a0000 0x80000>; + read-only; + }; + + APPSBL@220000 { + label = "APPSBL"; + reg = <0x220000 0x80000>; + read-only; + }; + + APPSBLENV@2a0000 { + label = "APPSBLENV"; + reg = <0x2a0000 0x40000>; + read-only; + }; + + OLDART@2e0000 { + label = "OLDART"; + reg = <0x2e0000 0x40000>; + read-only; + }; + + kernel@320000 { + label = "kernel"; + reg = <0x320000 0x300000>; + }; + + rootfs@620000 { + label = "rootfs"; + reg = <0x620000 0x960000>; + }; + + defaultmac: default-mac@0xfaf100 { + label = "default-mac"; + reg = <0xfaf100 0x00200>; + read-only; + }; + + ART@fc0000 { + label = "ART"; + reg = <0xfc0000 0x40000>; + read-only; + }; + }; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_defaultmac_0>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_defaultmac_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&defaultmac { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_defaultmac_0: macaddr@0 { + reg = <0x0 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts new file mode 100644 index 0000000..7148fdf --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts @@ -0,0 +1,398 @@ +#include "qcom-ipq8064-v2.0.dtsi" + +#include + +/ { + model = "NEC Aterm WG2600HP"; + compatible = "nec,wg2600hp", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power_green; + led-failsafe = &power_red; + led-running = &power_green; + led-upgrade = &power_green; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + bridge { + label = "bridge"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + converter { + label = "converter"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + converter_green { + label = "green:converter"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_HIGH>; + }; + + power_red: power_red { + label = "red:power"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + active_green { + label = "green:active"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + active_red { + label = "red:active"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + power_green: power_green { + label = "green:power"; + gpios = <&qcom_pinmux 14 GPIO_ACTIVE_HIGH>; + }; + + converter_red { + label = "red:converter"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "green:wlan2g"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_red { + label = "red:wlan2g"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_green { + label = "green:wlan5g"; + gpios = <&qcom_pinmux 57 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_red { + label = "red:wlan5g"; + gpios = <&qcom_pinmux 58 GPIO_ACTIVE_HIGH>; + }; + + tv_green { + label = "green:tv"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + + tv_red { + label = "red:tv"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&CPU_SPC { + status = "disabled"; +}; + +&adm_dma { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x06000000 /* PAD0_MODE */ + 0x0000c 0x00080080 /* PAD6_MODE */ + 0x000e4 0x0006a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x0000004e /* PORT0_STATUS */ + 0x00094 0x0000004e /* PORT6_STATUS */ + >; + }; + + ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_PRODUCTDATA_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_PRODUCTDATA_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi5 { + status = "okay"; + + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + MIBIB@20000 { + label = "MIBIB"; + reg = <0x20000 0x20000>; + read-only; + }; + + SBL2@40000 { + label = "SBL2"; + reg = <0x40000 0x40000>; + read-only; + }; + + SBL3@80000 { + label = "SBL3"; + reg = <0x80000 0x80000>; + read-only; + }; + + DDRCONFIG@100000 { + label = "DDRCONFIG"; + reg = <0x100000 0x10000>; + read-only; + }; + + SSD@110000 { + label = "SSD"; + reg = <0x110000 0x10000>; + read-only; + }; + + TZ@120000 { + label = "TZ"; + reg = <0x120000 0x80000>; + read-only; + }; + + RPM@1a0000 { + label = "RPM"; + reg = <0x1a0000 0x80000>; + read-only; + }; + + APPSBL@220000 { + label = "APPSBL"; + reg = <0x220000 0x80000>; + read-only; + }; + + APPSBLENV@2a0000 { + label = "APPSBLENV"; + reg = <0x2a0000 0x10000>; + }; + + PRODUCTDATA: PRODUCTDATA@2b0000 { + label = "PRODUCTDATA"; + reg = <0x2b0000 0x30000>; + read-only; + }; + + ART@2e0000 { + label = "ART"; + reg = <0x2e0000 0x40000>; + read-only; + }; + + TP@320000 { + label = "TP"; + reg = <0x320000 0x40000>; + read-only; + }; + + TINY@360000 { + label = "TINY"; + reg = <0x360000 0x500000>; + read-only; + }; + + firmware@860000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x860000 0x17a0000>; + }; + }; + }; + }; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio16", "gpio54", "gpio24", "gpio25"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6", "gpio7", "gpio8", "gpio9", "gpio14", + "gpio15", "gpio55", "gpio56", "gpio57", "gpio58", + "gpio64", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + usb_pwr_en_pins: usb_pwr_en_pins { + mux { + pins = "gpio22"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + output-high; + }; + }; +}; + +&PRODUCTDATA { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_PRODUCTDATA_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_PRODUCTDATA_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts new file mode 100644 index 0000000..ec5d504 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2017 Christian Mehlis + * Copyright (C) 2018 Mathias Kresin + * All rights reserved. + */ + +#include "qcom-ipq8064-v1.0.dtsi" + +#include +#include + +/ { + compatible = "compex,wpq864", "qcom,ipq8064"; + model = "Compex WPQ864"; + + aliases { + mdio-gpio0 = &mdio0; + ethernet0 = &gmac1; + ethernet1 = &gmac0; + + led-boot = &led_pass; + led-failsafe = &led_fail; + led-running = &led_pass; + led-upgrade = &led_pass; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + rss4 { + label = "green:rss4"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + rss3 { + label = "green:rss3"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + rss2 { + label = "orange:rss2"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_HIGH>; + }; + + rss1 { + label = "red:rss1"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + led_pass: pass { + label = "green:pass"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + + led_fail: fail { + label = "green:fail"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + usb { + label = "green:usb"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb-pcie { + label = "green:usb-pcie"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + beeper { + compatible = "gpio-beeper"; + + pinctrl-0 = <&beeper_pins>; + pinctrl-names = "default"; + + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + }; +}; + +&rpm { + pinctrl-0 = <&rpm_pins>; + pinctrl-names = "default"; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + mt29f2g08abbeah4@0 { + compatible = "qcom,nandcs"; + + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + + MIBIB@40000 { + label = "MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + + SBL2@180000 { + label = "SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + + SBL3@2c0000 { + label = "SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + + DDRCONFIG@540000 { + label = "DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + + SSD@660000 { + label = "SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + + TZ@780000 { + label = "TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + + RPM@a00000 { + label = "RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + }; + + ART@1200000 { + label = "ART"; + reg = <0x1200000 0x0140000>; + }; + + ubi@1340000 { + label = "ubi"; + reg = <0x1340000 0x4000000>; + }; + + BOOTCONFIG@5340000 { + label = "BOOTCONFIG"; + reg = <0x5340000 0x0060000>; + }; + + SBL2-1@53a0000- { + label = "SBL2_1"; + reg = <0x53a0000 0x0140000>; + read-only; + }; + + SBL3-1@54e0000 { + label = "SBL3_1"; + reg = <0x54e0000 0x0280000>; + read-only; + }; + + DDRCONFIG-1@5760000 { + label = "DDRCONFIG_1"; + reg = <0x5760000 0x0120000>; + read-only; + }; + + SSD-1@5880000 { + label = "SSD_1"; + reg = <0x5880000 0x0120000>; + read-only; + }; + + TZ-1@59a0000 { + label = "TZ_1"; + reg = <0x59a0000 0x0280000>; + read-only; + }; + + RPM-1@5c20000 { + label = "RPM_1"; + reg = <0x5c20000 0x0280000>; + read-only; + }; + + BOOTCONFIG1@5ea0000 { + label = "BOOTCONFIG1"; + reg = <0x5ea0000 0x0060000>; + }; + + APPSBL-1@5f00000 { + label = "APPSBL_1"; + reg = <0x5f00000 0x0500000>; + read-only; + }; + + ubi-1@6400000 { + label = "ubi_1"; + reg = <0x6400000 0x4000000>; + }; + + unused@a400000 { + label = "unused"; + reg = <0xa400000 0x5c00000>; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi4_serial { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; +}; + +&flash { + compatible = "jedec,spi-nor"; +}; + +&sata_phy { + status = "disabled"; +}; + +&sata { + status = "disabled"; +}; + +&ss_phy_0 { /* USB3 port 0 SS phy */ + status = "okay"; + + rx_eq = <2>; + tx_deamp_3_5db = <32>; + mpll = <160>; +}; + +&ss_phy_1 { /* USB3 port 1 SS phy */ + status = "okay"; + + rx_eq = <2>; + tx_deamp_3_5db = <32>; + mpll = <160>; +}; + +&pcie0 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie2 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; +}; + +&qcom_pinmux { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinctrl0 { + pcie0_pcie2_perst { + pins = "gpio3"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio53"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio54"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + beeper_pins: beeper_pins { + mux { + pins = "gpio55"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + rpm_pins: rpm_pins { + mux { + pins = "gpio12", "gpio13"; + function = "gsbi4"; + drive-strength = <10>; + bias-disable; + }; + }; + + uart0_pins: uart0_pins { + mux { + pins = "gpio10", "gpio11"; + function = "gsbi4"; + drive-strength = <10>; + bias-disable; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + drive-strength = <10>; + bias-pull-down; + }; + + clk { + pins = "gpio21"; + function = "gsbi5"; + drive-strength = <12>; + bias-pull-down; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&tcsr { + qcom,usb-ctrl-select = ; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts new file mode 100644 index 0000000..1cf5e34 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +#include "qcom-ipq8064-v2.0.dtsi" + +#include + +/ { + model = "Buffalo WXR-2533DHP"; + compatible = "buffalo,wxr-2533dhp", "qcom,ipq8064"; + + memory@42000000 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + led-boot = &power; + led-failsafe = &diag; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + /* use "ubi_rootfs" volume in "ubi" partition as rootfs */ + bootargs = "ubi.block=0,1 root=/dev/ubiblock0_1 rootfstype=squashfs"; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb { + label = "green:usb"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "usbport"; + trigger-sources = <&hub_port0 &hub_port1>; + }; + + guestport { + label = "green:guestport"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + diag: diag { + label = "orange:diag"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + internet_orange { + label = "orange:internet"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + internet_white { + label = "white:internet"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wireless_orange { + label = "orange:wireless"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wireless_white { + label = "white:wireless"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + router_orange { + label = "orange:router"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_HIGH>; + }; + + router_white { + label = "white:router"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + power { + label = "power"; + gpios = <&qcom_pinmux 58 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + eject { + label = "eject"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + guest { + label = "guest"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + ap { + label = "ap"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + router { + label = "router"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + auto { + label = "auto"; + gpios = <&qcom_pinmux 57 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + }; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + cs@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + ubi@0 { + label = "ubi"; + reg = <0x0000000 0x4000000>; + }; + + rootfs_1@4000000 { + label = "rootfs_1"; + reg = <0x4000000 0x4000000>; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x07600000 /* PAD0_MODE */ + 0x00008 0x01000000 /* PAD5_MODE */ + 0x0000c 0x00000080 /* PAD6_MODE */ + 0x00050 0xcc35cc35 /* LED_CTRL0 */ + 0x00054 0xca35ca35 /* LED_CTRL1 */ + 0x00058 0xc935c935 /* LED_CTRL2 */ + 0x0005c 0x03ffff00 /* LED_CTRL3 */ + 0x000e4 0x0006a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x0000007e /* PORT0_STATUS */ + 0x00094 0x0000007e /* PORT6_STATUS */ + >; + }; + + ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_ART_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_ART_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi4_serial { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; +}; + +&gsbi5 { + status = "okay"; + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0 0x10000>; + read-only; + }; + + MIBIB@10000 { + label = "MIBIB"; + reg = <0x10000 0x20000>; + read-only; + }; + + SBL2@30000 { + label = "SBL2"; + reg = <0x30000 0x30000>; + read-only; + }; + + SBL3@60000 { + label = "SBL3"; + reg = <0x60000 0x30000>; + read-only; + }; + + DDRCONFIG@90000 { + label = "DDRCONFIG"; + reg = <0x90000 0x10000>; + read-only; + }; + + SSD@a0000 { + label = "SSD"; + reg = <0xa0000 0x10000>; + read-only; + }; + + TZ@b0000 { + label = "TZ"; + reg = <0xb0000 0x30000>; + read-only; + }; + + RPM@e0000 { + label = "RPM"; + reg = <0xe0000 0x20000>; + read-only; + }; + + APPSBL@100000 { + label = "APPSBL"; + reg = <0x100000 0x70000>; + read-only; + }; + + APPSBLENV@170000 { + label = "APPSBLENV"; + reg = <0x170000 0x10000>; + read-only; + }; + + ART: ART@180000 { + label = "ART"; + reg = <0x180000 0x40000>; + read-only; + }; + + BOOTCONFIG@1c0000 { + label = "BOOTCONFIG"; + reg = <0x1c0000 0x10000>; + read-only; + }; + + APPSBL_1@1d0000 { + label = "APPSBL_1"; + reg = <0x1d0000 0x70000>; + read-only; + }; + }; + }; + }; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&usb3_1 { + status = "okay"; +}; + +&dwc3_0 { + #address-cells = <1>; + #size-cells = <0>; + + hub_port0: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; +}; + +&dwc3_1 { + #address-cells = <1>; + #size-cells = <0>; + + hub_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio55", "gpio56", "gpio57", + "gpio58", "gpio64", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio16", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio26", "gpio53"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart0_pins: uart0_pins { + mux { + pins = "gpio10", "gpio11"; + function = "gsbi4"; + drive-strength = <12>; + bias-disable; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs{ + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + usb_pwr_en_pins: usb_pwr_en_pins { + mux{ + pins = "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + output-high; + }; + }; +}; + +&ART { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_ART_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_ART_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts new file mode 100644 index 0000000..969ca72 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts @@ -0,0 +1,316 @@ +#include "qcom-ipq8065.dtsi" + +#include + +/ { + model = "ZyXEL NBG6817"; + compatible = "zyxel,nbg6817", "qcom,ipq8065", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + sdcc1 = &sdcc1; + + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + bootargs = "rootfstype=squashfs,ext4 rootwait noinitrd fstools_ignore_partname=1"; + append-rootblock = "root=/dev/mmcblk0p"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + internet { + label = "white:internet"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi2g { + label = "amber:wifi2g"; + gpios = <&qcom_pinmux 33 GPIO_ACTIVE_HIGH>; + }; + + /* wifi2g amber from the manual is missing */ + + wifi5g { + label = "amber:wifi5g"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + /* wifi5g amber from the manual is missing */ + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio53", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio9", "gpio26", "gpio33", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + mdio0_pins: mdio0_pins { + clk { + pins = "gpio1"; + input-disable; + }; + }; + + rgmii2_pins: rgmii2_pins { + tx { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32" ; + input-disable; + }; + }; + + spi_pins: spi_pins { + cs { + pins = "gpio20"; + drive-strength = <12>; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio16", "gpio17"; + function = "gpio"; + drive-strength = <12>; + }; + + pwr { + pins = "gpio17"; + bias-pull-down; + output-high; + }; + + ovc { + pins = "gpio16"; + bias-pull-up; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio14", "gpio15"; + function = "gpio"; + drive-strength = <12>; + }; + + pwr { + pins = "gpio14"; + bias-pull-down; + output-high; + }; + + ovc { + pins = "gpio15"; + bias-pull-up; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <51200000>; + reg = <0>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; + }; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + 0x00970 0x1e864443 /* QM_PORT0_CTRL0 */ + 0x00974 0x000001c6 /* QM_PORT0_CTRL1 */ + 0x00978 0x19008643 /* QM_PORT1_CTRL0 */ + 0x0097c 0x000001c6 /* QM_PORT1_CTRL1 */ + 0x00980 0x19008643 /* QM_PORT2_CTRL0 */ + 0x00984 0x000001c6 /* QM_PORT2_CTRL1 */ + 0x00988 0x19008643 /* QM_PORT3_CTRL0 */ + 0x0098c 0x000001c6 /* QM_PORT3_CTRL1 */ + 0x00990 0x19008643 /* QM_PORT4_CTRL0 */ + 0x00994 0x000001c6 /* QM_PORT4_CTRL1 */ + 0x00998 0x1e864443 /* QM_PORT5_CTRL0 */ + 0x0099c 0x000001c6 /* QM_PORT5_CTRL1 */ + 0x009a0 0x1e864443 /* QM_PORT6_CTRL0 */ + 0x009a4 0x000001c6 /* QM_PORT6_CTRL1 */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + qca,ar8327-initvals = < + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x0000c 0x80 /* PAD6_MODE */ + >; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <0>; + qcom,rgmii_delay = <1>; + qcom,phy_mii_type = <0>; + qcom,emulation = <0>; + qcom,irq = <255>; + mdiobus = <&mdio0>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + qcom,phy_mdio_addr = <0>; /* none */ + qcom,poll_required = <0>; /* no polling */ + qcom,rgmii_delay = <0>; + qcom,phy_mii_type = <1>; + qcom,emulation = <0>; + qcom,irq = <258>; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&amba { + sdcc1: sdcc@12400000 { + status = "okay"; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts new file mode 100644 index 0000000..b12e348 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-r7800.dts @@ -0,0 +1,470 @@ +#include "qcom-ipq8065.dtsi" + +#include + +/ { + model = "Netgear Nighthawk X4S R7800"; + compatible = "netgear,r7800", "qcom,ipq8065", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + rsvd@5fe00000 { + reg = <0x5fe00000 0x200000>; + reusable; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power_white; + led-failsafe = &power_amber; + led-running = &power_white; + led-upgrade = &power_amber; + label-mac-device = &gmac2; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + power_white: power_white { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + power_amber: power_amber { + label = "amber:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23", + "gpio24","gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + mdio0_pins: mdio0_pins { + clk { + pins = "gpio1"; + input-disable; + }; + }; + + rgmii2_pins: rgmii2_pins { + tx { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32" ; + input-disable; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + spi6_pins: spi6_pins { + mux { + pins = "gpio55", "gpio56", "gpio58"; + function = "gsbi6"; + bias-pull-down; + }; + + mosi { + pins = "gpio55"; + drive-strength = <12>; + }; + + miso { + pins = "gpio56"; + drive-strength = <14>; + }; + + cs { + pins = "gpio57"; + drive-strength = <12>; + bias-pull-up; + }; + + clk { + pins = "gpio58"; + drive-strength = <12>; + }; + + reset { + pins = "gpio33"; + drive-strength = <10>; + bias-pull-down; + output-high; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio15"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio16", "gpio68"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot_pages_size = <0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + }; + + artbak: art@1340000 { + label = "artbak"; + reg = <0x1340000 0x0140000>; + read-only; + }; + + kernel@1480000 { + label = "kernel"; + reg = <0x1480000 0x0400000>; + }; + + ubi@1880000 { + label = "ubi"; + reg = <0x1880000 0x6080000>; + }; + + reserve@7900000 { + label = "reserve"; + reg = <0x7900000 0x0700000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + 0x00970 0x1e864443 /* QM_PORT0_CTRL0 */ + 0x00974 0x000001c6 /* QM_PORT0_CTRL1 */ + 0x00978 0x19008643 /* QM_PORT1_CTRL0 */ + 0x0097c 0x000001c6 /* QM_PORT1_CTRL1 */ + 0x00980 0x19008643 /* QM_PORT2_CTRL0 */ + 0x00984 0x000001c6 /* QM_PORT2_CTRL1 */ + 0x00988 0x19008643 /* QM_PORT3_CTRL0 */ + 0x0098c 0x000001c6 /* QM_PORT3_CTRL1 */ + 0x00990 0x19008643 /* QM_PORT4_CTRL0 */ + 0x00994 0x000001c6 /* QM_PORT4_CTRL1 */ + 0x00998 0x1e864443 /* QM_PORT5_CTRL0 */ + 0x0099c 0x000001c6 /* QM_PORT5_CTRL1 */ + 0x009a0 0x1e864443 /* QM_PORT6_CTRL0 */ + 0x009a4 0x000001c6 /* QM_PORT6_CTRL1 */ + >; + qca,ar8327-vlans = < + 0x1 0x5e /* VLAN1 Ports 1/2/3/4/6 */ + 0x2 0x21 /* VLAN2 Ports 0/5 */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + qca,ar8327-initvals = < + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x0000c 0x80 /* PAD6_MODE */ + >; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <0>; + qcom,rgmii_delay = <1>; + qcom,phy_mii_type = <0>; + qcom,emulation = <0>; + qcom,irq = <255>; + mdiobus = <&mdio0>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + qcom,phy_mdio_addr = <0>; /* none */ + qcom,poll_required = <0>; /* no polling */ + qcom,rgmii_delay = <0>; + qcom,phy_mii_type = <1>; + qcom,emulation = <0>; + qcom,irq = <258>; + mdiobus = <&mdio0>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0046"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <(1)>; + }; + }; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0046"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <(2)>; + }; + }; +}; + +&art { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts new file mode 100644 index 0000000..54356e2 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qcom-ipq8065.dtsi" +#include + +/ { + model = "Askey RT4230W REV6"; + compatible = "askey,rt4230w-rev6", "qcom,ipq8065", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x3e000000>; + device_type = "memory"; + }; + + aliases { + led-boot = &ledctrl3; + led-failsafe = &ledctrl1; + led-running = &ledctrl2; + led-upgrade = &ledctrl3; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + ledctrl1: ledctrl1 { + label = "ledctrl1"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + ledctrl2: ledctrl2 { + label = "ledctrl2"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + ledctrl3: ledctrl3 { + label = "ledctrl3"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio54", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio22", "gpio23", "gpio24"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + rgmii2_pins: rgmii2_pins { + mux { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", + "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62"; + function = "rgmii2"; + drive-strength = <8>; + bias-disable; + }; + + tx { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32"; + input-disable; + }; + }; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "0:SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + partition@40000 { + label = "0:MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + partition@180000 { + label = "0:SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + partition@2c0000 { + label = "0:SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + partition@540000 { + label = "0:DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + partition@660000 { + label = "0:SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + partition@780000 { + label = "0:TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + partition@a00000 { + label = "0:RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + partition@c80000 { + label = "0:APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + partition@1180000 { + label = "0:APPSBLENV"; + reg = <0x1180000 0x0080000>; + }; + ART: partition@1200000 { + label = "0:ART"; + reg = <0x1200000 0x0140000>; + read-only; + }; + partition@1340000 { + label = "0:BOOTCONFIG"; + reg = <0x1340000 0x0060000>; + read-only; + }; + partition@13a0000 { + label = "0:SBL2_1"; + reg = <0x13a0000 0x0140000>; + read-only; + }; + partition@14e0000 { + label = "0:SBL3_1"; + reg = <0x14e0000 0x0280000>; + read-only; + }; + partition@1760000 { + label = "0:DDRCONFIG_1"; + reg = <0x1760000 0x0120000>; + read-only; + }; + partition@1880000 { + label = "0:SSD_1"; + reg = <0x1880000 0x0120000>; + read-only; + }; + partition@19a0000 { + label = "0:TZ_1"; + reg = <0x19a0000 0x0280000>; + read-only; + }; + partition@1c20000 { + label = "0:RPM_1"; + reg = <0x1c20000 0x0280000>; + read-only; + }; + partition@1ea0000 { + label = "0:BOOTCONFIG1"; + reg = <0x1ea0000 0x0060000>; + read-only; + }; + partition@1f00000 { + label = "0:APPSBL_1"; + reg = <0x1f00000 0x0500000>; + read-only; + }; + partition@2400000 { + label = "ubi"; + reg = <0x2400000 0x1a000000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0x0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + 0x00050 0xcf02cf02 /* LED_CTRL_0 */ + 0x00054 0xc832c832 /* LED_CTRL_1 */ + >; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + + nvmem-cells = <&macaddr_ART_0>; + nvmem-cell-names = "mac-address"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <1>; + + nvmem-cells = <&macaddr_ART_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + clocks = <&gcc USB30_1_MASTER_CLK>; +}; + +&usb3_1 { + status = "okay"; + clocks = <&gcc USB30_0_MASTER_CLK>; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_HIGH>; + /delete-property/ perst-gpios; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_HIGH>; + /delete-property/ perst-gpios; + force_gen1 = <1>; +}; + +&ART { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_ART_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_ART_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi new file mode 100644 index 0000000..a031268 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8065.dtsi @@ -0,0 +1,164 @@ +#include "qcom-ipq8064.dtsi" + +/ { + model = "Qualcomm IPQ8065"; + compatible = "qcom,ipq8065", "qcom,ipq8064"; + + aliases { + serial0 = &gsbi4_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; +}; + +&gsbi4 { + qcom,mode = ; + status = "okay"; + + serial@16340000 { + status = "okay"; + }; + /* + * The i2c device on gsbi4 should not be enabled. + * On ipq806x designs gsbi4 i2c is meant for exclusive + * RPM usage. Turning this on in kernel manifests as + * i2c failure for the RPM. + */ +}; + +&pcie0 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&pcie1 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&pcie2 { + compatible = "qcom,pcie-ipq8064-v2"; +}; + +&sata { + ports-implemented = <0x1>; +}; + +&smb208_s2a { + regulator-min-microvolt = <775000>; + regulator-max-microvolt = <1275000>; +}; + +&smb208_s2b { + regulator-min-microvolt = <775000>; + regulator-max-microvolt = <1275000>; +}; + +&ss_phy_0 { + qcom,rx-eq = <2>; + qcom,tx-deamp_3_5db = <32>; + qcom,mpll = <5>; +}; + +&ss_phy_1 { + qcom,rx-eq = <2>; + qcom,tx-deamp_3_5db = <32>; + qcom,mpll = <5>; +}; + +&opp_table_l2 { + /delete-node/opp-1200000000; + + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-microvolt = <1150000>; + clock-latency-ns = <100000>; + opp-level = <2>; + }; +}; + +&opp_table0 { + /* + * On ipq8065 1.2 ghz freq is not present + * Remove it to make cpufreq work and not + * complain for missing definition + */ + + /delete-node/opp-1200000000; + + opp-384000000 { + opp-microvolt-speed0-pvs0-v0 = <926250 975000 1023750>; + opp-microvolt-speed0-pvs1-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs2-v0 = <878750 925000 971250>; + opp-microvolt-speed0-pvs3-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs4-v0 = <831250 875000 918750>; + opp-microvolt-speed0-pvs5-v0 = <783750 825000 866250>; + opp-microvolt-speed0-pvs6-v0 = <736250 775000 813750>; + }; + + opp-600000000 { + opp-microvolt-speed0-pvs0-v0 = <950000 1000000 1050000>; + opp-microvolt-speed0-pvs1-v0 = <926250 975000 1023750>; + opp-microvolt-speed0-pvs2-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs3-v0 = <878750 925000 971250>; + opp-microvolt-speed0-pvs4-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs5-v0 = <807500 850000 892500>; + opp-microvolt-speed0-pvs6-v0 = <760000 800000 840000>; + }; + + opp-800000000 { + opp-microvolt-speed0-pvs0-v0 = <997500 1050000 1102500>; + opp-microvolt-speed0-pvs1-v0 = <973750 1025000 1076250>; + opp-microvolt-speed0-pvs2-v0 = <950000 1000000 1050000>; + opp-microvolt-speed0-pvs3-v0 = <926250 975000 1023750>; + opp-microvolt-speed0-pvs4-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs5-v0 = <855000 900000 945000>; + opp-microvolt-speed0-pvs6-v0 = <807500 850000 892500>; + }; + + opp-1000000000 { + opp-microvolt-speed0-pvs0-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs1-v0 = <1021250 1075000 1128750>; + opp-microvolt-speed0-pvs2-v0 = <997500 1050000 1102500>; + opp-microvolt-speed0-pvs3-v0 = <973750 1025000 1076250>; + opp-microvolt-speed0-pvs4-v0 = <950000 1000000 1050000>; + opp-microvolt-speed0-pvs5-v0 = <902500 950000 997500>; + opp-microvolt-speed0-pvs6-v0 = <855000 900000 945000>; + }; + + opp-1400000000 { + opp-microvolt-speed0-pvs0-v0 = <1116250 1175000 1233750>; + opp-microvolt-speed0-pvs1-v0 = <1092500 1150000 1207500>; + opp-microvolt-speed0-pvs2-v0 = <1068750 1125000 1181250>; + opp-microvolt-speed0-pvs3-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs4-v0 = <1021250 1075000 1128750>; + opp-microvolt-speed0-pvs5-v0 = <973750 1025000 1076250>; + opp-microvolt-speed0-pvs6-v0 = <926250 975000 1023750>; + opp-level = <1>; + }; + + opp-1725000000 { + opp-hz = /bits/ 64 <1725000000>; + opp-microvolt-speed0-pvs0-v0 = <1199375 1262500 1325625>; + opp-microvolt-speed0-pvs1-v0 = <1163750 1225000 1286250>; + opp-microvolt-speed0-pvs2-v0 = <1140000 1200000 1260000>; + opp-microvolt-speed0-pvs3-v0 = <1116250 1175000 1233750>; + opp-microvolt-speed0-pvs4-v0 = <1092500 1150000 1207500>; + opp-microvolt-speed0-pvs5-v0 = <1045000 1100000 1155000>; + opp-microvolt-speed0-pvs6-v0 = <997500 1050000 1102500>; + opp-supported-hw = <0x1>; + clock-latency-ns = <100000>; + opp-level = <2>; + }; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts new file mode 100644 index 0000000..43bed45 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts @@ -0,0 +1,341 @@ +#include "qcom-ipq8064-v2.0.dtsi" + +#include +#include + +/ { + model = "Edgecore ECW5410"; + compatible = "edgecore,ecw5410", "qcom,ipq8064"; + + reserved-memory { + nss@40000000 { + reg = <0x40000000 0x1000000>; + no-map; + }; + + smem: smem@41000000 { + reg = <0x41000000 0x200000>; + no-map; + }; + + wifi_dump@44000000 { + reg = <0x44000000 0x600000>; + no-map; + }; + }; + + cpus { + idle-states { + CPU_SPC: spc { + status = "disabled"; + }; + }; + }; + + aliases { + serial1 = &gsbi1_serial; + mdio-gpio0 = &mdio0; + ethernet0 = &gmac3; + ethernet1 = &gmac2; + + led-boot = &led_power_green; + led-failsafe = &led_power_red; + led-running = &led_power_green; + led-upgrade = &led_power_green; + }; + + chosen { + bootargs-append = " console=ttyMSM0,115200n8 root=/dev/ubiblock0_1"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power_green: power_green { + label = "green:power"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "green:wlan2g"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_LOW>; + }; + + wlan2g_yellow { + label = "yellow:wlan2g"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; + }; + + wlan5g_green { + label = "green:wlan5g"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + led_power_red: power_red { + label = "red:power"; + gpios = <&qcom_pinmux 28 GPIO_ACTIVE_LOW>; + }; + + wlan5g_yellow { + label = "yellow:wlan5g"; + gpios = <&qcom_pinmux 59 GPIO_ACTIVE_LOW>; + }; + }; +}; + + +&qcom_pinmux { + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + drive-strength = <10>; + bias-pull-down; + }; + + clk { + pins = "gpio21"; + function = "gsbi5"; + drive-strength = <12>; + bias-pull-down; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio16", "gpio23", "gpio24", "gpio26", + "gpio28", "gpio59"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio25"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart1_pins: uart1_pins { + mux { + pins = "gpio51", "gpio52", "gpio53", "gpio54"; + function = "gsbi1"; + drive-strength = <12>; + bias-none; + }; + }; +}; + +&gsbi1 { + qcom,mode = ; + status = "okay"; + + serial@12450000 { + status = "okay"; + + pinctrl-0 = <&uart1_pins>; + pinctrl-names = "default"; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; + }; +}; + +&hs_phy_0 { /* USB3 port 0 HS phy */ + status = "okay"; +}; + +&hs_phy_1 { /* USB3 port 1 HS phy */ + status = "okay"; +}; + +&ss_phy_0 { /* USB3 port 0 SS phy */ + status = "okay"; +}; + +&ss_phy_1 { /* USB3 port 1 SS phy */ + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Edgecore-ECW5410-L"; + }; + }; +}; + +&pcie2 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Edgecore-ECW5410-L"; + }; + }; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + compatible = "qcom,nandcs"; + + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + rootfs1@0 { + label = "rootfs1"; + reg = <0x0000000 0x4000000>; + }; + + rootfs2@4000000 { + label = "rootfs2"; + reg = <0x4000000 0x4000000>; + }; + }; + }; +}; + +&soc { + mdio1: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; +}; + +&gmac2 { + status = "okay"; + + qcom,id = <2>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy1>; +}; + +&gmac3 { + status = "okay"; + + qcom,id = <3>; + mdiobus = <&mdio1>; + + phy-mode = "sgmii"; + phy-handle = <&phy0>; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ssw2ac2600.dts b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ssw2ac2600.dts new file mode 100644 index 0000000..b5608c2 --- /dev/null +++ b/ipq806x/files/arch/arm/boot/dts/qcom-ipq8068-ssw2ac2600.dts @@ -0,0 +1,341 @@ +#include "qcom-ipq8064-v2.0.dtsi" + +#include +#include + +/ { + model = "Edgecore SSW2AC2600"; + compatible = "edgecore,ssw2ac2600", "qcom,ipq8064"; + + reserved-memory { + nss@40000000 { + reg = <0x40000000 0x1000000>; + no-map; + }; + + smem: smem@41000000 { + reg = <0x41000000 0x200000>; + no-map; + }; + + wifi_dump@44000000 { + reg = <0x44000000 0x600000>; + no-map; + }; + }; + + cpus { + idle-states { + CPU_SPC: spc { + status = "disabled"; + }; + }; + }; + + aliases { + serial1 = &gsbi1_serial; + mdio-gpio0 = &mdio0; + ethernet0 = &gmac3; + ethernet1 = &gmac2; + + led-boot = &led_power_green; + led-failsafe = &led_power_red; + led-running = &led_power_green; + led-upgrade = &led_power_green; + }; + + chosen { + bootargs-append = " console=ttyMSM0,115200n8 root=/dev/ubiblock0_1"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power_green: power_green { + label = "green:power"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "green:wlan2g"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_LOW>; + }; + + wlan2g_yellow { + label = "yellow:wlan2g"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; + }; + + wlan5g_green { + label = "green:wlan5g"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + led_power_red: power_red { + label = "red:power"; + gpios = <&qcom_pinmux 28 GPIO_ACTIVE_LOW>; + }; + + wlan5g_yellow { + label = "yellow:wlan5g"; + gpios = <&qcom_pinmux 59 GPIO_ACTIVE_LOW>; + }; + }; +}; + + +&qcom_pinmux { + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + drive-strength = <10>; + bias-pull-down; + }; + + clk { + pins = "gpio21"; + function = "gsbi5"; + drive-strength = <12>; + bias-pull-down; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio16", "gpio23", "gpio24", "gpio26", + "gpio28", "gpio59"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio25"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart1_pins: uart1_pins { + mux { + pins = "gpio51", "gpio52", "gpio53", "gpio54"; + function = "gsbi1"; + drive-strength = <12>; + bias-none; + }; + }; +}; + +&gsbi1 { + qcom,mode = ; + status = "okay"; + + serial@12450000 { + status = "okay"; + + pinctrl-0 = <&uart1_pins>; + pinctrl-names = "default"; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; + }; +}; + +&hs_phy_0 { /* USB3 port 0 HS phy */ + status = "okay"; +}; + +&hs_phy_1 { /* USB3 port 1 HS phy */ + status = "okay"; +}; + +&ss_phy_0 { /* USB3 port 0 SS phy */ + status = "okay"; +}; + +&ss_phy_1 { /* USB3 port 1 SS phy */ + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Edgecore-ECW5410-L"; + }; + }; +}; + +&pcie2 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Edgecore-ECW5410-L"; + }; + }; +}; + +&nand_controller { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + compatible = "qcom,nandcs"; + + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + rootfs1@0 { + label = "rootfs1"; + reg = <0x0000000 0x4000000>; + }; + + rootfs2@4000000 { + label = "rootfs2"; + reg = <0x4000000 0x4000000>; + }; + }; + }; +}; + +&soc { + mdio1: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; +}; + +&gmac2 { + status = "okay"; + + qcom,id = <2>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy1>; +}; + +&gmac3 { + status = "okay"; + + qcom,id = <3>; + mdiobus = <&mdio1>; + + phy-mode = "sgmii"; + phy-handle = <&phy0>; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/ipq806x/generic/target.mk b/ipq806x/generic/target.mk new file mode 100644 index 0000000..f5cb1fb --- /dev/null +++ b/ipq806x/generic/target.mk @@ -0,0 +1 @@ +BOARDNAME:=Generic diff --git a/ipq806x/hack-5.4/204-module_strip.patch b/ipq806x/hack-5.4/204-module_strip.patch new file mode 100644 index 0000000..c642073 --- /dev/null +++ b/ipq806x/hack-5.4/204-module_strip.patch @@ -0,0 +1,204 @@ +From a779a482fb9b9f8fcdf8b2519c789b4b9bb5dd05 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 16:56:48 +0200 +Subject: build: add a hack for removing non-essential module info + +Signed-off-by: Felix Fietkau +--- + include/linux/module.h | 13 ++++++++----- + include/linux/moduleparam.h | 15 ++++++++++++--- + init/Kconfig | 7 +++++++ + kernel/module.c | 5 ++++- + scripts/mod/modpost.c | 12 ++++++++++++ + 5 files changed, 43 insertions(+), 9 deletions(-) + +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -157,6 +157,7 @@ extern void cleanup_module(void); + + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info) + + /* For userspace: you can also call me... */ + #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) +@@ -216,12 +217,12 @@ extern void cleanup_module(void); + * Author(s), use "Name " or just "Name", for multiple + * authors use multiple MODULE_AUTHOR() statements/lines. + */ +-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) ++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author) + + /* What your module does. */ +-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) ++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description) + +-#ifdef MODULE ++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED) + /* Creates an alias so file2alias.c can find device table. */ + #define MODULE_DEVICE_TABLE(type, name) \ + extern typeof(name) __mod_##type##__##name##_device_table \ +@@ -248,7 +249,9 @@ extern typeof(name) __mod_##type##__##na + */ + + #if defined(MODULE) || !defined(CONFIG_SYSFS) +-#define MODULE_VERSION(_version) MODULE_INFO(version, _version) ++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version) ++#elif defined(CONFIG_MODULE_STRIPPED) ++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version) + #else + #define MODULE_VERSION(_version) \ + MODULE_INFO(version, _version); \ +@@ -271,7 +274,7 @@ extern typeof(name) __mod_##type##__##na + /* Optional firmware file (or files) needed by the module + * format is simply firmware file name. Multiple firmware + * files require multiple MODULE_FIRMWARE() specifiers */ +-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) ++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) + + #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) + +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -20,10 +20,24 @@ + /* Chosen so that structs with an unsigned long line up. */ + #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) + ++/* This struct is here for syntactic coherency, it is not used */ ++#define __MODULE_INFO_DISABLED(name) \ ++ struct __UNIQUE_ID(name) {} ++ ++#ifdef CONFIG_MODULE_STRIPPED ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name) ++#else ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info) ++#endif ++ ++#ifdef MODULE + #define __MODULE_INFO(tag, name, info) \ + static const char __UNIQUE_ID(name)[] \ + __used __attribute__((section(".modinfo"), unused, aligned(1))) \ + = __MODULE_INFO_PREFIX __stringify(tag) "=" info ++#else ++#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name) ++#endif + + #define __MODULE_PARM_TYPE(name, _type) \ + __MODULE_INFO(parmtype, name##type, #name ":" _type) +@@ -31,7 +45,7 @@ static const char __UNIQUE_ID(name)[] + /* One for each parameter, describing how to use it. Some files do + multiple of these per line, so can't just use MODULE_INFO. */ + #define MODULE_PARM_DESC(_parm, desc) \ +- __MODULE_INFO(parm, _parm, #_parm ":" desc) ++ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc) + + struct kernel_param; + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -2198,6 +2198,13 @@ config TRIM_UNUSED_KSYMS + + If unsure, or if you need to build out-of-tree modules, say N. + ++config MODULE_STRIPPED ++ bool "Reduce module size" ++ depends on MODULES ++ help ++ Remove module parameter descriptions, author info, version, aliases, ++ device tables, etc. ++ + endif # MODULES + + config MODULES_TREE_LOOKUP +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -3256,9 +3256,11 @@ static int setup_load_info(struct load_i + + static int check_modinfo(struct module *mod, struct load_info *info, int flags) + { +- const char *modmagic = get_modinfo(info, "vermagic"); + int err; + ++#ifndef CONFIG_MODULE_STRIPPED ++ const char *modmagic = get_modinfo(info, "vermagic"); ++ + if (flags & MODULE_INIT_IGNORE_VERMAGIC) + modmagic = NULL; + +@@ -3279,6 +3281,7 @@ static int check_modinfo(struct module * + mod->name); + add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK); + } ++#endif + + check_modinfo_retpoline(mod, info); + +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -2056,7 +2056,9 @@ static void read_symbols(const char *mod + symname = remove_dot(info.strtab + sym->st_name); + + handle_modversions(mod, &info, sym, symname); ++#ifndef CONFIG_MODULE_STRIPPED + handle_moddevtable(mod, &info, sym, symname); ++#endif + } + + /* Apply symbol namespaces from __kstrtabns_ entries. */ +@@ -2270,8 +2272,10 @@ static void add_header(struct buffer *b, + buf_printf(b, "\n"); + buf_printf(b, "BUILD_SALT;\n"); + buf_printf(b, "\n"); ++#ifndef CONFIG_MODULE_STRIPPED + buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); + buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); ++#endif + buf_printf(b, "\n"); + buf_printf(b, "__visible struct module __this_module\n"); + buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n"); +@@ -2288,8 +2292,10 @@ static void add_header(struct buffer *b, + + static void add_intree_flag(struct buffer *b, int is_intree) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (is_intree) + buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); ++#endif + } + + /* Cannot check for assembler */ +@@ -2302,8 +2308,10 @@ static void add_retpoline(struct buffer + + static void add_staging_flag(struct buffer *b, const char *name) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (strstarts(name, "drivers/staging")) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); ++#endif + } + + /** +@@ -2387,11 +2395,13 @@ static void add_depends(struct buffer *b + + static void add_srcversion(struct buffer *b, struct module *mod) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (mod->srcversion[0]) { + buf_printf(b, "\n"); + buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", + mod->srcversion); + } ++#endif + } + + static void write_if_changed(struct buffer *b, const char *fname) +@@ -2661,7 +2671,9 @@ int main(int argc, char **argv) + add_staging_flag(&buf, mod->name); + err |= add_versions(&buf, mod); + add_depends(&buf, mod); ++#ifndef CONFIG_MODULE_STRIPPED + add_moddevtable(&buf, mod); ++#endif + add_srcversion(&buf, mod); + + sprintf(fname, "%s.mod.c", mod->name); diff --git a/ipq806x/hack-5.4/210-darwin_scripts_include.patch b/ipq806x/hack-5.4/210-darwin_scripts_include.patch new file mode 100644 index 0000000..be6adc0 --- /dev/null +++ b/ipq806x/hack-5.4/210-darwin_scripts_include.patch @@ -0,0 +1,3053 @@ +From db7c30dcd9a0391bf13b62c9f91e144d762ef43a Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Fri, 7 Jul 2017 17:00:49 +0200 +Subject: Add an OSX specific patch to make the kernel be compiled + +lede-commit: 3fc2a24f0422b2f55f9ed43f116db3111f700526 +Signed-off-by: Florian Fainelli +--- + scripts/kconfig/Makefile | 3 + + scripts/mod/elf.h | 3007 ++++++++++++++++++++++++++++++++++++++++++++ + scripts/mod/mk_elfconfig.c | 4 + + scripts/mod/modpost.h | 4 + + 4 files changed, 3018 insertions(+) + create mode 100644 scripts/mod/elf.h + +--- /dev/null ++++ b/scripts/mod/elf.h +@@ -0,0 +1,3007 @@ ++/* This file defines standard ELF types, structures, and macros. ++ Copyright (C) 1995-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _ELF_H ++#define _ELF_H 1 ++ ++/* Standard ELF types. */ ++ ++#include ++ ++/* Type for a 16-bit quantity. */ ++typedef uint16_t Elf32_Half; ++typedef uint16_t Elf64_Half; ++ ++/* Types for signed and unsigned 32-bit quantities. */ ++typedef uint32_t Elf32_Word; ++typedef int32_t Elf32_Sword; ++typedef uint32_t Elf64_Word; ++typedef int32_t Elf64_Sword; ++ ++/* Types for signed and unsigned 64-bit quantities. */ ++typedef uint64_t Elf32_Xword; ++typedef int64_t Elf32_Sxword; ++typedef uint64_t Elf64_Xword; ++typedef int64_t Elf64_Sxword; ++ ++/* Type of addresses. */ ++typedef uint32_t Elf32_Addr; ++typedef uint64_t Elf64_Addr; ++ ++/* Type of file offsets. */ ++typedef uint32_t Elf32_Off; ++typedef uint64_t Elf64_Off; ++ ++/* Type for section indices, which are 16-bit quantities. */ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++ ++/* Type for version symbol information. */ ++typedef Elf32_Half Elf32_Versym; ++typedef Elf64_Half Elf64_Versym; ++ ++ ++/* The ELF file header. This appears at the start of every ELF file. */ ++ ++#define EI_NIDENT (16) ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf32_Half e_type; /* Object file type */ ++ Elf32_Half e_machine; /* Architecture */ ++ Elf32_Word e_version; /* Object file version */ ++ Elf32_Addr e_entry; /* Entry point virtual address */ ++ Elf32_Off e_phoff; /* Program header table file offset */ ++ Elf32_Off e_shoff; /* Section header table file offset */ ++ Elf32_Word e_flags; /* Processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size in bytes */ ++ Elf32_Half e_phentsize; /* Program header table entry size */ ++ Elf32_Half e_phnum; /* Program header table entry count */ ++ Elf32_Half e_shentsize; /* Section header table entry size */ ++ Elf32_Half e_shnum; /* Section header table entry count */ ++ Elf32_Half e_shstrndx; /* Section header string table index */ ++} Elf32_Ehdr; ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf64_Half e_type; /* Object file type */ ++ Elf64_Half e_machine; /* Architecture */ ++ Elf64_Word e_version; /* Object file version */ ++ Elf64_Addr e_entry; /* Entry point virtual address */ ++ Elf64_Off e_phoff; /* Program header table file offset */ ++ Elf64_Off e_shoff; /* Section header table file offset */ ++ Elf64_Word e_flags; /* Processor-specific flags */ ++ Elf64_Half e_ehsize; /* ELF header size in bytes */ ++ Elf64_Half e_phentsize; /* Program header table entry size */ ++ Elf64_Half e_phnum; /* Program header table entry count */ ++ Elf64_Half e_shentsize; /* Section header table entry size */ ++ Elf64_Half e_shnum; /* Section header table entry count */ ++ Elf64_Half e_shstrndx; /* Section header string table index */ ++} Elf64_Ehdr; ++ ++/* Fields in the e_ident array. The EI_* macros are indices into the ++ array. The macros under each EI_* macro are the values the byte ++ may have. */ ++ ++#define EI_MAG0 0 /* File identification byte 0 index */ ++#define ELFMAG0 0x7f /* Magic number byte 0 */ ++ ++#define EI_MAG1 1 /* File identification byte 1 index */ ++#define ELFMAG1 'E' /* Magic number byte 1 */ ++ ++#define EI_MAG2 2 /* File identification byte 2 index */ ++#define ELFMAG2 'L' /* Magic number byte 2 */ ++ ++#define EI_MAG3 3 /* File identification byte 3 index */ ++#define ELFMAG3 'F' /* Magic number byte 3 */ ++ ++/* Conglomeration of the identification bytes, for easy testing as a word. */ ++#define ELFMAG "\177ELF" ++#define SELFMAG 4 ++ ++#define EI_CLASS 4 /* File class byte index */ ++#define ELFCLASSNONE 0 /* Invalid class */ ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++#define ELFCLASSNUM 3 ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATANONE 0 /* Invalid data encoding */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ ++#define ELFDATANUM 3 ++ ++#define EI_VERSION 6 /* File version byte index */ ++ /* Value must be EV_CURRENT */ ++ ++#define EI_OSABI 7 /* OS ABI identification */ ++#define ELFOSABI_NONE 0 /* UNIX System V ABI */ ++#define ELFOSABI_SYSV 0 /* Alias. */ ++#define ELFOSABI_HPUX 1 /* HP-UX */ ++#define ELFOSABI_NETBSD 2 /* NetBSD. */ ++#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ ++#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ ++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ ++#define ELFOSABI_AIX 7 /* IBM AIX. */ ++#define ELFOSABI_IRIX 8 /* SGI Irix. */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ ++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ ++#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++#define EI_ABIVERSION 8 /* ABI version */ ++ ++#define EI_PAD 9 /* Byte index of padding bytes */ ++ ++/* Legal values for e_type (object file type). */ ++ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* Relocatable file */ ++#define ET_EXEC 2 /* Executable file */ ++#define ET_DYN 3 /* Shared object file */ ++#define ET_CORE 4 /* Core file */ ++#define ET_NUM 5 /* Number of defined types */ ++#define ET_LOOS 0xfe00 /* OS-specific range start */ ++#define ET_HIOS 0xfeff /* OS-specific range end */ ++#define ET_LOPROC 0xff00 /* Processor-specific range start */ ++#define ET_HIPROC 0xffff /* Processor-specific range end */ ++ ++/* Legal values for e_machine (architecture). */ ++ ++#define EM_NONE 0 /* No machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SUN SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola m68k family */ ++#define EM_88K 5 /* Motorola m88k family */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 big-endian */ ++#define EM_S370 9 /* IBM System/370 */ ++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ ++ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_VPP500 17 /* Fujitsu VPP500 */ ++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ ++#define EM_960 19 /* Intel 80960 */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_S390 22 /* IBM S390 */ ++ ++#define EM_V800 36 /* NEC V800 series */ ++#define EM_FR20 37 /* Fujitsu FR20 */ ++#define EM_RH32 38 /* TRW RH-32 */ ++#define EM_RCE 39 /* Motorola RCE */ ++#define EM_ARM 40 /* ARM */ ++#define EM_FAKE_ALPHA 41 /* Digital Alpha */ ++#define EM_SH 42 /* Hitachi SH */ ++#define EM_SPARCV9 43 /* SPARC v9 64-bit */ ++#define EM_TRICORE 44 /* Siemens Tricore */ ++#define EM_ARC 45 /* Argonaut RISC Core */ ++#define EM_H8_300 46 /* Hitachi H8/300 */ ++#define EM_H8_300H 47 /* Hitachi H8/300H */ ++#define EM_H8S 48 /* Hitachi H8S */ ++#define EM_H8_500 49 /* Hitachi H8/500 */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_MIPS_X 51 /* Stanford MIPS-X */ ++#define EM_COLDFIRE 52 /* Motorola Coldfire */ ++#define EM_68HC12 53 /* Motorola M68HC12 */ ++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ ++#define EM_PCP 55 /* Siemens PCP */ ++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ ++#define EM_NDR1 57 /* Denso NDR1 microprocessor */ ++#define EM_STARCORE 58 /* Motorola Start*Core processor */ ++#define EM_ME16 59 /* Toyota ME16 processor */ ++#define EM_ST100 60 /* STMicroelectronic ST100 processor */ ++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_PDSP 63 /* Sony DSP Processor */ ++ ++#define EM_FX66 66 /* Siemens FX66 microcontroller */ ++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ ++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ ++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ ++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ ++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ ++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ ++#define EM_SVX 73 /* Silicon Graphics SVx */ ++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ ++#define EM_VAX 75 /* Digital VAX */ ++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ ++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ ++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ ++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ ++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ ++#define EM_HUANY 81 /* Harvard University machine-independent object files */ ++#define EM_PRISM 82 /* SiTera Prism */ ++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ ++#define EM_FR30 84 /* Fujitsu FR30 */ ++#define EM_D10V 85 /* Mitsubishi D10V */ ++#define EM_D30V 86 /* Mitsubishi D30V */ ++#define EM_V850 87 /* NEC v850 */ ++#define EM_M32R 88 /* Mitsubishi M32R */ ++#define EM_MN10300 89 /* Matsushita MN10300 */ ++#define EM_MN10200 90 /* Matsushita MN10200 */ ++#define EM_PJ 91 /* picoJava */ ++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ ++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ ++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ ++#define EM_TILEPRO 188 /* Tilera TILEPro */ ++#define EM_TILEGX 191 /* Tilera TILE-Gx */ ++#define EM_NUM 192 ++ ++/* If it is necessary to assign new unofficial EM_* values, please ++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the ++ chances of collision with official or non-GNU unofficial values. */ ++ ++#define EM_ALPHA 0x9026 ++ ++/* Legal values for e_version (version). */ ++ ++#define EV_NONE 0 /* Invalid ELF version */ ++#define EV_CURRENT 1 /* Current version */ ++#define EV_NUM 2 ++ ++/* Section header. */ ++ ++typedef struct ++{ ++ Elf32_Word sh_name; /* Section name (string tbl index) */ ++ Elf32_Word sh_type; /* Section type */ ++ Elf32_Word sh_flags; /* Section flags */ ++ Elf32_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf32_Off sh_offset; /* Section file offset */ ++ Elf32_Word sh_size; /* Section size in bytes */ ++ Elf32_Word sh_link; /* Link to another section */ ++ Elf32_Word sh_info; /* Additional section information */ ++ Elf32_Word sh_addralign; /* Section alignment */ ++ Elf32_Word sh_entsize; /* Entry size if section holds table */ ++} Elf32_Shdr; ++ ++typedef struct ++{ ++ Elf64_Word sh_name; /* Section name (string tbl index) */ ++ Elf64_Word sh_type; /* Section type */ ++ Elf64_Xword sh_flags; /* Section flags */ ++ Elf64_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf64_Off sh_offset; /* Section file offset */ ++ Elf64_Xword sh_size; /* Section size in bytes */ ++ Elf64_Word sh_link; /* Link to another section */ ++ Elf64_Word sh_info; /* Additional section information */ ++ Elf64_Xword sh_addralign; /* Section alignment */ ++ Elf64_Xword sh_entsize; /* Entry size if section holds table */ ++} Elf64_Shdr; ++ ++/* Special section indices. */ ++ ++#define SHN_UNDEF 0 /* Undefined section */ ++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ ++#define SHN_LOPROC 0xff00 /* Start of processor-specific */ ++#define SHN_BEFORE 0xff00 /* Order section before all others ++ (Solaris). */ ++#define SHN_AFTER 0xff01 /* Order section after all others ++ (Solaris). */ ++#define SHN_HIPROC 0xff1f /* End of processor-specific */ ++#define SHN_LOOS 0xff20 /* Start of OS-specific */ ++#define SHN_HIOS 0xff3f /* End of OS-specific */ ++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ ++#define SHN_COMMON 0xfff2 /* Associated symbol is common */ ++#define SHN_XINDEX 0xffff /* Index is in extra table. */ ++#define SHN_HIRESERVE 0xffff /* End of reserved indices */ ++ ++/* Legal values for sh_type (section type). */ ++ ++#define SHT_NULL 0 /* Section header table entry unused */ ++#define SHT_PROGBITS 1 /* Program data */ ++#define SHT_SYMTAB 2 /* Symbol table */ ++#define SHT_STRTAB 3 /* String table */ ++#define SHT_RELA 4 /* Relocation entries with addends */ ++#define SHT_HASH 5 /* Symbol hash table */ ++#define SHT_DYNAMIC 6 /* Dynamic linking information */ ++#define SHT_NOTE 7 /* Notes */ ++#define SHT_NOBITS 8 /* Program space with no data (bss) */ ++#define SHT_REL 9 /* Relocation entries, no addends */ ++#define SHT_SHLIB 10 /* Reserved */ ++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ ++#define SHT_INIT_ARRAY 14 /* Array of constructors */ ++#define SHT_FINI_ARRAY 15 /* Array of destructors */ ++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ ++#define SHT_GROUP 17 /* Section group */ ++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ ++#define SHT_NUM 19 /* Number of defined types. */ ++#define SHT_LOOS 0x60000000 /* Start OS-specific. */ ++#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ ++#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ ++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ ++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ ++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ ++#define SHT_SUNW_move 0x6ffffffa ++#define SHT_SUNW_COMDAT 0x6ffffffb ++#define SHT_SUNW_syminfo 0x6ffffffc ++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ ++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ ++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ ++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ ++#define SHT_HIOS 0x6fffffff /* End OS-specific type */ ++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define SHT_LOUSER 0x80000000 /* Start of application-specific */ ++#define SHT_HIUSER 0x8fffffff /* End of application-specific */ ++ ++/* Legal values for sh_flags (section flags). */ ++ ++#define SHF_WRITE (1 << 0) /* Writable */ ++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ ++#define SHF_EXECINSTR (1 << 2) /* Executable */ ++#define SHF_MERGE (1 << 4) /* Might be merged */ ++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ ++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ ++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ ++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling ++ required */ ++#define SHF_GROUP (1 << 9) /* Section is member of a group. */ ++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ ++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ ++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ ++#define SHF_ORDERED (1 << 30) /* Special ordering requirement ++ (Solaris). */ ++#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless ++ referenced or allocated (Solaris).*/ ++ ++/* Section group handling. */ ++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ ++ ++/* Symbol table entry. */ ++ ++typedef struct ++{ ++ Elf32_Word st_name; /* Symbol name (string tbl index) */ ++ Elf32_Addr st_value; /* Symbol value */ ++ Elf32_Word st_size; /* Symbol size */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf32_Section st_shndx; /* Section index */ ++} Elf32_Sym; ++ ++typedef struct ++{ ++ Elf64_Word st_name; /* Symbol name (string tbl index) */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf64_Section st_shndx; /* Section index */ ++ Elf64_Addr st_value; /* Symbol value */ ++ Elf64_Xword st_size; /* Symbol size */ ++} Elf64_Sym; ++ ++/* The syminfo section if available contains additional information about ++ every dynamic symbol. */ ++ ++typedef struct ++{ ++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf32_Half si_flags; /* Per symbol flags */ ++} Elf32_Syminfo; ++ ++typedef struct ++{ ++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf64_Half si_flags; /* Per symbol flags */ ++} Elf64_Syminfo; ++ ++/* Possible values for si_boundto. */ ++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ ++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ ++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ ++ ++/* Possible bitmasks for si_flags. */ ++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ ++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ ++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ ++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy ++ loaded */ ++/* Syminfo version values. */ ++#define SYMINFO_NONE 0 ++#define SYMINFO_CURRENT 1 ++#define SYMINFO_NUM 2 ++ ++ ++/* How to extract and insert information held in the st_info field. */ ++ ++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) ++#define ELF32_ST_TYPE(val) ((val) & 0xf) ++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) ++ ++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ ++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) ++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) ++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) ++ ++/* Legal values for ST_BIND subfield of st_info (symbol binding). */ ++ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* Weak symbol */ ++#define STB_NUM 3 /* Number of defined types. */ ++#define STB_LOOS 10 /* Start of OS-specific */ ++#define STB_GNU_UNIQUE 10 /* Unique symbol. */ ++#define STB_HIOS 12 /* End of OS-specific */ ++#define STB_LOPROC 13 /* Start of processor-specific */ ++#define STB_HIPROC 15 /* End of processor-specific */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_NOTYPE 0 /* Symbol type is unspecified */ ++#define STT_OBJECT 1 /* Symbol is a data object */ ++#define STT_FUNC 2 /* Symbol is a code object */ ++#define STT_SECTION 3 /* Symbol associated with a section */ ++#define STT_FILE 4 /* Symbol's name is file name */ ++#define STT_COMMON 5 /* Symbol is a common data object */ ++#define STT_TLS 6 /* Symbol is thread-local data object*/ ++#define STT_NUM 7 /* Number of defined types. */ ++#define STT_LOOS 10 /* Start of OS-specific */ ++#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ ++#define STT_HIOS 12 /* End of OS-specific */ ++#define STT_LOPROC 13 /* Start of processor-specific */ ++#define STT_HIPROC 15 /* End of processor-specific */ ++ ++ ++/* Symbol table indices are found in the hash buckets and chain table ++ of a symbol hash table section. This special index value indicates ++ the end of a chain, meaning no further symbols are found in that bucket. */ ++ ++#define STN_UNDEF 0 /* End of a chain. */ ++ ++ ++/* How to extract and insert information held in the st_other field. */ ++ ++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) ++ ++/* For ELF64 the definitions are the same. */ ++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) ++ ++/* Symbol visibility specification encoded in the st_other field. */ ++#define STV_DEFAULT 0 /* Default symbol visibility rules */ ++#define STV_INTERNAL 1 /* Processor specific hidden class */ ++#define STV_HIDDEN 2 /* Sym unavailable in other modules */ ++#define STV_PROTECTED 3 /* Not preemptible, not exported */ ++ ++ ++/* Relocation table entry without addend (in section of type SHT_REL). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++} Elf32_Rel; ++ ++/* I have seen two different definitions of the Elf64_Rel and ++ Elf64_Rela structures, so we'll leave them out until Novell (or ++ whoever) gets their act together. */ ++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++} Elf64_Rel; ++ ++/* Relocation table entry with addend (in section of type SHT_RELA). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++ Elf32_Sword r_addend; /* Addend */ ++} Elf32_Rela; ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++ Elf64_Sxword r_addend; /* Addend */ ++} Elf64_Rela; ++ ++/* How to extract and insert information held in the r_info field. */ ++ ++#define ELF32_R_SYM(val) ((val) >> 8) ++#define ELF32_R_TYPE(val) ((val) & 0xff) ++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) ++ ++#define ELF64_R_SYM(i) ((i) >> 32) ++#define ELF64_R_TYPE(i) ((i) & 0xffffffff) ++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) ++ ++/* Program segment header. */ ++ ++typedef struct ++{ ++ Elf32_Word p_type; /* Segment type */ ++ Elf32_Off p_offset; /* Segment file offset */ ++ Elf32_Addr p_vaddr; /* Segment virtual address */ ++ Elf32_Addr p_paddr; /* Segment physical address */ ++ Elf32_Word p_filesz; /* Segment size in file */ ++ Elf32_Word p_memsz; /* Segment size in memory */ ++ Elf32_Word p_flags; /* Segment flags */ ++ Elf32_Word p_align; /* Segment alignment */ ++} Elf32_Phdr; ++ ++typedef struct ++{ ++ Elf64_Word p_type; /* Segment type */ ++ Elf64_Word p_flags; /* Segment flags */ ++ Elf64_Off p_offset; /* Segment file offset */ ++ Elf64_Addr p_vaddr; /* Segment virtual address */ ++ Elf64_Addr p_paddr; /* Segment physical address */ ++ Elf64_Xword p_filesz; /* Segment size in file */ ++ Elf64_Xword p_memsz; /* Segment size in memory */ ++ Elf64_Xword p_align; /* Segment alignment */ ++} Elf64_Phdr; ++ ++/* Special value for e_phnum. This indicates that the real number of ++ program headers is too large to fit into e_phnum. Instead the real ++ value is in the field sh_info of section 0. */ ++ ++#define PN_XNUM 0xffff ++ ++/* Legal values for p_type (segment type). */ ++ ++#define PT_NULL 0 /* Program header table entry unused */ ++#define PT_LOAD 1 /* Loadable program segment */ ++#define PT_DYNAMIC 2 /* Dynamic linking information */ ++#define PT_INTERP 3 /* Program interpreter */ ++#define PT_NOTE 4 /* Auxiliary information */ ++#define PT_SHLIB 5 /* Reserved */ ++#define PT_PHDR 6 /* Entry for header table itself */ ++#define PT_TLS 7 /* Thread-local storage segment */ ++#define PT_NUM 8 /* Number of defined types */ ++#define PT_LOOS 0x60000000 /* Start of OS-specific */ ++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ ++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ ++#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ ++#define PT_LOSUNW 0x6ffffffa ++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ ++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ ++#define PT_HISUNW 0x6fffffff ++#define PT_HIOS 0x6fffffff /* End of OS-specific */ ++#define PT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define PT_HIPROC 0x7fffffff /* End of processor-specific */ ++ ++/* Legal values for p_flags (segment flags). */ ++ ++#define PF_X (1 << 0) /* Segment is executable */ ++#define PF_W (1 << 1) /* Segment is writable */ ++#define PF_R (1 << 2) /* Segment is readable */ ++#define PF_MASKOS 0x0ff00000 /* OS-specific */ ++#define PF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Legal values for note segment descriptor types for core files. */ ++ ++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ ++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ ++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ ++#define NT_PRXREG 4 /* Contains copy of prxregset struct */ ++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ ++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ ++#define NT_AUXV 6 /* Contains copy of auxv array */ ++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ ++#define NT_ASRS 8 /* Contains copy of asrset struct */ ++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ ++#define NT_PSINFO 13 /* Contains copy of psinfo struct */ ++#define NT_PRCRED 14 /* Contains copy of prcred struct */ ++#define NT_UTSNAME 15 /* Contains copy of utsname struct */ ++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ ++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ ++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ ++#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ ++#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ ++#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ ++#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ ++#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ ++#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ ++#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ ++ ++/* Legal values for the note segment descriptor types for object files. */ ++ ++#define NT_VERSION 1 /* Contains a version string. */ ++ ++ ++/* Dynamic section entry. */ ++ ++typedef struct ++{ ++ Elf32_Sword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf32_Word d_val; /* Integer value */ ++ Elf32_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct ++{ ++ Elf64_Sxword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf64_Xword d_val; /* Integer value */ ++ Elf64_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf64_Dyn; ++ ++/* Legal values for d_tag (dynamic entry type). */ ++ ++#define DT_NULL 0 /* Marks end of dynamic section */ ++#define DT_NEEDED 1 /* Name of needed library */ ++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ ++#define DT_PLTGOT 3 /* Processor defined value */ ++#define DT_HASH 4 /* Address of symbol hash table */ ++#define DT_STRTAB 5 /* Address of string table */ ++#define DT_SYMTAB 6 /* Address of symbol table */ ++#define DT_RELA 7 /* Address of Rela relocs */ ++#define DT_RELASZ 8 /* Total size of Rela relocs */ ++#define DT_RELAENT 9 /* Size of one Rela reloc */ ++#define DT_STRSZ 10 /* Size of string table */ ++#define DT_SYMENT 11 /* Size of one symbol table entry */ ++#define DT_INIT 12 /* Address of init function */ ++#define DT_FINI 13 /* Address of termination function */ ++#define DT_SONAME 14 /* Name of shared object */ ++#define DT_RPATH 15 /* Library search path (deprecated) */ ++#define DT_SYMBOLIC 16 /* Start symbol search here */ ++#define DT_REL 17 /* Address of Rel relocs */ ++#define DT_RELSZ 18 /* Total size of Rel relocs */ ++#define DT_RELENT 19 /* Size of one Rel reloc */ ++#define DT_PLTREL 20 /* Type of reloc in PLT */ ++#define DT_DEBUG 21 /* For debugging; unspecified */ ++#define DT_TEXTREL 22 /* Reloc might modify .text */ ++#define DT_JMPREL 23 /* Address of PLT relocs */ ++#define DT_BIND_NOW 24 /* Process relocations of object */ ++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ ++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ ++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ ++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ ++#define DT_RUNPATH 29 /* Library search path */ ++#define DT_FLAGS 30 /* Flags for the object being loaded */ ++#define DT_ENCODING 32 /* Start of encoded range */ ++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ ++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ ++#define DT_NUM 34 /* Number used */ ++#define DT_LOOS 0x6000000d /* Start of OS-specific */ ++#define DT_HIOS 0x6ffff000 /* End of OS-specific */ ++#define DT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define DT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ ++ ++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the ++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's ++ approach. */ ++#define DT_VALRNGLO 0x6ffffd00 ++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ ++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ ++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ ++#define DT_CHECKSUM 0x6ffffdf8 ++#define DT_PLTPADSZ 0x6ffffdf9 ++#define DT_MOVEENT 0x6ffffdfa ++#define DT_MOVESZ 0x6ffffdfb ++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ ++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting ++ the following DT_* entry. */ ++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ ++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ ++#define DT_VALRNGHI 0x6ffffdff ++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ ++#define DT_VALNUM 12 ++ ++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the ++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure. ++ ++ If any adjustment is made to the ELF object after it has been ++ built these entries will need to be adjusted. */ ++#define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ ++#define DT_TLSDESC_PLT 0x6ffffef6 ++#define DT_TLSDESC_GOT 0x6ffffef7 ++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ ++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ ++#define DT_CONFIG 0x6ffffefa /* Configuration information. */ ++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ ++#define DT_AUDIT 0x6ffffefc /* Object auditing. */ ++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ ++#define DT_MOVETAB 0x6ffffefe /* Move table. */ ++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ ++#define DT_ADDRRNGHI 0x6ffffeff ++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ ++#define DT_ADDRNUM 11 ++ ++/* The versioning entry types. The next are defined as part of the ++ GNU extension. */ ++#define DT_VERSYM 0x6ffffff0 ++ ++#define DT_RELACOUNT 0x6ffffff9 ++#define DT_RELCOUNT 0x6ffffffa ++ ++/* These were chosen by Sun. */ ++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ ++#define DT_VERDEF 0x6ffffffc /* Address of version definition ++ table */ ++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ ++#define DT_VERNEED 0x6ffffffe /* Address of table with needed ++ versions */ ++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ ++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ ++#define DT_VERSIONTAGNUM 16 ++ ++/* Sun added these machine-independent extensions in the "processor-specific" ++ range. Be compatible. */ ++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ ++#define DT_FILTER 0x7fffffff /* Shared object to get values from */ ++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) ++#define DT_EXTRANUM 3 ++ ++/* Values of `d_un.d_val' in the DT_FLAGS entry. */ ++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ ++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ ++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ ++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ ++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ ++ ++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 ++ entry in the dynamic section. */ ++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ ++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ ++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ ++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ ++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ ++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ ++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ ++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ ++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ ++#define DF_1_TRANS 0x00000200 ++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ ++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ ++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ ++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ ++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ ++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ ++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ ++ ++/* Flags for the feature selection in DT_FEATURE_1. */ ++#define DTF_1_PARINIT 0x00000001 ++#define DTF_1_CONFEXP 0x00000002 ++ ++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ ++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ ++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not ++ generally available. */ ++ ++/* Version definition sections. */ ++ ++typedef struct ++{ ++ Elf32_Half vd_version; /* Version revision */ ++ Elf32_Half vd_flags; /* Version information */ ++ Elf32_Half vd_ndx; /* Version Index */ ++ Elf32_Half vd_cnt; /* Number of associated aux entries */ ++ Elf32_Word vd_hash; /* Version name hash value */ ++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf32_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf32_Verdef; ++ ++typedef struct ++{ ++ Elf64_Half vd_version; /* Version revision */ ++ Elf64_Half vd_flags; /* Version information */ ++ Elf64_Half vd_ndx; /* Version Index */ ++ Elf64_Half vd_cnt; /* Number of associated aux entries */ ++ Elf64_Word vd_hash; /* Version name hash value */ ++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf64_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf64_Verdef; ++ ++ ++/* Legal values for vd_version (version revision). */ ++#define VER_DEF_NONE 0 /* No version */ ++#define VER_DEF_CURRENT 1 /* Current version */ ++#define VER_DEF_NUM 2 /* Given version number */ ++ ++/* Legal values for vd_flags (version information flags). */ ++#define VER_FLG_BASE 0x1 /* Version definition of file itself */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++/* Versym symbol index values. */ ++#define VER_NDX_LOCAL 0 /* Symbol is local. */ ++#define VER_NDX_GLOBAL 1 /* Symbol is global. */ ++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ ++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ ++ ++/* Auxialiary version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vda_name; /* Version or dependency names */ ++ Elf32_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf32_Verdaux; ++ ++typedef struct ++{ ++ Elf64_Word vda_name; /* Version or dependency names */ ++ Elf64_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf64_Verdaux; ++ ++ ++/* Version dependency section. */ ++ ++typedef struct ++{ ++ Elf32_Half vn_version; /* Version of structure */ ++ Elf32_Half vn_cnt; /* Number of associated aux entries */ ++ Elf32_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf32_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf32_Verneed; ++ ++typedef struct ++{ ++ Elf64_Half vn_version; /* Version of structure */ ++ Elf64_Half vn_cnt; /* Number of associated aux entries */ ++ Elf64_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf64_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf64_Verneed; ++ ++ ++/* Legal values for vn_version (version revision). */ ++#define VER_NEED_NONE 0 /* No version */ ++#define VER_NEED_CURRENT 1 /* Current version */ ++#define VER_NEED_NUM 2 /* Given version number */ ++ ++/* Auxiliary needed version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vna_hash; /* Hash value of dependency name */ ++ Elf32_Half vna_flags; /* Dependency specific information */ ++ Elf32_Half vna_other; /* Unused */ ++ Elf32_Word vna_name; /* Dependency name string offset */ ++ Elf32_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf32_Vernaux; ++ ++typedef struct ++{ ++ Elf64_Word vna_hash; /* Hash value of dependency name */ ++ Elf64_Half vna_flags; /* Dependency specific information */ ++ Elf64_Half vna_other; /* Unused */ ++ Elf64_Word vna_name; /* Dependency name string offset */ ++ Elf64_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf64_Vernaux; ++ ++ ++/* Legal values for vna_flags. */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++ ++/* Auxiliary vector. */ ++ ++/* This vector is normally only used by the program interpreter. The ++ usual definition in an ABI supplement uses the name auxv_t. The ++ vector is not usually defined in a standard file, but it ++ can't hurt. We rename it to avoid conflicts. The sizes of these ++ types are an arrangement between the exec server and the program ++ interpreter, so we don't fully specify them here. */ ++ ++typedef struct ++{ ++ uint32_t a_type; /* Entry type */ ++ union ++ { ++ uint32_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf32_auxv_t; ++ ++typedef struct ++{ ++ uint64_t a_type; /* Entry type */ ++ union ++ { ++ uint64_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf64_auxv_t; ++ ++/* Legal values for a_type (entry type). */ ++ ++#define AT_NULL 0 /* End of vector */ ++#define AT_IGNORE 1 /* Entry should be ignored */ ++#define AT_EXECFD 2 /* File descriptor of program */ ++#define AT_PHDR 3 /* Program headers for program */ ++#define AT_PHENT 4 /* Size of program header entry */ ++#define AT_PHNUM 5 /* Number of program headers */ ++#define AT_PAGESZ 6 /* System page size */ ++#define AT_BASE 7 /* Base address of interpreter */ ++#define AT_FLAGS 8 /* Flags */ ++#define AT_ENTRY 9 /* Entry point of program */ ++#define AT_NOTELF 10 /* Program is not ELF */ ++#define AT_UID 11 /* Real uid */ ++#define AT_EUID 12 /* Effective uid */ ++#define AT_GID 13 /* Real gid */ ++#define AT_EGID 14 /* Effective gid */ ++#define AT_CLKTCK 17 /* Frequency of times() */ ++ ++/* Some more special a_type values describing the hardware. */ ++#define AT_PLATFORM 15 /* String identifying platform. */ ++#define AT_HWCAP 16 /* Machine dependent hints about ++ processor capabilities. */ ++ ++/* This entry gives some information about the FPU initialization ++ performed by the kernel. */ ++#define AT_FPUCW 18 /* Used FPU control word. */ ++ ++/* Cache block sizes. */ ++#define AT_DCACHEBSIZE 19 /* Data cache block size. */ ++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ ++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ ++ ++/* A special ignored value for PPC, used by the kernel to control the ++ interpretation of the AUXV. Must be > 16. */ ++#define AT_IGNOREPPC 22 /* Entry should be ignored. */ ++ ++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ ++ ++#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ ++ ++#define AT_RANDOM 25 /* Address of 16 random bytes. */ ++ ++#define AT_EXECFN 31 /* Filename of executable. */ ++ ++/* Pointer to the global system page used for system calls and other ++ nice things. */ ++#define AT_SYSINFO 32 ++#define AT_SYSINFO_EHDR 33 ++ ++/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains ++ log2 of line size; mask those to get cache size. */ ++#define AT_L1I_CACHESHAPE 34 ++#define AT_L1D_CACHESHAPE 35 ++#define AT_L2_CACHESHAPE 36 ++#define AT_L3_CACHESHAPE 37 ++ ++/* Note section contents. Each entry in the note section begins with ++ a header of a fixed form. */ ++ ++typedef struct ++{ ++ Elf32_Word n_namesz; /* Length of the note's name. */ ++ Elf32_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf32_Word n_type; /* Type of the note. */ ++} Elf32_Nhdr; ++ ++typedef struct ++{ ++ Elf64_Word n_namesz; /* Length of the note's name. */ ++ Elf64_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf64_Word n_type; /* Type of the note. */ ++} Elf64_Nhdr; ++ ++/* Known names of notes. */ ++ ++/* Solaris entries in the note section have this name. */ ++#define ELF_NOTE_SOLARIS "SUNW Solaris" ++ ++/* Note entries for GNU systems have this name. */ ++#define ELF_NOTE_GNU "GNU" ++ ++ ++/* Defined types of notes for Solaris. */ ++ ++/* Value of descriptor (one word) is desired pagesize for the binary. */ ++#define ELF_NOTE_PAGESIZE_HINT 1 ++ ++ ++/* Defined note types for GNU systems. */ ++ ++/* ABI information. The descriptor consists of words: ++ word 0: OS descriptor ++ word 1: major version of the ABI ++ word 2: minor version of the ABI ++ word 3: subminor version of the ABI ++*/ ++#define NT_GNU_ABI_TAG 1 ++#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ ++ ++/* Known OSes. These values can appear in word 0 of an ++ NT_GNU_ABI_TAG note section entry. */ ++#define ELF_NOTE_OS_LINUX 0 ++#define ELF_NOTE_OS_GNU 1 ++#define ELF_NOTE_OS_SOLARIS2 2 ++#define ELF_NOTE_OS_FREEBSD 3 ++ ++/* Synthetic hwcap information. The descriptor begins with two words: ++ word 0: number of entries ++ word 1: bitmask of enabled entries ++ Then follow variable-length entries, one byte followed by a ++ '\0'-terminated hwcap name string. The byte gives the bit ++ number to test if enabled, (1U << bit) & bitmask. */ ++#define NT_GNU_HWCAP 2 ++ ++/* Build ID bits as generated by ld --build-id. ++ The descriptor consists of any nonzero number of bytes. */ ++#define NT_GNU_BUILD_ID 3 ++ ++/* Version note generated by GNU gold containing a version string. */ ++#define NT_GNU_GOLD_VERSION 4 ++ ++ ++/* Move records. */ ++typedef struct ++{ ++ Elf32_Xword m_value; /* Symbol value. */ ++ Elf32_Word m_info; /* Size and index. */ ++ Elf32_Word m_poffset; /* Symbol offset. */ ++ Elf32_Half m_repeat; /* Repeat count. */ ++ Elf32_Half m_stride; /* Stride info. */ ++} Elf32_Move; ++ ++typedef struct ++{ ++ Elf64_Xword m_value; /* Symbol value. */ ++ Elf64_Xword m_info; /* Size and index. */ ++ Elf64_Xword m_poffset; /* Symbol offset. */ ++ Elf64_Half m_repeat; /* Repeat count. */ ++ Elf64_Half m_stride; /* Stride info. */ ++} Elf64_Move; ++ ++/* Macro to construct move records. */ ++#define ELF32_M_SYM(info) ((info) >> 8) ++#define ELF32_M_SIZE(info) ((unsigned char) (info)) ++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) ++ ++#define ELF64_M_SYM(info) ELF32_M_SYM (info) ++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) ++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) ++ ++ ++/* Motorola 68k specific definitions. */ ++ ++/* Values for Elf32_Ehdr.e_flags. */ ++#define EF_CPU32 0x00810000 ++ ++/* m68k relocs. */ ++ ++#define R_68K_NONE 0 /* No reloc */ ++#define R_68K_32 1 /* Direct 32 bit */ ++#define R_68K_16 2 /* Direct 16 bit */ ++#define R_68K_8 3 /* Direct 8 bit */ ++#define R_68K_PC32 4 /* PC relative 32 bit */ ++#define R_68K_PC16 5 /* PC relative 16 bit */ ++#define R_68K_PC8 6 /* PC relative 8 bit */ ++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ ++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ ++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ ++#define R_68K_GOT32O 10 /* 32 bit GOT offset */ ++#define R_68K_GOT16O 11 /* 16 bit GOT offset */ ++#define R_68K_GOT8O 12 /* 8 bit GOT offset */ ++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ ++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ ++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ ++#define R_68K_PLT32O 16 /* 32 bit PLT offset */ ++#define R_68K_PLT16O 17 /* 16 bit PLT offset */ ++#define R_68K_PLT8O 18 /* 8 bit PLT offset */ ++#define R_68K_COPY 19 /* Copy symbol at runtime */ ++#define R_68K_GLOB_DAT 20 /* Create GOT entry */ ++#define R_68K_JMP_SLOT 21 /* Create PLT entry */ ++#define R_68K_RELATIVE 22 /* Adjust by program base */ ++#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ ++#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ ++#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ ++#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ ++#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ ++#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ ++#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ ++#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ ++#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ ++#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ ++#define R_68K_TLS_LE32 37 /* 32 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE16 38 /* 16 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE8 39 /* 8 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ ++#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ ++#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ ++/* Keep this the last entry. */ ++#define R_68K_NUM 43 ++ ++/* Intel 80386 specific definitions. */ ++ ++/* i386 relocs. */ ++ ++#define R_386_NONE 0 /* No reloc */ ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++#define R_386_GOT32 3 /* 32 bit GOT entry */ ++#define R_386_PLT32 4 /* 32 bit PLT address */ ++#define R_386_COPY 5 /* Copy symbol at runtime */ ++#define R_386_GLOB_DAT 6 /* Create GOT entry */ ++#define R_386_JMP_SLOT 7 /* Create PLT entry */ ++#define R_386_RELATIVE 8 /* Adjust by program base */ ++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ ++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ ++#define R_386_32PLT 11 ++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ ++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS ++ block offset */ ++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block ++ offset */ ++#define R_386_TLS_LE 17 /* Offset relative to static TLS ++ block */ ++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of ++ general dynamic thread local data */ ++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of ++ local dynamic thread local data ++ in LE code */ ++#define R_386_16 20 ++#define R_386_PC16 21 ++#define R_386_8 22 ++#define R_386_PC8 23 ++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic ++ thread local data */ ++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ ++#define R_386_TLS_GD_CALL 26 /* Relocation for call to ++ __tls_get_addr() */ ++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ ++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic ++ thread local data in LE code */ ++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ ++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to ++ __tls_get_addr() in LDM code */ ++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ ++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ ++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS ++ block offset */ ++#define R_386_TLS_LE_32 34 /* Negated offset relative to static ++ TLS block */ ++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ ++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ ++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ ++/* 38? */ ++#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ ++#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS ++ descriptor for ++ relaxation. */ ++#define R_386_TLS_DESC 41 /* TLS descriptor containing ++ pointer to code and to ++ argument, returning the TLS ++ offset for the symbol. */ ++#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ ++/* Keep this the last entry. */ ++#define R_386_NUM 43 ++ ++/* SUN SPARC specific definitions. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ ++ ++/* Values for Elf64_Ehdr.e_flags. */ ++ ++#define EF_SPARCV9_MM 3 ++#define EF_SPARCV9_TSO 0 ++#define EF_SPARCV9_PSO 1 ++#define EF_SPARCV9_RMO 2 ++#define EF_SPARC_LEDATA 0x800000 /* little endian data */ ++#define EF_SPARC_EXT_MASK 0xFFFF00 ++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ ++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ ++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ ++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ ++ ++/* SPARC relocs. */ ++ ++#define R_SPARC_NONE 0 /* No reloc */ ++#define R_SPARC_8 1 /* Direct 8 bit */ ++#define R_SPARC_16 2 /* Direct 16 bit */ ++#define R_SPARC_32 3 /* Direct 32 bit */ ++#define R_SPARC_DISP8 4 /* PC relative 8 bit */ ++#define R_SPARC_DISP16 5 /* PC relative 16 bit */ ++#define R_SPARC_DISP32 6 /* PC relative 32 bit */ ++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ ++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ ++#define R_SPARC_HI22 9 /* High 22 bit */ ++#define R_SPARC_22 10 /* Direct 22 bit */ ++#define R_SPARC_13 11 /* Direct 13 bit */ ++#define R_SPARC_LO10 12 /* Truncated 10 bit */ ++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ ++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ ++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ ++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ ++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ ++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ ++#define R_SPARC_COPY 19 /* Copy symbol at runtime */ ++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ ++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ ++#define R_SPARC_RELATIVE 22 /* Adjust by program base */ ++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ ++ ++/* Additional Sparc64 relocs. */ ++ ++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ ++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ ++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ ++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ ++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ ++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ ++#define R_SPARC_10 30 /* Direct 10 bit */ ++#define R_SPARC_11 31 /* Direct 11 bit */ ++#define R_SPARC_64 32 /* Direct 64 bit */ ++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ ++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ ++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ ++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ ++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ ++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ ++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ ++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ ++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ ++#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ ++#define R_SPARC_7 43 /* Direct 7 bit */ ++#define R_SPARC_5 44 /* Direct 5 bit */ ++#define R_SPARC_6 45 /* Direct 6 bit */ ++#define R_SPARC_DISP64 46 /* PC relative 64 bit */ ++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ ++#define R_SPARC_HIX22 48 /* High 22 bit complemented */ ++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ ++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ ++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ ++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ ++#define R_SPARC_REGISTER 53 /* Global register usage */ ++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ ++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ ++#define R_SPARC_TLS_GD_HI22 56 ++#define R_SPARC_TLS_GD_LO10 57 ++#define R_SPARC_TLS_GD_ADD 58 ++#define R_SPARC_TLS_GD_CALL 59 ++#define R_SPARC_TLS_LDM_HI22 60 ++#define R_SPARC_TLS_LDM_LO10 61 ++#define R_SPARC_TLS_LDM_ADD 62 ++#define R_SPARC_TLS_LDM_CALL 63 ++#define R_SPARC_TLS_LDO_HIX22 64 ++#define R_SPARC_TLS_LDO_LOX10 65 ++#define R_SPARC_TLS_LDO_ADD 66 ++#define R_SPARC_TLS_IE_HI22 67 ++#define R_SPARC_TLS_IE_LO10 68 ++#define R_SPARC_TLS_IE_LD 69 ++#define R_SPARC_TLS_IE_LDX 70 ++#define R_SPARC_TLS_IE_ADD 71 ++#define R_SPARC_TLS_LE_HIX22 72 ++#define R_SPARC_TLS_LE_LOX10 73 ++#define R_SPARC_TLS_DTPMOD32 74 ++#define R_SPARC_TLS_DTPMOD64 75 ++#define R_SPARC_TLS_DTPOFF32 76 ++#define R_SPARC_TLS_DTPOFF64 77 ++#define R_SPARC_TLS_TPOFF32 78 ++#define R_SPARC_TLS_TPOFF64 79 ++#define R_SPARC_GOTDATA_HIX22 80 ++#define R_SPARC_GOTDATA_LOX10 81 ++#define R_SPARC_GOTDATA_OP_HIX22 82 ++#define R_SPARC_GOTDATA_OP_LOX10 83 ++#define R_SPARC_GOTDATA_OP 84 ++#define R_SPARC_H34 85 ++#define R_SPARC_SIZE32 86 ++#define R_SPARC_SIZE64 87 ++#define R_SPARC_WDISP10 88 ++#define R_SPARC_JMP_IREL 248 ++#define R_SPARC_IRELATIVE 249 ++#define R_SPARC_GNU_VTINHERIT 250 ++#define R_SPARC_GNU_VTENTRY 251 ++#define R_SPARC_REV32 252 ++/* Keep this the last entry. */ ++#define R_SPARC_NUM 253 ++ ++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ ++ ++#define DT_SPARC_REGISTER 0x70000001 ++#define DT_SPARC_NUM 2 ++ ++/* MIPS R3000 specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ ++#define EF_MIPS_PIC 2 /* Contains PIC code */ ++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ ++#define EF_MIPS_XGOT 8 ++#define EF_MIPS_64BIT_WHIRL 16 ++#define EF_MIPS_ABI2 32 ++#define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ ++ ++/* Legal values for MIPS architecture level. */ ++ ++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* The following are non-official names and should not be used. */ ++ ++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* Special section indices. */ ++ ++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ ++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ ++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ ++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ ++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ ++#define SHT_MIPS_MSYM 0x70000001 ++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ ++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ ++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ ++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ ++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ ++#define SHT_MIPS_PACKAGE 0x70000007 ++#define SHT_MIPS_PACKSYM 0x70000008 ++#define SHT_MIPS_RELD 0x70000009 ++#define SHT_MIPS_IFACE 0x7000000b ++#define SHT_MIPS_CONTENT 0x7000000c ++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ ++#define SHT_MIPS_SHDR 0x70000010 ++#define SHT_MIPS_FDESC 0x70000011 ++#define SHT_MIPS_EXTSYM 0x70000012 ++#define SHT_MIPS_DENSE 0x70000013 ++#define SHT_MIPS_PDESC 0x70000014 ++#define SHT_MIPS_LOCSYM 0x70000015 ++#define SHT_MIPS_AUXSYM 0x70000016 ++#define SHT_MIPS_OPTSYM 0x70000017 ++#define SHT_MIPS_LOCSTR 0x70000018 ++#define SHT_MIPS_LINE 0x70000019 ++#define SHT_MIPS_RFDESC 0x7000001a ++#define SHT_MIPS_DELTASYM 0x7000001b ++#define SHT_MIPS_DELTAINST 0x7000001c ++#define SHT_MIPS_DELTACLASS 0x7000001d ++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ ++#define SHT_MIPS_DELTADECL 0x7000001f ++#define SHT_MIPS_SYMBOL_LIB 0x70000020 ++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ ++#define SHT_MIPS_TRANSLATE 0x70000022 ++#define SHT_MIPS_PIXIE 0x70000023 ++#define SHT_MIPS_XLATE 0x70000024 ++#define SHT_MIPS_XLATE_DEBUG 0x70000025 ++#define SHT_MIPS_WHIRL 0x70000026 ++#define SHT_MIPS_EH_REGION 0x70000027 ++#define SHT_MIPS_XLATE_OLD 0x70000028 ++#define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ ++#define SHF_MIPS_MERGE 0x20000000 ++#define SHF_MIPS_ADDR 0x40000000 ++#define SHF_MIPS_STRINGS 0x80000000 ++#define SHF_MIPS_NOSTRIP 0x08000000 ++#define SHF_MIPS_LOCAL 0x04000000 ++#define SHF_MIPS_NAMES 0x02000000 ++#define SHF_MIPS_NODUPE 0x01000000 ++ ++ ++/* Symbol tables. */ ++ ++/* MIPS specific values for `st_other'. */ ++#define STO_MIPS_DEFAULT 0x0 ++#define STO_MIPS_INTERNAL 0x1 ++#define STO_MIPS_HIDDEN 0x2 ++#define STO_MIPS_PROTECTED 0x3 ++#define STO_MIPS_PLT 0x8 ++#define STO_MIPS_SC_ALIGN_UNUSED 0xff ++ ++/* MIPS specific values for `st_info'. */ ++#define STB_MIPS_SPLIT_COMMON 13 ++ ++/* Entries found in sections of type SHT_MIPS_GPTAB. */ ++ ++typedef union ++{ ++ struct ++ { ++ Elf32_Word gt_current_g_value; /* -G value used for compilation */ ++ Elf32_Word gt_unused; /* Not used */ ++ } gt_header; /* First entry in section */ ++ struct ++ { ++ Elf32_Word gt_g_value; /* If this value were used for -G */ ++ Elf32_Word gt_bytes; /* This many bytes would be used */ ++ } gt_entry; /* Subsequent entries in section */ ++} Elf32_gptab; ++ ++/* Entry found in sections of type SHT_MIPS_REGINFO. */ ++ ++typedef struct ++{ ++ Elf32_Word ri_gprmask; /* General registers used */ ++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ ++ Elf32_Sword ri_gp_value; /* $gp register value */ ++} Elf32_RegInfo; ++ ++/* Entries found in sections of type SHT_MIPS_OPTIONS. */ ++ ++typedef struct ++{ ++ unsigned char kind; /* Determines interpretation of the ++ variable part of descriptor. */ ++ unsigned char size; /* Size of descriptor, including header. */ ++ Elf32_Section section; /* Section header index of section affected, ++ 0 for global options. */ ++ Elf32_Word info; /* Kind-specific information. */ ++} Elf_Options; ++ ++/* Values for `kind' field in Elf_Options. */ ++ ++#define ODK_NULL 0 /* Undefined. */ ++#define ODK_REGINFO 1 /* Register usage information. */ ++#define ODK_EXCEPTIONS 2 /* Exception processing options. */ ++#define ODK_PAD 3 /* Section padding options. */ ++#define ODK_HWPATCH 4 /* Hardware workarounds performed */ ++#define ODK_FILL 5 /* record the fill value used by the linker. */ ++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ ++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ ++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ ++ ++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ ++ ++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ ++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ ++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ ++#define OEX_SMM 0x20000 /* Force sequential memory mode? */ ++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ ++#define OEX_PRECISEFP OEX_FPDBUG ++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ ++ ++#define OEX_FPU_INVAL 0x10 ++#define OEX_FPU_DIV0 0x08 ++#define OEX_FPU_OFLO 0x04 ++#define OEX_FPU_UFLO 0x02 ++#define OEX_FPU_INEX 0x01 ++ ++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ ++ ++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ ++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ ++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ ++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ ++ ++#define OPAD_PREFIX 0x1 ++#define OPAD_POSTFIX 0x2 ++#define OPAD_SYMBOL 0x4 ++ ++/* Entry found in `.options' section. */ ++ ++typedef struct ++{ ++ Elf32_Word hwp_flags1; /* Extra flags. */ ++ Elf32_Word hwp_flags2; /* Extra flags. */ ++} Elf_Options_Hw; ++ ++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ ++ ++#define OHWA0_R4KEOP_CHECKED 0x00000001 ++#define OHWA1_R4KEOP_CLEAN 0x00000002 ++ ++/* MIPS relocs. */ ++ ++#define R_MIPS_NONE 0 /* No reloc */ ++#define R_MIPS_16 1 /* Direct 16 bit */ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_REL32 3 /* PC relative 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ ++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ ++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ ++#define R_MIPS_PC16 10 /* PC relative 16 bit */ ++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ ++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ ++ ++#define R_MIPS_SHIFT5 16 ++#define R_MIPS_SHIFT6 17 ++#define R_MIPS_64 18 ++#define R_MIPS_GOT_DISP 19 ++#define R_MIPS_GOT_PAGE 20 ++#define R_MIPS_GOT_OFST 21 ++#define R_MIPS_GOT_HI16 22 ++#define R_MIPS_GOT_LO16 23 ++#define R_MIPS_SUB 24 ++#define R_MIPS_INSERT_A 25 ++#define R_MIPS_INSERT_B 26 ++#define R_MIPS_DELETE 27 ++#define R_MIPS_HIGHER 28 ++#define R_MIPS_HIGHEST 29 ++#define R_MIPS_CALL_HI16 30 ++#define R_MIPS_CALL_LO16 31 ++#define R_MIPS_SCN_DISP 32 ++#define R_MIPS_REL16 33 ++#define R_MIPS_ADD_IMMEDIATE 34 ++#define R_MIPS_PJUMP 35 ++#define R_MIPS_RELGOT 36 ++#define R_MIPS_JALR 37 ++#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ ++#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ ++#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ ++#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ ++#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ ++#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ ++#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ ++#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ ++#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ ++#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ ++#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ ++#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ ++#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ ++#define R_MIPS_GLOB_DAT 51 ++#define R_MIPS_COPY 126 ++#define R_MIPS_JUMP_SLOT 127 ++/* Keep this the last entry. */ ++#define R_MIPS_NUM 128 ++ ++/* Legal values for p_type field of Elf32_Phdr. */ ++ ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++ ++/* Special program header types. */ ++ ++#define PF_MIPS_LOCAL 0x10000000 ++ ++/* Legal values for d_tag field of Elf32_Dyn. */ ++ ++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ ++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ ++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ ++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ ++#define DT_MIPS_FLAGS 0x70000005 /* Flags */ ++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ ++#define DT_MIPS_MSYM 0x70000007 ++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ ++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ ++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ ++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ ++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ ++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ ++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ ++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ ++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ ++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ ++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ ++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in ++ DT_MIPS_DELTA_CLASS. */ ++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ ++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in ++ DT_MIPS_DELTA_INSTANCE. */ ++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ ++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in ++ DT_MIPS_DELTA_RELOC. */ ++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta ++ relocations refer to. */ ++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in ++ DT_MIPS_DELTA_SYM. */ ++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the ++ class declaration. */ ++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in ++ DT_MIPS_DELTA_CLASSSYM. */ ++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ ++#define DT_MIPS_PIXIE_INIT 0x70000023 ++#define DT_MIPS_SYMBOL_LIB 0x70000024 ++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 ++#define DT_MIPS_LOCAL_GOTIDX 0x70000026 ++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 ++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 ++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ ++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ ++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b ++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ ++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve ++ function stored in GOT. */ ++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added ++ by rld on dlopen() calls. */ ++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ ++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ ++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ ++/* The address of .got.plt in an executable using the new non-PIC ABI. */ ++#define DT_MIPS_PLTGOT 0x70000032 ++/* The base of the PLT in an executable using the new non-PIC ABI if that ++ PLT is writable. For a non-writable PLT, this is omitted or has a zero ++ value. */ ++#define DT_MIPS_RWPLT 0x70000034 ++#define DT_MIPS_NUM 0x35 ++ ++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ ++ ++#define RHF_NONE 0 /* No flags */ ++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ ++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ ++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ ++#define RHF_NO_MOVE (1 << 3) ++#define RHF_SGI_ONLY (1 << 4) ++#define RHF_GUARANTEE_INIT (1 << 5) ++#define RHF_DELTA_C_PLUS_PLUS (1 << 6) ++#define RHF_GUARANTEE_START_INIT (1 << 7) ++#define RHF_PIXIE (1 << 8) ++#define RHF_DEFAULT_DELAY_LOAD (1 << 9) ++#define RHF_REQUICKSTART (1 << 10) ++#define RHF_REQUICKSTARTED (1 << 11) ++#define RHF_CORD (1 << 12) ++#define RHF_NO_UNRES_UNDEF (1 << 13) ++#define RHF_RLD_ORDER_SAFE (1 << 14) ++ ++/* Entries found in sections of type SHT_MIPS_LIBLIST. */ ++ ++typedef struct ++{ ++ Elf32_Word l_name; /* Name (string table index) */ ++ Elf32_Word l_time_stamp; /* Timestamp */ ++ Elf32_Word l_checksum; /* Checksum */ ++ Elf32_Word l_version; /* Interface version */ ++ Elf32_Word l_flags; /* Flags */ ++} Elf32_Lib; ++ ++typedef struct ++{ ++ Elf64_Word l_name; /* Name (string table index) */ ++ Elf64_Word l_time_stamp; /* Timestamp */ ++ Elf64_Word l_checksum; /* Checksum */ ++ Elf64_Word l_version; /* Interface version */ ++ Elf64_Word l_flags; /* Flags */ ++} Elf64_Lib; ++ ++ ++/* Legal values for l_flags. */ ++ ++#define LL_NONE 0 ++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ ++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ ++#define LL_REQUIRE_MINOR (1 << 2) ++#define LL_EXPORTS (1 << 3) ++#define LL_DELAY_LOAD (1 << 4) ++#define LL_DELTA (1 << 5) ++ ++/* Entries found in sections of type SHT_MIPS_CONFLICT. */ ++ ++typedef Elf32_Addr Elf32_Conflict; ++ ++ ++/* HPPA specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ ++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ ++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ ++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ ++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch ++ prediction. */ ++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ ++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ ++ ++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ ++ ++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ ++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ ++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ ++ ++/* Additional section indeces. */ ++ ++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared ++ symbols in ANSI C. */ ++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ ++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ ++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ ++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ ++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ ++ ++#define STT_HP_OPAQUE (STT_LOOS + 0x1) ++#define STT_HP_STUB (STT_LOOS + 0x2) ++ ++/* HPPA relocs. */ ++ ++#define R_PARISC_NONE 0 /* No reloc. */ ++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ ++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ ++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ ++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ ++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ ++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ ++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ ++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ ++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ ++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ ++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ ++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ ++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ ++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ ++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ ++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ ++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ ++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ ++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ ++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ ++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ ++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ ++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ ++#define R_PARISC_FPTR64 64 /* 64 bits function address. */ ++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ ++#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ ++#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ ++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ ++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ ++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ ++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ ++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ ++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ ++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ ++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ ++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ ++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ ++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ ++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ ++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ ++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ ++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LORESERVE 128 ++#define R_PARISC_COPY 128 /* Copy relocation. */ ++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ ++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ ++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ ++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ ++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ ++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ ++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ ++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ ++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_GNU_VTENTRY 232 ++#define R_PARISC_GNU_VTINHERIT 233 ++#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ ++#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ ++#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ ++#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ ++#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ ++#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ ++#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ ++#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ ++#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ ++#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ ++#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L ++#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R ++#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L ++#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R ++#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 ++#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 ++#define R_PARISC_HIRESERVE 255 ++ ++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PT_HP_TLS (PT_LOOS + 0x0) ++#define PT_HP_CORE_NONE (PT_LOOS + 0x1) ++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) ++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) ++#define PT_HP_CORE_COMM (PT_LOOS + 0x4) ++#define PT_HP_CORE_PROC (PT_LOOS + 0x5) ++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) ++#define PT_HP_CORE_STACK (PT_LOOS + 0x7) ++#define PT_HP_CORE_SHM (PT_LOOS + 0x8) ++#define PT_HP_CORE_MMF (PT_LOOS + 0x9) ++#define PT_HP_PARALLEL (PT_LOOS + 0x10) ++#define PT_HP_FASTBIND (PT_LOOS + 0x11) ++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) ++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) ++#define PT_HP_STACK (PT_LOOS + 0x14) ++ ++#define PT_PARISC_ARCHEXT 0x70000000 ++#define PT_PARISC_UNWIND 0x70000001 ++ ++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PF_PARISC_SBP 0x08000000 ++ ++#define PF_HP_PAGE_SIZE 0x00100000 ++#define PF_HP_FAR_SHARED 0x00200000 ++#define PF_HP_NEAR_SHARED 0x00400000 ++#define PF_HP_CODE 0x01000000 ++#define PF_HP_MODIFY 0x02000000 ++#define PF_HP_LAZYSWAP 0x04000000 ++#define PF_HP_SBP 0x08000000 ++ ++ ++/* Alpha specific definitions. */ ++ ++/* Legal values for e_flags field of Elf64_Ehdr. */ ++ ++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ ++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ ++ ++/* Legal values for sh_type field of Elf64_Shdr. */ ++ ++/* These two are primerily concerned with ECOFF debugging info. */ ++#define SHT_ALPHA_DEBUG 0x70000001 ++#define SHT_ALPHA_REGINFO 0x70000002 ++ ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++ ++#define SHF_ALPHA_GPREL 0x10000000 ++ ++/* Legal values for st_other field of Elf64_Sym. */ ++#define STO_ALPHA_NOPV 0x80 /* No PV required. */ ++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ ++ ++/* Alpha relocs. */ ++ ++#define R_ALPHA_NONE 0 /* No reloc */ ++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ ++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ ++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ ++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ ++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ ++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ ++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ ++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ ++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ ++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ ++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ ++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ ++#define R_ALPHA_TLS_GD_HI 28 ++#define R_ALPHA_TLSGD 29 ++#define R_ALPHA_TLS_LDM 30 ++#define R_ALPHA_DTPMOD64 31 ++#define R_ALPHA_GOTDTPREL 32 ++#define R_ALPHA_DTPREL64 33 ++#define R_ALPHA_DTPRELHI 34 ++#define R_ALPHA_DTPRELLO 35 ++#define R_ALPHA_DTPREL16 36 ++#define R_ALPHA_GOTTPREL 37 ++#define R_ALPHA_TPREL64 38 ++#define R_ALPHA_TPRELHI 39 ++#define R_ALPHA_TPRELLO 40 ++#define R_ALPHA_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_ALPHA_NUM 46 ++ ++/* Magic values of the LITUSE relocation addend. */ ++#define LITUSE_ALPHA_ADDR 0 ++#define LITUSE_ALPHA_BASE 1 ++#define LITUSE_ALPHA_BYTOFF 2 ++#define LITUSE_ALPHA_JSR 3 ++#define LITUSE_ALPHA_TLS_GD 4 ++#define LITUSE_ALPHA_TLS_LDM 5 ++ ++/* Legal values for d_tag of Elf64_Dyn. */ ++#define DT_ALPHA_PLTRO (DT_LOPROC + 0) ++#define DT_ALPHA_NUM 1 ++ ++/* PowerPC specific declarations */ ++ ++/* Values for Elf32/64_Ehdr.e_flags. */ ++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ ++ ++/* Cygnus local bits below */ ++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ ++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib ++ flag */ ++ ++/* PowerPC relocations defined by the ABIs */ ++#define R_PPC_NONE 0 ++#define R_PPC_ADDR32 1 /* 32bit absolute address */ ++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ ++#define R_PPC_ADDR16 3 /* 16bit absolute address */ ++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ ++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ ++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ ++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ ++#define R_PPC_ADDR14_BRTAKEN 8 ++#define R_PPC_ADDR14_BRNTAKEN 9 ++#define R_PPC_REL24 10 /* PC relative 26 bit */ ++#define R_PPC_REL14 11 /* PC relative 16 bit */ ++#define R_PPC_REL14_BRTAKEN 12 ++#define R_PPC_REL14_BRNTAKEN 13 ++#define R_PPC_GOT16 14 ++#define R_PPC_GOT16_LO 15 ++#define R_PPC_GOT16_HI 16 ++#define R_PPC_GOT16_HA 17 ++#define R_PPC_PLTREL24 18 ++#define R_PPC_COPY 19 ++#define R_PPC_GLOB_DAT 20 ++#define R_PPC_JMP_SLOT 21 ++#define R_PPC_RELATIVE 22 ++#define R_PPC_LOCAL24PC 23 ++#define R_PPC_UADDR32 24 ++#define R_PPC_UADDR16 25 ++#define R_PPC_REL32 26 ++#define R_PPC_PLT32 27 ++#define R_PPC_PLTREL32 28 ++#define R_PPC_PLT16_LO 29 ++#define R_PPC_PLT16_HI 30 ++#define R_PPC_PLT16_HA 31 ++#define R_PPC_SDAREL16 32 ++#define R_PPC_SECTOFF 33 ++#define R_PPC_SECTOFF_LO 34 ++#define R_PPC_SECTOFF_HI 35 ++#define R_PPC_SECTOFF_HA 36 ++ ++/* PowerPC relocations defined for the TLS access ABI. */ ++#define R_PPC_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ ++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ ++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ ++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ ++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ ++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ ++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ ++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ ++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ ++ ++/* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++#define R_PPC_EMB_NADDR32 101 ++#define R_PPC_EMB_NADDR16 102 ++#define R_PPC_EMB_NADDR16_LO 103 ++#define R_PPC_EMB_NADDR16_HI 104 ++#define R_PPC_EMB_NADDR16_HA 105 ++#define R_PPC_EMB_SDAI16 106 ++#define R_PPC_EMB_SDA2I16 107 ++#define R_PPC_EMB_SDA2REL 108 ++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ ++#define R_PPC_EMB_MRKREF 110 ++#define R_PPC_EMB_RELSEC16 111 ++#define R_PPC_EMB_RELST_LO 112 ++#define R_PPC_EMB_RELST_HI 113 ++#define R_PPC_EMB_RELST_HA 114 ++#define R_PPC_EMB_BIT_FLD 115 ++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ ++ ++/* Diab tool relocations. */ ++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ ++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ ++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ ++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ ++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ ++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC_IRELATIVE 248 ++ ++/* GNU relocs used in PIC code sequences. */ ++#define R_PPC_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* This is a phony reloc to handle any old fashioned TOC16 references ++ that may still be in object files. */ ++#define R_PPC_TOC16 255 ++ ++/* PowerPC specific values for the Dyn d_tag field. */ ++#define DT_PPC_GOT (DT_LOPROC + 0) ++#define DT_PPC_NUM 1 ++ ++/* PowerPC64 relocations defined by the ABIs */ ++#define R_PPC64_NONE R_PPC_NONE ++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ ++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ ++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ ++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ ++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ ++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ ++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ ++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN ++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN ++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ ++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ ++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN ++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN ++#define R_PPC64_GOT16 R_PPC_GOT16 ++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO ++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI ++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA ++ ++#define R_PPC64_COPY R_PPC_COPY ++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT ++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT ++#define R_PPC64_RELATIVE R_PPC_RELATIVE ++ ++#define R_PPC64_UADDR32 R_PPC_UADDR32 ++#define R_PPC64_UADDR16 R_PPC_UADDR16 ++#define R_PPC64_REL32 R_PPC_REL32 ++#define R_PPC64_PLT32 R_PPC_PLT32 ++#define R_PPC64_PLTREL32 R_PPC_PLTREL32 ++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO ++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI ++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA ++ ++#define R_PPC64_SECTOFF R_PPC_SECTOFF ++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO ++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI ++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA ++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ ++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ ++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ ++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ ++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ ++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ ++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ ++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ ++#define R_PPC64_PLT64 45 /* doubleword64 L + A */ ++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ ++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ ++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ ++#define R_PPC64_TOC 51 /* doubleword64 .TOC */ ++#define R_PPC64_PLTGOT16 52 /* half16* M + A */ ++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ ++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ ++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ ++ ++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ ++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ ++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ ++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ ++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ ++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ ++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ ++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ ++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ ++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ ++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ ++ ++/* PowerPC64 relocations defined for the TLS access ABI. */ ++#define R_PPC64_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ ++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ ++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ ++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ ++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ ++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ ++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ ++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ ++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ ++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ ++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ ++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ ++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ ++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ ++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ ++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ ++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC64_JMP_IREL 247 ++#define R_PPC64_IRELATIVE 248 ++#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* PowerPC64 specific values for the Dyn d_tag field. */ ++#define DT_PPC64_GLINK (DT_LOPROC + 0) ++#define DT_PPC64_OPD (DT_LOPROC + 1) ++#define DT_PPC64_OPDSZ (DT_LOPROC + 2) ++#define DT_PPC64_NUM 3 ++ ++ ++/* ARM specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_ARM_RELEXEC 0x01 ++#define EF_ARM_HASENTRY 0x02 ++#define EF_ARM_INTERWORK 0x04 ++#define EF_ARM_APCS_26 0x08 ++#define EF_ARM_APCS_FLOAT 0x10 ++#define EF_ARM_PIC 0x20 ++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ ++#define EF_ARM_NEW_ABI 0x80 ++#define EF_ARM_OLD_ABI 0x100 ++#define EF_ARM_SOFT_FLOAT 0x200 ++#define EF_ARM_VFP_FLOAT 0x400 ++#define EF_ARM_MAVERICK_FLOAT 0x800 ++ ++ ++/* Other constants defined in the ARM ELF spec. version B-01. */ ++/* NB. These conflict with values defined above. */ ++#define EF_ARM_SYMSARESORTED 0x04 ++#define EF_ARM_DYNSYMSUSESEGIDX 0x08 ++#define EF_ARM_MAPSYMSFIRST 0x10 ++#define EF_ARM_EABIMASK 0XFF000000 ++ ++/* Constants defined in AAELF. */ ++#define EF_ARM_BE8 0x00800000 ++#define EF_ARM_LE8 0x00400000 ++ ++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) ++#define EF_ARM_EABI_UNKNOWN 0x00000000 ++#define EF_ARM_EABI_VER1 0x01000000 ++#define EF_ARM_EABI_VER2 0x02000000 ++#define EF_ARM_EABI_VER3 0x03000000 ++#define EF_ARM_EABI_VER4 0x04000000 ++#define EF_ARM_EABI_VER5 0x05000000 ++ ++/* Additional symbol types for Thumb. */ ++#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ ++#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ ++ ++/* ARM-specific values for sh_flags */ ++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ ++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined ++ in the input to a link step. */ ++ ++/* ARM-specific program header flags */ ++#define PF_ARM_SB 0x10000000 /* Segment contains the location ++ addressed by the static base. */ ++#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ ++#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ ++#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ ++#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ ++ ++ ++/* ARM relocs. */ ++ ++#define R_ARM_NONE 0 /* No reloc */ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++#define R_ARM_REL32 3 /* PC relative 32 bit */ ++#define R_ARM_PC13 4 ++#define R_ARM_ABS16 5 /* Direct 16 bit */ ++#define R_ARM_ABS12 6 /* Direct 12 bit */ ++#define R_ARM_THM_ABS5 7 ++#define R_ARM_ABS8 8 /* Direct 8 bit */ ++#define R_ARM_SBREL32 9 ++#define R_ARM_THM_PC22 10 ++#define R_ARM_THM_PC8 11 ++#define R_ARM_AMP_VCALL9 12 ++#define R_ARM_SWI24 13 /* Obsolete static relocation. */ ++#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ ++#define R_ARM_THM_SWI8 14 ++#define R_ARM_XPC25 15 ++#define R_ARM_THM_XPC22 16 ++#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ ++#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ ++#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ ++#define R_ARM_COPY 20 /* Copy symbol at runtime */ ++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ ++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ ++#define R_ARM_RELATIVE 23 /* Adjust by program base */ ++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ ++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ ++#define R_ARM_GOT32 26 /* 32 bit GOT entry */ ++#define R_ARM_PLT32 27 /* 32 bit PLT address */ ++#define R_ARM_ALU_PCREL_7_0 32 ++#define R_ARM_ALU_PCREL_15_8 33 ++#define R_ARM_ALU_PCREL_23_15 34 ++#define R_ARM_LDR_SBREL_11_0 35 ++#define R_ARM_ALU_SBREL_19_12 36 ++#define R_ARM_ALU_SBREL_27_20 37 ++#define R_ARM_TLS_GOTDESC 90 ++#define R_ARM_TLS_CALL 91 ++#define R_ARM_TLS_DESCSEQ 92 ++#define R_ARM_THM_TLS_CALL 93 ++#define R_ARM_GNU_VTENTRY 100 ++#define R_ARM_GNU_VTINHERIT 101 ++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ ++#define R_ARM_THM_PC9 103 /* thumb conditional branch */ ++#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic ++ thread local data */ ++#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic ++ thread local data */ ++#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS ++ block */ ++#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of ++ static TLS block offset */ ++#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static ++ TLS block */ ++#define R_ARM_THM_TLS_DESCSEQ 129 ++#define R_ARM_IRELATIVE 160 ++#define R_ARM_RXPC25 249 ++#define R_ARM_RSBREL32 250 ++#define R_ARM_THM_RPC22 251 ++#define R_ARM_RREL32 252 ++#define R_ARM_RABS22 253 ++#define R_ARM_RPC24 254 ++#define R_ARM_RBASE 255 ++/* Keep this the last entry. */ ++#define R_ARM_NUM 256 ++ ++/* IA-64 specific declarations. */ ++ ++/* Processor specific flags for the Ehdr e_flags field. */ ++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ ++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ ++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ ++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ ++#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) ++#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) ++#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) ++ ++/* Processor specific flags for the Phdr p_flags field. */ ++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ ++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ ++ ++/* Processor specific flags for the Shdr sh_flags field. */ ++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ ++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Dyn d_tag field. */ ++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) ++#define DT_IA_64_NUM 1 ++ ++/* IA-64 relocations. */ ++#define R_IA64_NONE 0x00 /* none */ ++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ ++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ ++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ ++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ ++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ ++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ ++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ ++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ ++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ ++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ ++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ ++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ ++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ ++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ ++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ ++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ ++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ ++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ ++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ ++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ ++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ ++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ ++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ ++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ ++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ ++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ ++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ ++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ ++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ ++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ ++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ ++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ ++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ ++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ ++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ ++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ ++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ ++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ ++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ ++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ ++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ ++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ ++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ ++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ ++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ ++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ ++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ ++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ ++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ ++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ ++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ ++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ ++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ ++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ ++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ ++#define R_IA64_COPY 0x84 /* copy relocation */ ++#define R_IA64_SUB 0x85 /* Addend and symbol difference */ ++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ ++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ ++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ ++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ ++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ ++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ ++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ ++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ ++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ ++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ ++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ ++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ ++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ ++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ ++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ ++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ ++ ++/* SH specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_SH_MACH_MASK 0x1f ++#define EF_SH_UNKNOWN 0x0 ++#define EF_SH1 0x1 ++#define EF_SH2 0x2 ++#define EF_SH3 0x3 ++#define EF_SH_DSP 0x4 ++#define EF_SH3_DSP 0x5 ++#define EF_SH4AL_DSP 0x6 ++#define EF_SH3E 0x8 ++#define EF_SH4 0x9 ++#define EF_SH2E 0xb ++#define EF_SH4A 0xc ++#define EF_SH2A 0xd ++#define EF_SH4_NOFPU 0x10 ++#define EF_SH4A_NOFPU 0x11 ++#define EF_SH4_NOMMU_NOFPU 0x12 ++#define EF_SH2A_NOFPU 0x13 ++#define EF_SH3_NOMMU 0x14 ++#define EF_SH2A_SH4_NOFPU 0x15 ++#define EF_SH2A_SH3_NOFPU 0x16 ++#define EF_SH2A_SH4 0x17 ++#define EF_SH2A_SH3E 0x18 ++ ++/* SH relocs. */ ++#define R_SH_NONE 0 ++#define R_SH_DIR32 1 ++#define R_SH_REL32 2 ++#define R_SH_DIR8WPN 3 ++#define R_SH_IND12W 4 ++#define R_SH_DIR8WPL 5 ++#define R_SH_DIR8WPZ 6 ++#define R_SH_DIR8BP 7 ++#define R_SH_DIR8W 8 ++#define R_SH_DIR8L 9 ++#define R_SH_SWITCH16 25 ++#define R_SH_SWITCH32 26 ++#define R_SH_USES 27 ++#define R_SH_COUNT 28 ++#define R_SH_ALIGN 29 ++#define R_SH_CODE 30 ++#define R_SH_DATA 31 ++#define R_SH_LABEL 32 ++#define R_SH_SWITCH8 33 ++#define R_SH_GNU_VTINHERIT 34 ++#define R_SH_GNU_VTENTRY 35 ++#define R_SH_TLS_GD_32 144 ++#define R_SH_TLS_LD_32 145 ++#define R_SH_TLS_LDO_32 146 ++#define R_SH_TLS_IE_32 147 ++#define R_SH_TLS_LE_32 148 ++#define R_SH_TLS_DTPMOD32 149 ++#define R_SH_TLS_DTPOFF32 150 ++#define R_SH_TLS_TPOFF32 151 ++#define R_SH_GOT32 160 ++#define R_SH_PLT32 161 ++#define R_SH_COPY 162 ++#define R_SH_GLOB_DAT 163 ++#define R_SH_JMP_SLOT 164 ++#define R_SH_RELATIVE 165 ++#define R_SH_GOTOFF 166 ++#define R_SH_GOTPC 167 ++/* Keep this the last entry. */ ++#define R_SH_NUM 256 ++ ++/* S/390 specific definitions. */ ++ ++/* Valid values for the e_flags field. */ ++ ++#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ ++ ++/* Additional s390 relocs */ ++ ++#define R_390_NONE 0 /* No reloc. */ ++#define R_390_8 1 /* Direct 8 bit. */ ++#define R_390_12 2 /* Direct 12 bit. */ ++#define R_390_16 3 /* Direct 16 bit. */ ++#define R_390_32 4 /* Direct 32 bit. */ ++#define R_390_PC32 5 /* PC relative 32 bit. */ ++#define R_390_GOT12 6 /* 12 bit GOT offset. */ ++#define R_390_GOT32 7 /* 32 bit GOT offset. */ ++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ ++#define R_390_COPY 9 /* Copy symbol at runtime. */ ++#define R_390_GLOB_DAT 10 /* Create GOT entry. */ ++#define R_390_JMP_SLOT 11 /* Create PLT entry. */ ++#define R_390_RELATIVE 12 /* Adjust by program base. */ ++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ ++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ ++#define R_390_GOT16 15 /* 16 bit GOT offset. */ ++#define R_390_PC16 16 /* PC relative 16 bit. */ ++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ ++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ ++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ ++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ ++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ ++#define R_390_64 22 /* Direct 64 bit. */ ++#define R_390_PC64 23 /* PC relative 64 bit. */ ++#define R_390_GOT64 24 /* 64 bit GOT offset. */ ++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ ++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ ++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ ++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ ++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ ++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ ++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ ++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ ++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ ++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ ++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ ++#define R_390_TLS_GDCALL 38 /* Tag for function call in general ++ dynamic TLS code. */ ++#define R_390_TLS_LDCALL 39 /* Tag for function call in local ++ dynamic TLS code. */ ++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ ++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ ++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS ++ block. */ ++#define R_390_20 57 /* Direct 20 bit. */ ++#define R_390_GOT20 58 /* 20 bit GOT offset. */ ++#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ ++#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ ++/* Keep this the last entry. */ ++#define R_390_NUM 62 ++ ++ ++/* CRIS relocations. */ ++#define R_CRIS_NONE 0 ++#define R_CRIS_8 1 ++#define R_CRIS_16 2 ++#define R_CRIS_32 3 ++#define R_CRIS_8_PCREL 4 ++#define R_CRIS_16_PCREL 5 ++#define R_CRIS_32_PCREL 6 ++#define R_CRIS_GNU_VTINHERIT 7 ++#define R_CRIS_GNU_VTENTRY 8 ++#define R_CRIS_COPY 9 ++#define R_CRIS_GLOB_DAT 10 ++#define R_CRIS_JUMP_SLOT 11 ++#define R_CRIS_RELATIVE 12 ++#define R_CRIS_16_GOT 13 ++#define R_CRIS_32_GOT 14 ++#define R_CRIS_16_GOTPLT 15 ++#define R_CRIS_32_GOTPLT 16 ++#define R_CRIS_32_GOTREL 17 ++#define R_CRIS_32_PLT_GOTREL 18 ++#define R_CRIS_32_PLT_PCREL 19 ++ ++#define R_CRIS_NUM 20 ++ ++ ++/* AMD x86-64 relocations. */ ++#define R_X86_64_NONE 0 /* No reloc */ ++#define R_X86_64_64 1 /* Direct 64 bit */ ++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ ++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ ++#define R_X86_64_PLT32 4 /* 32 bit PLT address */ ++#define R_X86_64_COPY 5 /* Copy symbol at runtime */ ++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ ++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ ++#define R_X86_64_RELATIVE 8 /* Adjust by program base */ ++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative ++ offset to GOT */ ++#define R_X86_64_32 10 /* Direct 32 bit zero extended */ ++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ ++#define R_X86_64_16 12 /* Direct 16 bit zero extended */ ++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ ++#define R_X86_64_8 14 /* Direct 8 bit sign extended */ ++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ ++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ ++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ ++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ ++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset ++ to two GOT entries for GD symbol */ ++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset ++ to two GOT entries for LD symbol */ ++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ ++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset ++ to GOT entry for IE symbol */ ++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ ++#define R_X86_64_PC64 24 /* PC relative 64 bit */ ++#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ ++#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative ++ offset to GOT */ ++#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ ++#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset ++ to GOT entry */ ++#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ ++#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ ++#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset ++ to PLT entry */ ++#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ ++#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ ++#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ ++#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS ++ descriptor. */ ++#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ ++#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ ++#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ ++ ++#define R_X86_64_NUM 39 ++ ++ ++/* AM33 relocations. */ ++#define R_MN10300_NONE 0 /* No reloc. */ ++#define R_MN10300_32 1 /* Direct 32 bit. */ ++#define R_MN10300_16 2 /* Direct 16 bit. */ ++#define R_MN10300_8 3 /* Direct 8 bit. */ ++#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ ++#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ ++#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ ++#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ ++#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ ++#define R_MN10300_24 9 /* Direct 24 bit. */ ++#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ ++#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ ++#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ ++#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ ++#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ ++#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ ++#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ ++#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ ++#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ ++#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ ++#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ ++#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ ++ ++#define R_MN10300_NUM 24 ++ ++ ++/* M32R relocs. */ ++#define R_M32R_NONE 0 /* No reloc. */ ++#define R_M32R_16 1 /* Direct 16 bit. */ ++#define R_M32R_32 2 /* Direct 32 bit. */ ++#define R_M32R_24 3 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ ++#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ ++#define R_M32R_LO16 9 /* Low 16 bit. */ ++#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ ++#define R_M32R_GNU_VTINHERIT 11 ++#define R_M32R_GNU_VTENTRY 12 ++/* M32R relocs use SHT_RELA. */ ++#define R_M32R_16_RELA 33 /* Direct 16 bit. */ ++#define R_M32R_32_RELA 34 /* Direct 32 bit. */ ++#define R_M32R_24_RELA 35 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ ++#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ ++#define R_M32R_LO16_RELA 41 /* Low 16 bit */ ++#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ ++#define R_M32R_RELA_GNU_VTINHERIT 43 ++#define R_M32R_RELA_GNU_VTENTRY 44 ++#define R_M32R_REL32 45 /* PC relative 32 bit. */ ++ ++#define R_M32R_GOT24 48 /* 24 bit GOT entry */ ++#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ ++#define R_M32R_COPY 50 /* Copy symbol at runtime */ ++#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ ++#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ ++#define R_M32R_RELATIVE 53 /* Adjust by program base */ ++#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ ++#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ ++#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned ++ low */ ++#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed ++ low */ ++#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ ++#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to ++ GOT with unsigned low */ ++#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to ++ GOT with signed low */ ++#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to ++ GOT */ ++#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT ++ with unsigned low */ ++#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT ++ with signed low */ ++#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ ++#define R_M32R_NUM 256 /* Keep this the last entry. */ ++ ++ ++/* TILEPro relocations. */ ++#define R_TILEPRO_NONE 0 /* No reloc */ ++#define R_TILEPRO_32 1 /* Direct 32 bit */ ++#define R_TILEPRO_16 2 /* Direct 16 bit */ ++#define R_TILEPRO_8 3 /* Direct 8 bit */ ++#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ ++#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ ++#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ ++#define R_TILEPRO_LO16 7 /* Low 16 bit */ ++#define R_TILEPRO_HI16 8 /* High 16 bit */ ++#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ ++#define R_TILEPRO_COPY 10 /* Copy relocation */ ++#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ ++#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ ++#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ ++#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ ++#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ ++#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ ++#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ ++#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ ++#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ ++#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ ++#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ ++#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ ++#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ ++/* Relocs 56-59 are currently not defined. */ ++#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ ++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ ++#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ ++#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ ++#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ ++#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ ++ ++#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEPRO_NUM 130 ++ ++ ++/* TILE-Gx relocations. */ ++#define R_TILEGX_NONE 0 /* No reloc */ ++#define R_TILEGX_64 1 /* Direct 64 bit */ ++#define R_TILEGX_32 2 /* Direct 32 bit */ ++#define R_TILEGX_16 3 /* Direct 16 bit */ ++#define R_TILEGX_8 4 /* Direct 8 bit */ ++#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ ++#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ ++#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ ++#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ ++#define R_TILEGX_HW0 9 /* hword 0 16-bit */ ++#define R_TILEGX_HW1 10 /* hword 1 16-bit */ ++#define R_TILEGX_HW2 11 /* hword 2 16-bit */ ++#define R_TILEGX_HW3 12 /* hword 3 16-bit */ ++#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ ++#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ ++#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ ++#define R_TILEGX_COPY 16 /* Copy relocation */ ++#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ ++#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ ++#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ ++#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ ++#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ ++#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ ++#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ ++#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ ++#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ ++#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ ++#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ ++#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ ++#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ ++#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ ++#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ ++#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ ++/* Relocs 66-71 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ ++/* Relocs 76-77 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ ++/* Relocs 90-91 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ ++/* Relocs 94-99 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ ++/* Relocs 104-105 are currently not defined. */ ++#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ ++#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ ++#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ ++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ ++#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ ++ ++#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEGX_NUM 130 ++ ++#endif /* elf.h */ +--- a/scripts/mod/mk_elfconfig.c ++++ b/scripts/mod/mk_elfconfig.c +@@ -2,7 +2,11 @@ + #include + #include + #include ++#ifndef __APPLE__ + #include ++#else ++#include "elf.h" ++#endif + + int + main(int argc, char **argv) +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -8,7 +8,11 @@ + #include + #include + #include ++#if !(defined(__APPLE__) || defined(__CYGWIN__)) + #include ++#else ++#include "elf.h" ++#endif + + #include "elfconfig.h" + diff --git a/ipq806x/hack-5.4/211-darwin-uuid-typedef-clash.patch b/ipq806x/hack-5.4/211-darwin-uuid-typedef-clash.patch new file mode 100644 index 0000000..50a6227 --- /dev/null +++ b/ipq806x/hack-5.4/211-darwin-uuid-typedef-clash.patch @@ -0,0 +1,22 @@ +From e44fc2af1ddc452b6659d08c16973d65c73b7d0a Mon Sep 17 00:00:00 2001 +From: Kevin Darbyshire-Bryant +Date: Wed, 5 Feb 2020 18:36:43 +0000 +Subject: [PATCH] file2alias: build on macos + +Signed-off-by: Kevin Darbyshire-Bryant +--- + scripts/mod/file2alias.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -38,6 +38,9 @@ typedef struct { + __u8 b[16]; + } guid_t; + ++#ifdef __APPLE__ ++#define uuid_t compat_uuid_t ++#endif + /* backwards compatibility, don't use in new code */ + typedef struct { + __u8 b[16]; diff --git a/ipq806x/hack-5.4/212-tools_portability.patch b/ipq806x/hack-5.4/212-tools_portability.patch new file mode 100644 index 0000000..0d8eb6f --- /dev/null +++ b/ipq806x/hack-5.4/212-tools_portability.patch @@ -0,0 +1,110 @@ +From 48232d3d931c95953ce2ddfe7da7bb164aef6a73 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:03:16 +0200 +Subject: fix portability of some includes files in tools/ used on the host + +Signed-off-by: Felix Fietkau +--- + tools/include/tools/be_byteshift.h | 4 ++++ + tools/include/tools/le_byteshift.h | 4 ++++ + tools/include/tools/linux_types.h | 22 ++++++++++++++++++++++ + 3 files changed, 30 insertions(+) + create mode 100644 tools/include/tools/linux_types.h + +--- a/tools/include/tools/be_byteshift.h ++++ b/tools/include/tools/be_byteshift.h +@@ -2,6 +2,10 @@ + #ifndef _TOOLS_BE_BYTESHIFT_H + #define _TOOLS_BE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_be16(const uint8_t *p) +--- a/tools/include/tools/le_byteshift.h ++++ b/tools/include/tools/le_byteshift.h +@@ -2,6 +2,10 @@ + #ifndef _TOOLS_LE_BYTESHIFT_H + #define _TOOLS_LE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_le16(const uint8_t *p) +--- /dev/null ++++ b/tools/include/tools/linux_types.h +@@ -0,0 +1,26 @@ ++#ifndef __LINUX_TYPES_H ++#define __LINUX_TYPES_H ++ ++#include ++ ++typedef int8_t __s8; ++typedef uint8_t __u8; ++typedef uint8_t __be8; ++typedef uint8_t __le8; ++ ++typedef int16_t __s16; ++typedef uint16_t __u16; ++typedef uint16_t __be16; ++typedef uint16_t __le16; ++ ++typedef int32_t __s32; ++typedef uint32_t __u32; ++typedef uint32_t __be32; ++typedef uint32_t __le32; ++ ++typedef int64_t __s64; ++typedef uint64_t __u64; ++typedef uint64_t __be64; ++typedef uint64_t __le64; ++ ++#endif +--- a/tools/include/linux/types.h ++++ b/tools/include/linux/types.h +@@ -7,8 +7,12 @@ + #include + + #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ ++#ifndef __linux__ ++#include ++#else + #include + #include ++#endif + + struct page; + struct kmem_cache; +--- a/tools/perf/pmu-events/jevents.c ++++ b/tools/perf/pmu-events/jevents.c +@@ -1,4 +1,6 @@ ++#ifdef __linux__ + #define _XOPEN_SOURCE 500 /* needed for nftw() */ ++#endif + #define _GNU_SOURCE /* needed for asprintf() */ + + /* Parse event JSON files */ +@@ -35,6 +37,7 @@ + #include + #include + #include ++#include + #include + #include + #include +--- a/tools/perf/pmu-events/json.c ++++ b/tools/perf/pmu-events/json.c +@@ -38,7 +38,6 @@ + #include + #include "jsmn.h" + #include "json.h" +-#include + + + static char *mapfile(const char *fn, size_t *size) diff --git a/ipq806x/hack-5.4/214-spidev_h_portability.patch b/ipq806x/hack-5.4/214-spidev_h_portability.patch new file mode 100644 index 0000000..415e9a4 --- /dev/null +++ b/ipq806x/hack-5.4/214-spidev_h_portability.patch @@ -0,0 +1,24 @@ +From be9be95ff10e16a5b4ad36f903978d0cc5747024 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:04:08 +0200 +Subject: kernel: fix linux/spi/spidev.h portability issues with musl + +Felix will try to get this define included into musl + +lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/spi/spidev.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/uapi/linux/spi/spidev.h ++++ b/include/uapi/linux/spi/spidev.h +@@ -117,7 +117,7 @@ struct spi_ioc_transfer { + + /* not all platforms use or _IOC_TYPECHECK() ... */ + #define SPI_MSGSIZE(N) \ +- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ ++ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \ + ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) + #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) + diff --git a/ipq806x/hack-5.4/220-gc_sections.patch b/ipq806x/hack-5.4/220-gc_sections.patch new file mode 100644 index 0000000..fdfaf51 --- /dev/null +++ b/ipq806x/hack-5.4/220-gc_sections.patch @@ -0,0 +1,136 @@ +From e3d8676f5722b7622685581e06e8f53e6138e3ab Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 15 Jul 2017 23:42:36 +0200 +Subject: use -ffunction-sections, -fdata-sections and --gc-sections + +In combination with kernel symbol export stripping this significantly reduces +the kernel image size. Used on both ARM and MIPS architectures. + +Signed-off-by: Felix Fietkau +Signed-off-by: Jonas Gorski +Signed-off-by: Gabor Juhos +--- + Makefile | 10 +++---- + arch/arm/Kconfig | 1 + + arch/arm/boot/compressed/Makefile | 1 + + arch/arm/kernel/vmlinux.lds.S | 26 ++++++++-------- + arch/mips/Kconfig | 1 + + arch/mips/kernel/vmlinux.lds.S | 4 +-- + include/asm-generic/vmlinux.lds.h | 63 ++++++++++++++++++++------------------- + 7 files changed, 55 insertions(+), 51 deletions(-) + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -112,6 +112,7 @@ config ARM + select HAVE_UID16 + select HAVE_VIRT_CPU_ACCOUNTING_GEN + select IRQ_FORCED_THREADING ++ select HAVE_LD_DEAD_CODE_DATA_ELIMINATION + select MODULES_USE_ELF_REL + select NEED_DMA_MAP_STATE + select OF_EARLY_FLATTREE if OF +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -108,6 +108,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y) + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) + endif ++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL)) + + # -fstack-protector-strong triggers protection checks in this code, + # but it is being used too early to link to meaningful stack_chk logic. +--- a/arch/arm/kernel/vmlinux.lds.S ++++ b/arch/arm/kernel/vmlinux.lds.S +@@ -100,24 +100,24 @@ SECTIONS + } + .init.arch.info : { + __arch_info_begin = .; +- *(.arch.info.init) ++ KEEP(*(.arch.info.init)) + __arch_info_end = .; + } + .init.tagtable : { + __tagtable_begin = .; +- *(.taglist.init) ++ KEEP(*(.taglist.init)) + __tagtable_end = .; + } + #ifdef CONFIG_SMP_ON_UP + .init.smpalt : { + __smpalt_begin = .; +- *(.alt.smp.init) ++ KEEP(*(.alt.smp.init)) + __smpalt_end = .; + } + #endif + .init.pv_table : { + __pv_table_begin = .; +- *(.pv_table) ++ KEEP(*(.pv_table)) + __pv_table_end = .; + } + +--- a/arch/arm/kernel/vmlinux.lds.h ++++ b/arch/arm/kernel/vmlinux.lds.h +@@ -22,13 +22,13 @@ + #define ARM_MMU_DISCARD(x) + #else + #define ARM_MMU_KEEP(x) +-#define ARM_MMU_DISCARD(x) x ++#define ARM_MMU_DISCARD(x) KEEP(x) + #endif + + #define PROC_INFO \ + . = ALIGN(4); \ + __proc_info_begin = .; \ +- *(.proc.info.init) \ ++ KEEP(*(.proc.info.init)) \ + __proc_info_end = .; + + #define HYPERVISOR_TEXT \ +@@ -39,11 +39,11 @@ + #define IDMAP_TEXT \ + ALIGN_FUNCTION(); \ + __idmap_text_start = .; \ +- *(.idmap.text) \ ++ KEEP(*(.idmap.text)) \ + __idmap_text_end = .; \ + . = ALIGN(PAGE_SIZE); \ + __hyp_idmap_text_start = .; \ +- *(.hyp.idmap.text) \ ++ KEEP(*(.hyp.idmap.text)) \ + __hyp_idmap_text_end = .; + + #define ARM_DISCARD \ +@@ -86,12 +86,12 @@ + . = ALIGN(8); \ + .ARM.unwind_idx : { \ + __start_unwind_idx = .; \ +- *(.ARM.exidx*) \ ++ KEEP(*(.ARM.exidx*)) \ + __stop_unwind_idx = .; \ + } \ + .ARM.unwind_tab : { \ + __start_unwind_tab = .; \ +- *(.ARM.extab*) \ ++ KEEP(*(.ARM.extab*)) \ + __stop_unwind_tab = .; \ + } + +@@ -102,14 +102,14 @@ + #define ARM_VECTORS \ + __vectors_start = .; \ + .vectors 0xffff0000 : AT(__vectors_start) { \ +- *(.vectors) \ ++ KEEP(*(.vectors)) \ + } \ + . = __vectors_start + SIZEOF(.vectors); \ + __vectors_end = .; \ + \ + __stubs_start = .; \ + .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) { \ +- *(.stubs) \ ++ KEEP(*(.stubs)) \ + } \ + . = __stubs_start + SIZEOF(.stubs); \ + __stubs_end = .; \ diff --git a/ipq806x/hack-5.4/221-module_exports.patch b/ipq806x/hack-5.4/221-module_exports.patch new file mode 100644 index 0000000..47f40ac --- /dev/null +++ b/ipq806x/hack-5.4/221-module_exports.patch @@ -0,0 +1,109 @@ +From b14784e7883390c20ed3ff904892255404a5914b Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:05:53 +0200 +Subject: add an optional config option for stripping all unnecessary symbol exports from the kernel image + +lede-commit: bb5a40c64b7c4f4848509fa0a6625055fc9e66cc +Signed-off-by: Felix Fietkau +--- + include/asm-generic/vmlinux.lds.h | 18 +++++++++++++++--- + include/linux/export.h | 9 ++++++++- + scripts/Makefile.build | 2 +- + 3 files changed, 24 insertions(+), 5 deletions(-) + +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -54,6 +54,16 @@ + #define LOAD_OFFSET 0 + #endif + ++#ifndef SYMTAB_KEEP ++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*))) ++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*))) ++#endif ++ ++#ifndef SYMTAB_DISCARD ++#define SYMTAB_DISCARD ++#define SYMTAB_DISCARD_GPL ++#endif ++ + /* Align . to a 8 byte boundary equals to maximum function alignment. */ + #define ALIGN_FUNCTION() . = ALIGN(8) + +@@ -407,14 +417,14 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + __start___ksymtab = .; \ +- KEEP(*(SORT(___ksymtab+*))) \ ++ SYMTAB_KEEP \ + __stop___ksymtab = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + __start___ksymtab_gpl = .; \ +- KEEP(*(SORT(___ksymtab_gpl+*))) \ ++ SYMTAB_KEEP_GPL \ + __stop___ksymtab_gpl = .; \ + } \ + \ +@@ -476,7 +486,7 @@ + \ + /* Kernel symbol table: strings */ \ + __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ +- *(__ksymtab_strings) \ ++ *(__ksymtab_strings+*) \ + } \ + \ + /* __*init sections */ \ +@@ -905,6 +915,8 @@ + EXIT_TEXT \ + EXIT_DATA \ + EXIT_CALL \ ++ SYMTAB_DISCARD \ ++ SYMTAB_DISCARD_GPL \ + *(.discard) \ + *(.discard.*) \ + *(.modinfo) \ +--- a/include/linux/export.h ++++ b/include/linux/export.h +@@ -98,18 +98,26 @@ struct kernel_symbol { + + #else + ++#ifdef MODULE ++#define __EXPORT_SUFFIX(sym) ++#else ++#define __EXPORT_SUFFIX(sym) "+" #sym ++#endif ++ + #define ___export_symbol_common(sym, sec) \ + extern typeof(sym) sym; \ + __CRC_SYMBOL(sym, sec); \ + static const char __kstrtab_##sym[] \ +- __attribute__((section("__ksymtab_strings"), used, aligned(1))) \ ++ __attribute__((section("__ksymtab_strings" \ ++ __EXPORT_SUFFIX(sym)), used, aligned(1))) \ + = #sym \ + + /* For every exported symbol, place a struct in the __ksymtab section */ + #define ___EXPORT_SYMBOL_NS(sym, sec, ns) \ + ___export_symbol_common(sym, sec); \ + static const char __kstrtabns_##sym[] \ +- __attribute__((section("__ksymtab_strings"), used, aligned(1))) \ ++ __attribute__((section("__ksymtab_strings" \ ++ __EXPORT_SUFFIX(sym)), used, aligned(1))) \ + = #ns; \ + __KSYMTAB_ENTRY_NS(sym, sec) + +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -350,7 +350,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $( + # Linker scripts preprocessor (.lds.S -> .lds) + # --------------------------------------------------------------------------- + quiet_cmd_cpp_lds_S = LDS $@ +- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -U$(ARCH) \ ++ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -U$(ARCH) \ + -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< + + $(obj)/%.lds: $(src)/%.lds.S FORCE diff --git a/ipq806x/hack-5.4/230-openwrt_lzma_options.patch b/ipq806x/hack-5.4/230-openwrt_lzma_options.patch new file mode 100644 index 0000000..809ccbc --- /dev/null +++ b/ipq806x/hack-5.4/230-openwrt_lzma_options.patch @@ -0,0 +1,71 @@ +From b3d00b452467f621317953d9e4c6f9ae8dcfd271 Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Fri, 7 Jul 2017 17:06:55 +0200 +Subject: use the openwrt lzma options for now + +lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c +Signed-off-by: Imre Kaloz +--- + lib/decompress.c | 1 + + scripts/Makefile.lib | 2 +- + usr/gen_initramfs_list.sh | 10 +++++----- + 3 files changed, 7 insertions(+), 6 deletions(-) + +--- a/lib/decompress.c ++++ b/lib/decompress.c +@@ -49,6 +49,7 @@ static const struct compress_format comp + { {0x1f, 0x9e}, "gzip", gunzip }, + { {0x42, 0x5a}, "bzip2", bunzip2 }, + { {0x5d, 0x00}, "lzma", unlzma }, ++ { {0x6d, 0x00}, "lzma-openwrt", unlzma }, + { {0xfd, 0x37}, "xz", unxz }, + { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -328,7 +328,7 @@ quiet_cmd_bzip2 = BZIP2 $@ + # --------------------------------------------------------------------------- + + quiet_cmd_lzma = LZMA $@ +- cmd_lzma = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ ++ cmd_lzma = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@ + + quiet_cmd_lzo = LZO $@ + cmd_lzo = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@ +--- a/usr/gen_initramfs_list.sh ++++ b/usr/gen_initramfs_list.sh +@@ -229,7 +229,7 @@ cpio_list= + output="/dev/stdout" + output_file="" + is_cpio_compressed= +-compr="gzip -n -9 -f" ++compr="gzip -n -9 -f -" + + arg="$1" + case "$arg" in +@@ -245,13 +245,13 @@ case "$arg" in + output=${cpio_list} + echo "$output_file" | grep -q "\.gz$" \ + && [ -x "`which gzip 2> /dev/null`" ] \ +- && compr="gzip -n -9 -f" ++ && compr="gzip -n -9 -f -" + echo "$output_file" | grep -q "\.bz2$" \ + && [ -x "`which bzip2 2> /dev/null`" ] \ +- && compr="bzip2 -9 -f" ++ && compr="bzip2 -9 -f -" + echo "$output_file" | grep -q "\.lzma$" \ + && [ -x "`which lzma 2> /dev/null`" ] \ +- && compr="lzma -9 -f" ++ && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so" + echo "$output_file" | grep -q "\.xz$" \ + && [ -x "`which xz 2> /dev/null`" ] \ + && compr="xz --check=crc32 --lzma2=dict=1MiB" +@@ -320,7 +320,7 @@ if [ ! -z ${output_file} ]; then + if [ "${is_cpio_compressed}" = "compressed" ]; then + cat ${cpio_tfile} > ${output_file} + else +- (cat ${cpio_tfile} | ${compr} - > ${output_file}) \ ++ (cat ${cpio_tfile} | ${compr} > ${output_file}) \ + || (rm -f ${output_file} ; false) + fi + [ -z ${cpio_file} ] && rm ${cpio_tfile} diff --git a/ipq806x/hack-5.4/249-udp-tunnel-selection.patch b/ipq806x/hack-5.4/249-udp-tunnel-selection.patch new file mode 100644 index 0000000..2c74298 --- /dev/null +++ b/ipq806x/hack-5.4/249-udp-tunnel-selection.patch @@ -0,0 +1,11 @@ +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -315,7 +315,7 @@ config NET_IPVTI + on top. + + config NET_UDP_TUNNEL +- tristate ++ tristate "IP: UDP tunneling support" + select NET_IP_TUNNEL + default n + diff --git a/ipq806x/hack-5.4/250-netfilter_depends.patch b/ipq806x/hack-5.4/250-netfilter_depends.patch new file mode 100644 index 0000000..d03cb53 --- /dev/null +++ b/ipq806x/hack-5.4/250-netfilter_depends.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau +Subject: hack: net: remove bogus netfilter dependencies + +lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6 +Signed-off-by: Felix Fietkau +--- + net/netfilter/Kconfig | 2 -- + 1 file changed, 2 deletions(-) + +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -228,7 +228,6 @@ config NF_CONNTRACK_FTP + + config NF_CONNTRACK_H323 + tristate "H.323 protocol support" +- depends on IPV6 || IPV6=n + depends on NETFILTER_ADVANCED + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most +@@ -1088,7 +1087,6 @@ config NETFILTER_XT_TARGET_SECMARK + + config NETFILTER_XT_TARGET_TCPMSS + tristate '"TCPMSS" target support' +- depends on IPV6 || IPV6=n + default m if NETFILTER_ADVANCED=n + ---help--- + This option adds a `TCPMSS' target, which allows you to alter the diff --git a/ipq806x/hack-5.4/251-sound_kconfig.patch b/ipq806x/hack-5.4/251-sound_kconfig.patch new file mode 100644 index 0000000..f593417 --- /dev/null +++ b/ipq806x/hack-5.4/251-sound_kconfig.patch @@ -0,0 +1,199 @@ +From da3c50704f14132f4adf80d48e9a4cd5d46e54c9 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 7 Jul 2017 17:09:21 +0200 +Subject: kconfig: owrt specifc dependencies + +Signed-off-by: John Crispin +--- + crypto/Kconfig | 10 +++++----- + drivers/bcma/Kconfig | 1 + + drivers/ssb/Kconfig | 3 ++- + lib/Kconfig | 8 ++++---- + net/netfilter/Kconfig | 2 +- + net/wireless/Kconfig | 17 ++++++++++------- + sound/core/Kconfig | 4 ++-- + 7 files changed, 25 insertions(+), 20 deletions(-) + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -33,7 +33,7 @@ config CRYPTO_FIPS + this is. + + config CRYPTO_ALGAPI +- tristate ++ tristate "ALGAPI" + select CRYPTO_ALGAPI2 + help + This option provides the API for cryptographic algorithms. +@@ -42,7 +42,7 @@ config CRYPTO_ALGAPI2 + tristate + + config CRYPTO_AEAD +- tristate ++ tristate "AEAD" + select CRYPTO_AEAD2 + select CRYPTO_ALGAPI + +@@ -53,7 +53,7 @@ config CRYPTO_AEAD2 + select CRYPTO_RNG2 + + config CRYPTO_BLKCIPHER +- tristate ++ tristate "BLKCIPHER" + select CRYPTO_BLKCIPHER2 + select CRYPTO_ALGAPI + +@@ -63,7 +63,7 @@ config CRYPTO_BLKCIPHER2 + select CRYPTO_RNG2 + + config CRYPTO_HASH +- tristate ++ tristate "HASH" + select CRYPTO_HASH2 + select CRYPTO_ALGAPI + +@@ -72,7 +72,7 @@ config CRYPTO_HASH2 + select CRYPTO_ALGAPI2 + + config CRYPTO_RNG +- tristate ++ tristate "RNG" + select CRYPTO_RNG2 + select CRYPTO_ALGAPI + +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -16,6 +16,7 @@ if BCMA + # Support for Block-I/O. SELECT this from the driver that needs it. + config BCMA_BLOCKIO + bool ++ default y + + config BCMA_HOST_PCI_POSSIBLE + bool +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -29,6 +29,7 @@ config SSB_SPROM + config SSB_BLOCKIO + bool + depends on SSB ++ default y + + config SSB_PCIHOST_POSSIBLE + bool +@@ -49,7 +50,7 @@ config SSB_PCIHOST + config SSB_B43_PCI_BRIDGE + bool + depends on SSB_PCIHOST +- default n ++ default y + + config SSB_PCMCIAHOST_POSSIBLE + bool +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -402,16 +402,16 @@ config BCH_CONST_T + # Textsearch support is select'ed if needed + # + config TEXTSEARCH +- bool ++ bool "Textsearch support" + + config TEXTSEARCH_KMP +- tristate ++ tristate "Textsearch KMP" + + config TEXTSEARCH_BM +- tristate ++ tristate "Textsearch BM" + + config TEXTSEARCH_FSM +- tristate ++ tristate "Textsearch FSM" + + config BTREE + bool +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -11,7 +11,7 @@ config NETFILTER_INGRESS + infrastructure. + + config NETFILTER_NETLINK +- tristate ++ tristate "Netfilter NFNETLINK interface" + + config NETFILTER_FAMILY_BRIDGE + bool +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0-only + config WIRELESS_EXT +- bool ++ bool "Wireless extensions" + + config WEXT_CORE + def_bool y +@@ -12,10 +12,10 @@ config WEXT_PROC + depends on WEXT_CORE + + config WEXT_SPY +- bool ++ bool "WEXT_SPY" + + config WEXT_PRIV +- bool ++ bool "WEXT_PRIV" + + config CFG80211 + tristate "cfg80211 - wireless configuration API" +@@ -203,7 +203,7 @@ config CFG80211_WEXT_EXPORT + endif # CFG80211 + + config LIB80211 +- tristate ++ tristate "LIB80211" + default n + help + This options enables a library of common routines used +@@ -212,17 +212,17 @@ config LIB80211 + Drivers should select this themselves if needed. + + config LIB80211_CRYPT_WEP +- tristate ++ tristate "LIB80211_CRYPT_WEP" + select CRYPTO_LIB_ARC4 + + config LIB80211_CRYPT_CCMP +- tristate ++ tristate "LIB80211_CRYPT_CCMP" + select CRYPTO + select CRYPTO_AES + select CRYPTO_CCM + + config LIB80211_CRYPT_TKIP +- tristate ++ tristate "LIB80211_CRYPT_TKIP" + select CRYPTO_LIB_ARC4 + + config LIB80211_DEBUG +--- a/sound/core/Kconfig ++++ b/sound/core/Kconfig +@@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM + tristate + + config SND_HWDEP +- tristate ++ tristate "Sound hardware support" + + config SND_SEQ_DEVICE + tristate +@@ -27,7 +27,7 @@ config SND_RAWMIDI + select SND_SEQ_DEVICE if SND_SEQUENCER != n + + config SND_COMPRESS_OFFLOAD +- tristate ++ tristate "Compression offloading support" + + config SND_JACK + bool diff --git a/ipq806x/hack-5.4/259-regmap_dynamic.patch b/ipq806x/hack-5.4/259-regmap_dynamic.patch new file mode 100644 index 0000000..812e182 --- /dev/null +++ b/ipq806x/hack-5.4/259-regmap_dynamic.patch @@ -0,0 +1,125 @@ +From 811d9e2268a62b830cfe93cd8bc929afcb8b198b Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 15 Jul 2017 21:12:38 +0200 +Subject: kernel: move regmap bloat out of the kernel image if it is only being used in modules + +lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998 +Signed-off-by: Felix Fietkau +--- + drivers/base/regmap/Kconfig | 15 ++++++++++----- + drivers/base/regmap/Makefile | 12 ++++++++---- + drivers/base/regmap/regmap.c | 3 +++ + include/linux/regmap.h | 2 +- + 4 files changed, 22 insertions(+), 10 deletions(-) + +--- a/drivers/base/regmap/Kconfig ++++ b/drivers/base/regmap/Kconfig +@@ -4,9 +4,8 @@ + # subsystems should select the appropriate symbols. + + config REGMAP +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SCCB || REGMAP_I3C) + select IRQ_DOMAIN if REGMAP_IRQ +- bool ++ tristate + + config REGCACHE_COMPRESSED + select LZO_COMPRESS +@@ -18,38 +17,49 @@ config REGMAP_AC97 + + config REGMAP_I2C + tristate ++ select REGMAP + depends on I2C + + config REGMAP_SLIMBUS + tristate ++ select REGMAP + depends on SLIMBUS + + config REGMAP_SPI + tristate ++ select REGMAP ++ depends on SPI_MASTER + depends on SPI + + config REGMAP_SPMI + tristate ++ select REGMAP + depends on SPMI + + config REGMAP_W1 + tristate ++ select REGMAP + depends on W1 + + config REGMAP_MMIO + tristate ++ select REGMAP + + config REGMAP_IRQ + bool ++ select REGMAP + + config REGMAP_SOUNDWIRE + tristate ++ select REGMAP + depends on SOUNDWIRE + + config REGMAP_SCCB + tristate ++ select REGMAP + depends on I2C + + config REGMAP_I3C + tristate ++ select REGMAP + depends on I3C +--- a/drivers/base/regmap/Makefile ++++ b/drivers/base/regmap/Makefile +@@ -2,10 +2,14 @@ + # For include/trace/define_trace.h to include trace.h + CFLAGS_regmap.o := -I$(src) + +-obj-$(CONFIG_REGMAP) += regmap.o regcache.o +-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o +-obj-$(CONFIG_REGCACHE_COMPRESSED) += regcache-lzo.o +-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o ++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o ++ifdef CONFIG_DEBUG_FS ++regmap-core-objs += regmap-debugfs.o ++endif ++ifdef CONFIG_REGCACHE_COMPRESSED ++regmap-core-objs += regcache-lzo.o ++endif ++obj-$(CONFIG_REGMAP) += regmap-core.o + obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o + obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o + obj-$(CONFIG_REGMAP_SLIMBUS) += regmap-slimbus.o +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -3118,3 +3119,5 @@ static int __init regmap_initcall(void) + return 0; + } + postcore_initcall(regmap_initcall); ++ ++MODULE_LICENSE("GPL"); +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -185,7 +185,7 @@ struct reg_sequence { + pollret ?: ((cond) ? 0 : -ETIMEDOUT); \ + }) + +-#ifdef CONFIG_REGMAP ++#if IS_REACHABLE(CONFIG_REGMAP) + + enum regmap_endian { + /* Unspecified -> 0 -> Backwards compatible default */ diff --git a/ipq806x/hack-5.4/260-crypto_test_dependencies.patch b/ipq806x/hack-5.4/260-crypto_test_dependencies.patch new file mode 100644 index 0000000..c1b0b85 --- /dev/null +++ b/ipq806x/hack-5.4/260-crypto_test_dependencies.patch @@ -0,0 +1,52 @@ +From fd1799b0bf5efa46dd3e6dfbbf3955564807e508 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:12:51 +0200 +Subject: kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run + +Reduces kernel size after LZMA by about 5k on MIPS + +lede-commit: 044c316167e076479a344c59905e5b435b84a77f +Signed-off-by: Felix Fietkau +--- + crypto/Kconfig | 13 ++++++------- + crypto/algboss.c | 4 ++++ + 2 files changed, 10 insertions(+), 7 deletions(-) + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -120,13 +120,13 @@ config CRYPTO_MANAGER + cbc(aes). + + config CRYPTO_MANAGER2 +- def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) +- select CRYPTO_AEAD2 +- select CRYPTO_HASH2 +- select CRYPTO_BLKCIPHER2 +- select CRYPTO_AKCIPHER2 +- select CRYPTO_KPP2 +- select CRYPTO_ACOMP2 ++ def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS) ++ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_USER + tristate "Userspace cryptographic algorithm configuration" +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -240,8 +240,12 @@ static int cryptomgr_schedule_test(struc + type = alg->cra_flags; + + /* Do not test internal algorithms. */ ++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS ++ type |= CRYPTO_ALG_TESTED; ++#else + if (type & CRYPTO_ALG_INTERNAL) + type |= CRYPTO_ALG_TESTED; ++#endif + + param->type = type; + diff --git a/ipq806x/hack-5.4/260-lib-arc4-unhide.patch b/ipq806x/hack-5.4/260-lib-arc4-unhide.patch new file mode 100644 index 0000000..a7668ac --- /dev/null +++ b/ipq806x/hack-5.4/260-lib-arc4-unhide.patch @@ -0,0 +1,15 @@ +This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We +need this to be able to compile this into the kernel and make use of it +from backports. + +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -6,7 +6,7 @@ config CRYPTO_LIB_AES + tristate + + config CRYPTO_LIB_ARC4 +- tristate ++ tristate "ARC4 cipher library" + + config CRYPTO_ARCH_HAVE_LIB_BLAKE2S + tristate diff --git a/ipq806x/hack-5.4/280-rfkill-stubs.patch b/ipq806x/hack-5.4/280-rfkill-stubs.patch new file mode 100644 index 0000000..2e48aea --- /dev/null +++ b/ipq806x/hack-5.4/280-rfkill-stubs.patch @@ -0,0 +1,84 @@ +From 236c1acdfef5958010ac9814a9872e0a46fd78ee Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 7 Jul 2017 17:13:44 +0200 +Subject: rfkill: add fake rfkill support + +allow building of modules depending on RFKILL even if RFKILL is not enabled. + +Signed-off-by: John Crispin +--- + include/linux/rfkill.h | 2 +- + net/Makefile | 2 +- + net/rfkill/Kconfig | 14 +++++++++----- + net/rfkill/Makefile | 2 +- + 4 files changed, 12 insertions(+), 8 deletions(-) + +--- a/include/linux/rfkill.h ++++ b/include/linux/rfkill.h +@@ -64,7 +64,7 @@ struct rfkill_ops { + int (*set_block)(void *data, bool blocked); + }; + +-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ++#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE) + /** + * rfkill_alloc - Allocate rfkill structure + * @name: name of the struct -- the string is not copied internally +--- a/net/Makefile ++++ b/net/Makefile +@@ -53,7 +53,7 @@ obj-$(CONFIG_TIPC) += tipc/ + obj-$(CONFIG_NETLABEL) += netlabel/ + obj-$(CONFIG_IUCV) += iucv/ + obj-$(CONFIG_SMC) += smc/ +-obj-$(CONFIG_RFKILL) += rfkill/ ++obj-$(CONFIG_RFKILL_FULL) += rfkill/ + obj-$(CONFIG_NET_9P) += 9p/ + obj-$(CONFIG_CAIF) += caif/ + ifneq ($(CONFIG_DCB),) +--- a/net/rfkill/Kconfig ++++ b/net/rfkill/Kconfig +@@ -2,7 +2,11 @@ + # + # RF switch subsystem configuration + # +-menuconfig RFKILL ++config RFKILL ++ bool ++ default y ++ ++menuconfig RFKILL_FULL + tristate "RF switch subsystem support" + help + Say Y here if you want to have control over RF switches +@@ -14,19 +18,19 @@ menuconfig RFKILL + # LED trigger support + config RFKILL_LEDS + bool +- depends on RFKILL ++ depends on RFKILL_FULL + depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS + default y + + config RFKILL_INPUT + bool "RF switch input support" if EXPERT +- depends on RFKILL ++ depends on RFKILL_FULL + depends on INPUT = y || RFKILL = INPUT + default y if !EXPERT + + config RFKILL_GPIO + tristate "GPIO RFKILL driver" +- depends on RFKILL ++ depends on RFKILL_FULL + depends on GPIOLIB || COMPILE_TEST + default n + help +--- a/net/rfkill/Makefile ++++ b/net/rfkill/Makefile +@@ -5,5 +5,5 @@ + + rfkill-y += core.o + rfkill-$(CONFIG_RFKILL_INPUT) += input.o +-obj-$(CONFIG_RFKILL) += rfkill.o ++obj-$(CONFIG_RFKILL_FULL) += rfkill.o + obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o diff --git a/ipq806x/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch b/ipq806x/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch new file mode 100644 index 0000000..aed08a5 --- /dev/null +++ b/ipq806x/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch @@ -0,0 +1,64 @@ +From: Ben Menchaca +Date: Fri, 7 Jun 2013 18:35:22 -0500 +Subject: MIPS: r4k_cache: use more efficient cache blast + +Optimize the compiler output for larger cache blast cases that are +common for DMA-based networking. + +Signed-off-by: Ben Menchaca +Signed-off-by: Felix Fietkau +--- +--- a/arch/mips/include/asm/r4kcache.h ++++ b/arch/mips/include/asm/r4kcache.h +@@ -617,14 +617,46 @@ static inline void prot##extra##blast_## + unsigned long end) \ + { \ + unsigned long lsize = cpu_##desc##_line_size(); \ ++ unsigned long lsize_2 = lsize * 2; \ ++ unsigned long lsize_3 = lsize * 3; \ ++ unsigned long lsize_4 = lsize * 4; \ ++ unsigned long lsize_5 = lsize * 5; \ ++ unsigned long lsize_6 = lsize * 6; \ ++ unsigned long lsize_7 = lsize * 7; \ ++ unsigned long lsize_8 = lsize * 8; \ + unsigned long addr = start & ~(lsize - 1); \ +- unsigned long aend = (end - 1) & ~(lsize - 1); \ ++ unsigned long aend = (end + lsize - 1) & ~(lsize - 1); \ ++ int lines = (aend - addr) / lsize; \ + \ +- while (1) { \ ++ while (lines >= 8) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ prot##cache_op(hitop, addr + lsize_2); \ ++ prot##cache_op(hitop, addr + lsize_3); \ ++ prot##cache_op(hitop, addr + lsize_4); \ ++ prot##cache_op(hitop, addr + lsize_5); \ ++ prot##cache_op(hitop, addr + lsize_6); \ ++ prot##cache_op(hitop, addr + lsize_7); \ ++ addr += lsize_8; \ ++ lines -= 8; \ ++ } \ ++ \ ++ if (lines & 0x4) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ prot##cache_op(hitop, addr + lsize_2); \ ++ prot##cache_op(hitop, addr + lsize_3); \ ++ addr += lsize_4; \ ++ } \ ++ \ ++ if (lines & 0x2) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ addr += lsize_2; \ ++ } \ ++ \ ++ if (lines & 0x1) { \ + prot##cache_op(hitop, addr); \ +- if (addr == aend) \ +- break; \ +- addr += lsize; \ + } \ + } + diff --git a/ipq806x/hack-5.4/301-mips_image_cmdline_hack.patch b/ipq806x/hack-5.4/301-mips_image_cmdline_hack.patch new file mode 100644 index 0000000..ada65cd --- /dev/null +++ b/ipq806x/hack-5.4/301-mips_image_cmdline_hack.patch @@ -0,0 +1,38 @@ +From: John Crispin +Subject: hack: kernel: add generic image_cmdline hack to MIPS targets + +lede-commit: d59f5b3a987a48508257a0ddbaeadc7909f9f976 +Signed-off-by: Gabor Juhos +--- + arch/mips/Kconfig | 4 ++++ + arch/mips/kernel/head.S | 6 ++++++ + 2 files changed, 10 insertions(+) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1159,6 +1159,10 @@ config SYNC_R4K + config MIPS_MACHINE + def_bool n + ++config IMAGE_CMDLINE_HACK ++ bool "OpenWrt specific image command line hack" ++ default n ++ + config NO_IOPORT_MAP + def_bool n + +--- a/arch/mips/kernel/head.S ++++ b/arch/mips/kernel/head.S +@@ -79,6 +79,12 @@ FEXPORT(__kernel_entry) + j kernel_entry + #endif /* CONFIG_BOOT_RAW */ + ++#ifdef CONFIG_IMAGE_CMDLINE_HACK ++ .ascii "CMDLINE:" ++EXPORT(__image_cmdline) ++ .fill 0x400 ++#endif /* CONFIG_IMAGE_CMDLINE_HACK */ ++ + __REF + + NESTED(kernel_entry, 16, sp) # kernel entry point diff --git a/ipq806x/hack-5.4/321-powerpc_crtsavres_prereq.patch b/ipq806x/hack-5.4/321-powerpc_crtsavres_prereq.patch new file mode 100644 index 0000000..8591705 --- /dev/null +++ b/ipq806x/hack-5.4/321-powerpc_crtsavres_prereq.patch @@ -0,0 +1,39 @@ +From 107c0964cb8db7ca28ac5199426414fdab3c274d Mon Sep 17 00:00:00 2001 +From: "Alexandros C. Couloumbis" +Date: Fri, 7 Jul 2017 17:14:51 +0200 +Subject: hack: arch: powerpc: drop register save/restore library from modules + +Upstream GCC uses a libgcc function for saving/restoring registers. This +makes the code bigger, and upstream kernels need to carry that function +for every single kernel module. Our GCC is patched to avoid those +references, so we can drop the extra bloat for modules. + +lede-commit: e8e1084654f50904e6bf77b70b2de3f137d7b3ec +Signed-off-by: Alexandros C. Couloumbis +--- + arch/powerpc/Makefile | 1 - + 1 file changed, 1 deletion(-) + +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -61,20 +61,6 @@ machine-$(CONFIG_PPC64) += 64 + machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le + UTS_MACHINE := $(subst $(space),,$(machine-y)) + +-# XXX This needs to be before we override LD below +-ifdef CONFIG_PPC32 +-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o +-else +-KBUILD_LDS_MODULE += $(srctree)/arch/powerpc/kernel/module.lds +-ifeq ($(call ld-ifversion, -ge, 225000000, y),y) +-# Have the linker provide sfpr if possible. +-# There is a corresponding test in arch/powerpc/lib/Makefile +-KBUILD_LDFLAGS_MODULE += --save-restore-funcs +-else +-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o +-endif +-endif +- + ifdef CONFIG_CPU_LITTLE_ENDIAN + KBUILD_CFLAGS += -mlittle-endian + KBUILD_LDFLAGS += -EL diff --git a/ipq806x/hack-5.4/400-unlock_mx25l6406e_with_4bit_block_protect.patch b/ipq806x/hack-5.4/400-unlock_mx25l6406e_with_4bit_block_protect.patch new file mode 100644 index 0000000..af0a149 --- /dev/null +++ b/ipq806x/hack-5.4/400-unlock_mx25l6406e_with_4bit_block_protect.patch @@ -0,0 +1,69 @@ +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -196,7 +196,7 @@ struct flash_info { + u16 page_size; + u16 addr_width; + +- u16 flags; ++ u32 flags; + #define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */ + #define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */ + #define SST_WRITE BIT(2) /* use SST byte programming */ +@@ -233,6 +233,10 @@ struct flash_info { + #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ + #define USE_CLSR BIT(14) /* use CLSR command */ + #define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */ ++#define SPI_NOR_4BIT_BP BIT(17) /* ++ * Flash SR has 4 bit fields (BP0-3) ++ * for block protection. ++ */ + + /* Part specific fixup hooks. */ + const struct spi_nor_fixups *fixups; +@@ -1985,6 +1989,9 @@ static int spi_nor_clear_sr_bp(struct sp + int ret; + u8 mask = SR_BP2 | SR_BP1 | SR_BP0; + ++ if (nor->flags & SNOR_F_HAS_4BIT_BP) ++ mask |= SR_BP3; ++ + ret = read_sr(nor); + if (ret < 0) { + dev_err(nor->dev, "error while reading status register\n"); +@@ -2337,7 +2344,7 @@ static const struct flash_info spi_nor_i + { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, + { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, + { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, +- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, ++ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_4BIT_BP) }, + { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, + { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +@@ -5025,6 +5032,9 @@ int spi_nor_scan(struct spi_nor *nor, co + if (info->flags & USE_CLSR) + nor->flags |= SNOR_F_USE_CLSR; + ++ if (info->flags & SPI_NOR_4BIT_BP) ++ nor->flags |= SNOR_F_HAS_4BIT_BP; ++ + if (info->flags & SPI_NOR_NO_ERASE) + mtd->flags |= MTD_NO_ERASE; + +--- a/include/linux/mtd/spi-nor.h ++++ b/include/linux/mtd/spi-nor.h +@@ -127,6 +127,7 @@ + #define SR_BP0 BIT(2) /* Block protect 0 */ + #define SR_BP1 BIT(3) /* Block protect 1 */ + #define SR_BP2 BIT(4) /* Block protect 2 */ ++#define SR_BP3 BIT(5) /* Block protect 3 */ + #define SR_TB BIT(5) /* Top/Bottom protect */ + #define SR_SRWD BIT(7) /* SR write protect */ + /* Spansion/Cypress specific status bits */ +@@ -243,6 +244,7 @@ enum spi_nor_option_flags { + SNOR_F_4B_OPCODES = BIT(6), + SNOR_F_HAS_4BAIT = BIT(7), + SNOR_F_HAS_LOCK = BIT(8), ++ SNOR_F_HAS_4BIT_BP = BIT(12), + }; + + /** diff --git a/ipq806x/hack-5.4/531-debloat_lzma.patch b/ipq806x/hack-5.4/531-debloat_lzma.patch new file mode 100644 index 0000000..2f70eee --- /dev/null +++ b/ipq806x/hack-5.4/531-debloat_lzma.patch @@ -0,0 +1,1040 @@ +From 3fd297761ac246c54d7723c57fca95c112b99465 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 15 Jul 2017 21:15:44 +0200 +Subject: lzma: de-bloat the lzma library used by jffs2 + +lede-commit: 3fd1dd08fbcbb78b34efefd32c3032e5c99108d6 +Signed-off-by: Felix Fietkau +--- + include/linux/lzma/LzFind.h | 17 --- + include/linux/lzma/LzmaDec.h | 101 --------------- + include/linux/lzma/LzmaEnc.h | 20 --- + lib/lzma/LzFind.c | 287 ++++--------------------------------------- + lib/lzma/LzmaDec.c | 86 +------------ + lib/lzma/LzmaEnc.c | 172 ++------------------------ + 6 files changed, 42 insertions(+), 641 deletions(-) + +--- a/include/linux/lzma/LzFind.h ++++ b/include/linux/lzma/LzFind.h +@@ -55,11 +55,6 @@ typedef struct _CMatchFinder + + #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +-int MatchFinder_NeedMove(CMatchFinder *p); +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +-void MatchFinder_MoveBlock(CMatchFinder *p); +-void MatchFinder_ReadIfRequired(CMatchFinder *p); +- + void MatchFinder_Construct(CMatchFinder *p); + + /* Conditions: +@@ -70,12 +65,6 @@ int MatchFinder_Create(CMatchFinder *p, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); + void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, +- UInt32 *distances, UInt32 maxLen); + + /* + Conditions: +@@ -102,12 +91,6 @@ typedef struct _IMatchFinder + + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +-void MatchFinder_Init(CMatchFinder *p); +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +- + #ifdef __cplusplus + } + #endif +--- a/include/linux/lzma/LzmaDec.h ++++ b/include/linux/lzma/LzmaDec.h +@@ -31,14 +31,6 @@ typedef struct _CLzmaProps + UInt32 dicSize; + } CLzmaProps; + +-/* LzmaProps_Decode - decodes properties +-Returns: +- SZ_OK +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); +- + + /* ---------- LZMA Decoder state ---------- */ + +@@ -70,8 +62,6 @@ typedef struct + + #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +-void LzmaDec_Init(CLzmaDec *p); +- + /* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ +@@ -108,97 +98,6 @@ typedef enum + + /* ELzmaStatus is used only as output value for function call */ + +- +-/* ---------- Interfaces ---------- */ +- +-/* There are 3 levels of interfaces: +- 1) Dictionary Interface +- 2) Buffer Interface +- 3) One Call Interface +- You can select any of these interfaces, but don't mix functions from different +- groups for same object. */ +- +- +-/* There are two variants to allocate state for Dictionary Interface: +- 1) LzmaDec_Allocate / LzmaDec_Free +- 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs +- You can use variant 2, if you set dictionary buffer manually. +- For Buffer Interface you must always use variant 1. +- +-LzmaDec_Allocate* can return: +- SZ_OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_UNSUPPORTED - Unsupported properties +-*/ +- +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); +- +-SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +-void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); +- +-/* ---------- Dictionary Interface ---------- */ +- +-/* You can use it, if you want to eliminate the overhead for data copying from +- dictionary to some other external buffer. +- You must work with CLzmaDec variables directly in this interface. +- +- STEPS: +- LzmaDec_Constr() +- LzmaDec_Allocate() +- for (each new stream) +- { +- LzmaDec_Init() +- while (it needs more decompression) +- { +- LzmaDec_DecodeToDic() +- use data from CLzmaDec::dic and update CLzmaDec::dicPos +- } +- } +- LzmaDec_Free() +-*/ +- +-/* LzmaDec_DecodeToDic +- +- The decoding to internal dictionary buffer (CLzmaDec::dic). +- You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! +- +-finishMode: +- It has meaning only if the decoding reaches output limit (dicLimit). +- LZMA_FINISH_ANY - Decode just dicLimit bytes. +- LZMA_FINISH_END - Stream must be finished after dicLimit. +- +-Returns: +- SZ_OK +- status: +- LZMA_STATUS_FINISHED_WITH_MARK +- LZMA_STATUS_NOT_FINISHED +- LZMA_STATUS_NEEDS_MORE_INPUT +- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK +- SZ_ERROR_DATA - Data error +-*/ +- +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- +-/* ---------- Buffer Interface ---------- */ +- +-/* It's zlib-like interface. +- See LzmaDec_DecodeToDic description for information about STEPS and return results, +- but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need +- to work with CLzmaDec variables manually. +- +-finishMode: +- It has meaning only if the decoding reaches output limit (*destLen). +- LZMA_FINISH_ANY - Decode just destLen bytes. +- LZMA_FINISH_END - Stream must be finished after (*destLen). +-*/ +- +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, +- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); +- +- + /* ---------- One Call Interface ---------- */ + + /* LzmaDecode +--- a/include/linux/lzma/LzmaEnc.h ++++ b/include/linux/lzma/LzmaEnc.h +@@ -31,9 +31,6 @@ typedef struct _CLzmaEncProps + } CLzmaEncProps; + + void LzmaEncProps_Init(CLzmaEncProps *p); +-void LzmaEncProps_Normalize(CLzmaEncProps *p); +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); +- + + /* ---------- CLzmaEncHandle Interface ---------- */ + +@@ -53,26 +50,9 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); + SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +-/* ---------- One Call Interface ---------- */ +- +-/* LzmaEncode +-Return code: +- SZ_OK - OK +- SZ_ERROR_MEM - Memory allocation error +- SZ_ERROR_PARAM - Incorrect paramater +- SZ_ERROR_OUTPUT_EOF - output buffer overflow +- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +-*/ +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +- + #ifdef __cplusplus + } + #endif +--- a/lib/lzma/LzFind.c ++++ b/lib/lzma/LzFind.c +@@ -14,9 +14,15 @@ + + #define kStartMaxLen 3 + ++#if 0 ++#define DIRECT_INPUT p->directInput ++#else ++#define DIRECT_INPUT 1 ++#endif ++ + static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) + { +- if (!p->directInput) ++ if (!DIRECT_INPUT) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; +@@ -28,7 +34,7 @@ static void LzInWindow_Free(CMatchFinder + static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) + { + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + p->blockSize = blockSize; + return 1; +@@ -42,12 +48,12 @@ static int LzInWindow_Create(CMatchFinde + return (p->bufferBase != 0); + } + +-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +-Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) + { + p->posLimit -= subValue; + p->pos -= subValue; +@@ -58,7 +64,7 @@ static void MatchFinder_ReadBlock(CMatch + { + if (p->streamEndWasReached || p->result != SZ_OK) + return; +- if (p->directInput) ++ if (DIRECT_INPUT) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) +@@ -89,7 +95,7 @@ static void MatchFinder_ReadBlock(CMatch + } + } + +-void MatchFinder_MoveBlock(CMatchFinder *p) ++static void MatchFinder_MoveBlock(CMatchFinder *p) + { + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, +@@ -97,22 +103,14 @@ void MatchFinder_MoveBlock(CMatchFinder + p->buffer = p->bufferBase + p->keepSizeBefore; + } + +-int MatchFinder_NeedMove(CMatchFinder *p) ++static int MatchFinder_NeedMove(CMatchFinder *p) + { +- if (p->directInput) ++ if (DIRECT_INPUT) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); + } + +-void MatchFinder_ReadIfRequired(CMatchFinder *p) +-{ +- if (p->streamEndWasReached) +- return; +- if (p->keepSizeAfter >= p->streamPos - p->pos) +- MatchFinder_ReadBlock(p); +-} +- + static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) + { + if (MatchFinder_NeedMove(p)) +@@ -268,7 +266,7 @@ static void MatchFinder_SetLimits(CMatch + p->posLimit = p->pos + limit; + } + +-void MatchFinder_Init(CMatchFinder *p) ++static void MatchFinder_Init(CMatchFinder *p) + { + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) +@@ -287,7 +285,7 @@ static UInt32 MatchFinder_GetSubValue(CM + return (p->pos - p->historySize - 1) & kNormalizeMask; + } + +-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) + { + UInt32 i; + for (i = 0; i < numItems; i++) +@@ -319,38 +317,7 @@ static void MatchFinder_CheckLimits(CMat + MatchFinder_SetLimits(p); + } + +-static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, +- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, +- UInt32 *distances, UInt32 maxLen) +-{ +- son[_cyclicBufferPos] = curMatch; +- for (;;) +- { +- UInt32 delta = pos - curMatch; +- if (cutValue-- == 0 || delta >= _cyclicBufferSize) +- return distances; +- { +- const Byte *pb = cur - delta; +- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; +- if (pb[maxLen] == cur[maxLen] && *pb == *cur) +- { +- UInt32 len = 0; +- while (++len != lenLimit) +- if (pb[len] != cur[len]) +- break; +- if (maxLen < len) +- { +- *distances++ = maxLen = len; +- *distances++ = delta - 1; +- if (len == lenLimit) +- return distances; +- } +- } +- } +- } +-} +- +-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) + { +@@ -460,10 +427,10 @@ static void SkipMatchesSpec(UInt32 lenLi + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +-#define MOVE_POS_RET MOVE_POS return offset; +- + static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + ++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset; ++ + #define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ +@@ -479,62 +446,7 @@ static void MatchFinder_MovePos(CMatchFi + distances + offset, maxLen) - distances); MOVE_POS_RET; + + #define SKIP_FOOTER \ +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; +- +-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 1) +-} +- +-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = 0; +- GET_MATCHES_FOOTER(offset, 2) +-} +- +-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, delta2, maxLen, offset; +- GET_MATCHES_HEADER(3) +- +- HASH3_CALC; +- +- delta2 = p->pos - p->hash[hash2Value]; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- +- +- maxLen = 2; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[0] = maxLen; +- distances[1] = delta2 - 1; +- offset = 2; +- if (maxLen == lenLimit) +- { +- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); +- MOVE_POS_RET; +- } +- } +- GET_MATCHES_FOOTER(offset, maxLen) +-} ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p); + + static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) + { +@@ -583,108 +495,6 @@ static UInt32 Bt4_MatchFinder_GetMatches + GET_MATCHES_FOOTER(offset, maxLen) + } + +-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; +- GET_MATCHES_HEADER(4) +- +- HASH4_CALC; +- +- delta2 = p->pos - p->hash[ hash2Value]; +- delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- +- maxLen = 1; +- offset = 0; +- if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) +- { +- distances[0] = maxLen = 2; +- distances[1] = delta2 - 1; +- offset = 2; +- } +- if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) +- { +- maxLen = 3; +- distances[offset + 1] = delta3 - 1; +- offset += 2; +- delta2 = delta3; +- } +- if (offset != 0) +- { +- for (; maxLen != lenLimit; maxLen++) +- if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) +- break; +- distances[offset - 2] = maxLen; +- if (maxLen == lenLimit) +- { +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS_RET; +- } +- } +- if (maxLen < 3) +- maxLen = 3; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances + offset, maxLen) - (distances)); +- MOVE_POS_RET +-} +- +-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +-{ +- UInt32 offset; +- GET_MATCHES_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), +- distances, 2) - (distances)); +- MOVE_POS_RET +-} +- +-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(2) +- HASH2_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- +-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value; +- SKIP_HEADER(3) +- HASH3_CALC; +- curMatch = p->hash[kFix3HashSize + hashValue]; +- p->hash[hash2Value] = +- p->hash[kFix3HashSize + hashValue] = p->pos; +- SKIP_FOOTER +- } +- while (--num != 0); +-} +- + static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) + { + do +@@ -701,61 +511,12 @@ static void Bt4_MatchFinder_Skip(CMatchF + while (--num != 0); + } + +-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- UInt32 hash2Value, hash3Value; +- SKIP_HEADER(4) +- HASH4_CALC; +- curMatch = p->hash[kFix4HashSize + hashValue]; +- p->hash[ hash2Value] = +- p->hash[kFix3HashSize + hash3Value] = +- p->hash[kFix4HashSize + hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- +-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +-{ +- do +- { +- SKIP_HEADER(3) +- HASH_ZIP_CALC; +- curMatch = p->hash[hashValue]; +- p->hash[hashValue] = p->pos; +- p->son[p->cyclicBufferPos] = curMatch; +- MOVE_POS +- } +- while (--num != 0); +-} +- + void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) + { + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; +- if (!p->btMode) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 2) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; +- } +- else if (p->numHashBytes == 3) +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; +- } +- else +- { +- vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; +- vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; +- } ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } +--- a/lib/lzma/LzmaDec.c ++++ b/lib/lzma/LzmaDec.c +@@ -682,7 +682,7 @@ static void LzmaDec_InitRc(CLzmaDec *p, + p->needFlush = 0; + } + +-void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) + { + p->needFlush = 1; + p->remainLen = 0; +@@ -698,7 +698,7 @@ void LzmaDec_InitDicAndState(CLzmaDec *p + p->needInitState = 1; + } + +-void LzmaDec_Init(CLzmaDec *p) ++static void LzmaDec_Init(CLzmaDec *p) + { + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +@@ -716,7 +716,7 @@ static void LzmaDec_InitStateReal(CLzmaD + p->needInitState = 0; + } + +-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) + { + SizeT inSize = *srcLen; +@@ -837,65 +837,13 @@ SRes LzmaDec_DecodeToDic(CLzmaDec *p, Si + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; + } + +-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +-{ +- SizeT outSize = *destLen; +- SizeT inSize = *srcLen; +- *srcLen = *destLen = 0; +- for (;;) +- { +- SizeT inSizeCur = inSize, outSizeCur, dicPos; +- ELzmaFinishMode curFinishMode; +- SRes res; +- if (p->dicPos == p->dicBufSize) +- p->dicPos = 0; +- dicPos = p->dicPos; +- if (outSize > p->dicBufSize - dicPos) +- { +- outSizeCur = p->dicBufSize; +- curFinishMode = LZMA_FINISH_ANY; +- } +- else +- { +- outSizeCur = dicPos + outSize; +- curFinishMode = finishMode; +- } +- +- res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); +- src += inSizeCur; +- inSize -= inSizeCur; +- *srcLen += inSizeCur; +- outSizeCur = p->dicPos - dicPos; +- memcpy(dest, p->dic + dicPos, outSizeCur); +- dest += outSizeCur; +- outSize -= outSizeCur; +- *destLen += outSizeCur; +- if (res != 0) +- return res; +- if (outSizeCur == 0 || outSize == 0) +- return SZ_OK; +- } +-} +- +-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->probs); + p->probs = 0; + } + +-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +-{ +- alloc->Free(alloc, p->dic); +- p->dic = 0; +-} +- +-void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +-{ +- LzmaDec_FreeProbs(p, alloc); +- LzmaDec_FreeDict(p, alloc); +-} +- +-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) + { + UInt32 dicSize; + Byte d; +@@ -935,7 +883,7 @@ static SRes LzmaDec_AllocateProbs2(CLzma + return SZ_OK; + } + +-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) + { + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +@@ -943,28 +891,6 @@ SRes LzmaDec_AllocateProbs(CLzmaDec *p, + p->prop = propNew; + return SZ_OK; + } +- +-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +-{ +- CLzmaProps propNew; +- SizeT dicBufSize; +- RINOK(LzmaProps_Decode(&propNew, props, propsSize)); +- RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); +- dicBufSize = propNew.dicSize; +- if (p->dic == 0 || dicBufSize != p->dicBufSize) +- { +- LzmaDec_FreeDict(p, alloc); +- p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); +- if (p->dic == 0) +- { +- LzmaDec_FreeProbs(p, alloc); +- return SZ_ERROR_MEM; +- } +- } +- p->dicBufSize = dicBufSize; +- p->prop = propNew; +- return SZ_OK; +-} + + SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, +--- a/lib/lzma/LzmaEnc.c ++++ b/lib/lzma/LzmaEnc.c +@@ -53,7 +53,7 @@ void LzmaEncProps_Init(CLzmaEncProps *p) + p->writeEndMark = 0; + } + +-void LzmaEncProps_Normalize(CLzmaEncProps *p) ++static void LzmaEncProps_Normalize(CLzmaEncProps *p) + { + int level = p->level; + if (level < 0) level = 5; +@@ -76,7 +76,7 @@ void LzmaEncProps_Normalize(CLzmaEncProp + #endif + } + +-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) + { + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); +@@ -93,7 +93,7 @@ UInt32 LzmaEncProps_GetDictSize(const CL + + #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +-UInt32 GetPosSlot1(UInt32 pos) ++static UInt32 GetPosSlot1(UInt32 pos) + { + UInt32 res; + BSR2_RET(pos, res); +@@ -107,7 +107,7 @@ UInt32 GetPosSlot1(UInt32 pos) + #define kNumLogBits (9 + (int)sizeof(size_t) / 2) + #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +-void LzmaEnc_FastPosInit(Byte *g_FastPos) ++static void LzmaEnc_FastPosInit(Byte *g_FastPos) + { + int c = 2, slotFast; + g_FastPos[0] = 0; +@@ -339,58 +339,6 @@ typedef struct + CSaveState saveState; + } CLzmaEnc; + +-void LzmaEnc_SaveState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- CSaveState *dest = &p->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +-} +- +-void LzmaEnc_RestoreState(CLzmaEncHandle pp) +-{ +- CLzmaEnc *dest = (CLzmaEnc *)pp; +- const CSaveState *p = &dest->saveState; +- int i; +- dest->lenEnc = p->lenEnc; +- dest->repLenEnc = p->repLenEnc; +- dest->state = p->state; +- +- for (i = 0; i < kNumStates; i++) +- { +- memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); +- memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); +- } +- for (i = 0; i < kNumLenToPosStates; i++) +- memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); +- memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); +- memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); +- memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); +- memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); +- memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); +- memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); +- memcpy(dest->reps, p->reps, sizeof(p->reps)); +- memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +-} +- + SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -600,7 +548,7 @@ static void LitEnc_EncodeMatched(CRangeE + while (symbol < 0x10000); + } + +-void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) + { + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) +@@ -1676,7 +1624,7 @@ static void FillDistancesPrices(CLzmaEnc + p->matchPriceCount = 0; + } + +-void LzmaEnc_Construct(CLzmaEnc *p) ++static void LzmaEnc_Construct(CLzmaEnc *p) + { + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); +@@ -1709,7 +1657,7 @@ CLzmaEncHandle LzmaEnc_Create(ISzAlloc * + return p; + } + +-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) + { + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); +@@ -1717,7 +1665,7 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAl + p->saveState.litProbs = 0; + } + +-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) + { + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); +@@ -1947,7 +1895,7 @@ static SRes LzmaEnc_Alloc(CLzmaEnc *p, U + return SZ_OK; + } + +-void LzmaEnc_Init(CLzmaEnc *p) ++static void LzmaEnc_Init(CLzmaEnc *p) + { + UInt32 i; + p->state = 0; +@@ -2005,7 +1953,7 @@ void LzmaEnc_Init(CLzmaEnc *p) + p->lpMask = (1 << p->lp) - 1; + } + +-void LzmaEnc_InitPrices(CLzmaEnc *p) ++static void LzmaEnc_InitPrices(CLzmaEnc *p) + { + if (!p->fastMode) + { +@@ -2037,26 +1985,6 @@ static SRes LzmaEnc_AllocAndInit(CLzmaEn + return SZ_OK; + } + +-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- p->rc.outStream = outStream; +- return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +-} +- +-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, +- ISeqInStream *inStream, UInt32 keepWindowSize, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- p->matchFinderBase.stream = inStream; +- p->needInit = 1; +- return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +-} +- + static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) + { + p->matchFinderBase.directInput = 1; +@@ -2064,7 +1992,7 @@ static void LzmaEnc_SetInputBuf(CLzmaEnc + p->matchFinderBase.directInputRem = srcLen; + } + +-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2074,7 +2002,7 @@ SRes LzmaEnc_MemPrepare(CLzmaEncHandle p + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); + } + +-void LzmaEnc_Finish(CLzmaEncHandle pp) ++static void LzmaEnc_Finish(CLzmaEncHandle pp) + { + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2107,53 +2035,6 @@ static size_t MyWrite(void *pp, const vo + return size; + } + +- +-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +-} +- +-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +-{ +- const CLzmaEnc *p = (CLzmaEnc *)pp; +- return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +-} +- +-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, +- Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +-{ +- CLzmaEnc *p = (CLzmaEnc *)pp; +- UInt64 nowPos64; +- SRes res; +- CSeqOutStreamBuf outStream; +- +- outStream.funcTable.Write = MyWrite; +- outStream.data = dest; +- outStream.rem = *destLen; +- outStream.overflow = False; +- +- p->writeEndMark = False; +- p->finished = False; +- p->result = SZ_OK; +- +- if (reInit) +- LzmaEnc_Init(p); +- LzmaEnc_InitPrices(p); +- nowPos64 = p->nowPos64; +- RangeEnc_Init(&p->rc); +- p->rc.outStream = &outStream.funcTable; +- +- res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); +- +- *unpackSize = (UInt32)(p->nowPos64 - nowPos64); +- *destLen -= outStream.rem; +- if (outStream.overflow) +- return SZ_ERROR_OUTPUT_EOF; +- +- return res; +-} +- + static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) + { + SRes res = SZ_OK; +@@ -2184,13 +2065,6 @@ static SRes LzmaEnc_Encode2(CLzmaEnc *p, + return res; + } + +-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, +- ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); +- return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +-} +- + SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) + { + CLzmaEnc *p = (CLzmaEnc *)pp; +@@ -2247,25 +2121,3 @@ SRes LzmaEnc_MemEncode(CLzmaEncHandle pp + return SZ_ERROR_OUTPUT_EOF; + return res; + } +- +-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, +- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, +- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +-{ +- CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); +- SRes res; +- if (p == 0) +- return SZ_ERROR_MEM; +- +- res = LzmaEnc_SetProps(p, props); +- if (res == SZ_OK) +- { +- res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); +- if (res == SZ_OK) +- res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, +- writeEndMark, progress, alloc, allocBig); +- } +- +- LzmaEnc_Destroy(p, alloc, allocBig); +- return res; +-} diff --git a/ipq806x/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch b/ipq806x/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch new file mode 100644 index 0000000..0e5447d --- /dev/null +++ b/ipq806x/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch @@ -0,0 +1,41 @@ +From 2e864386e62e702a343be2507062ee08d5dfc810 Mon Sep 17 00:00:00 2001 +From: Evan Green +Date: Thu, 14 Nov 2019 15:50:07 -0800 +Subject: loop: Report EOPNOTSUPP properly + +Properly plumb out EOPNOTSUPP from loop driver operations, which may +get returned when for instance a discard operation is attempted but not +supported by the underlying block device. Before this change, everything +was reported in the log as an I/O error, which is scary and not +helpful in debugging. + +Signed-off-by: Evan Green +Reviewed-by: Gwendal Grignou +Reviewed-by: Bart Van Assche +--- + drivers/block/loop.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -462,7 +462,7 @@ static void lo_complete_rq(struct reques + if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) || + req_op(rq) != REQ_OP_READ) { + if (cmd->ret < 0) +- ret = BLK_STS_IOERR; ++ ret = errno_to_blk_status(cmd->ret); + goto end_io; + } + +@@ -1973,7 +1973,10 @@ static void loop_handle_cmd(struct loop_ + failed: + /* complete non-aio request */ + if (!cmd->use_aio || ret) { +- cmd->ret = ret ? -EIO : 0; ++ if (ret == -EOPNOTSUPP) ++ cmd->ret = ret; ++ else ++ cmd->ret = ret ? -EIO : 0; + blk_mq_complete_request(rq); + } + } diff --git a/ipq806x/hack-5.4/640-bridge-only-accept-EAP-locally.patch b/ipq806x/hack-5.4/640-bridge-only-accept-EAP-locally.patch new file mode 100644 index 0000000..a713aa3 --- /dev/null +++ b/ipq806x/hack-5.4/640-bridge-only-accept-EAP-locally.patch @@ -0,0 +1,82 @@ +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:18:54 +0200 +Subject: bridge: only accept EAP locally + +When bridging, do not forward EAP frames to other ports, only deliver +them locally, regardless of the state. + +Signed-off-by: Felix Fietkau +[add disable_eap_hack sysfs attribute] +Signed-off-by: Etienne Champetier +--- + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -103,10 +103,14 @@ int br_handle_frame_finish(struct net *n + } + } + ++ BR_INPUT_SKB_CB(skb)->brdev = br->dev; ++ ++ if (skb->protocol == htons(ETH_P_PAE) && !br->disable_eap_hack) ++ return br_pass_frame_up(skb); ++ + if (p->state == BR_STATE_LEARNING) + goto drop; + +- BR_INPUT_SKB_CB(skb)->brdev = br->dev; + BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED); + + if (IS_ENABLED(CONFIG_INET) && +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -345,6 +345,8 @@ struct net_bridge { + u16 group_fwd_mask; + u16 group_fwd_mask_required; + ++ bool disable_eap_hack; ++ + /* STP */ + bridge_id designated_root; + bridge_id bridge_id; +--- a/net/bridge/br_sysfs_br.c ++++ b/net/bridge/br_sysfs_br.c +@@ -166,6 +166,30 @@ static ssize_t group_fwd_mask_store(stru + } + static DEVICE_ATTR_RW(group_fwd_mask); + ++static ssize_t disable_eap_hack_show(struct device *d, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct net_bridge *br = to_bridge(d); ++ return sprintf(buf, "%u\n", br->disable_eap_hack); ++} ++ ++static int set_disable_eap_hack(struct net_bridge *br, unsigned long val) ++{ ++ br->disable_eap_hack = !!val; ++ ++ return 0; ++} ++ ++static ssize_t disable_eap_hack_store(struct device *d, ++ struct device_attribute *attr, ++ const char *buf, ++ size_t len) ++{ ++ return store_bridge_parm(d, buf, len, set_disable_eap_hack); ++} ++static DEVICE_ATTR_RW(disable_eap_hack); ++ + static ssize_t priority_show(struct device *d, struct device_attribute *attr, + char *buf) + { +@@ -851,6 +875,7 @@ static struct attribute *bridge_attrs[] + &dev_attr_ageing_time.attr, + &dev_attr_stp_state.attr, + &dev_attr_group_fwd_mask.attr, ++ &dev_attr_disable_eap_hack.attr, + &dev_attr_priority.attr, + &dev_attr_bridge_id.attr, + &dev_attr_root_id.attr, diff --git a/ipq806x/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch b/ipq806x/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch new file mode 100644 index 0000000..2d3fe01 --- /dev/null +++ b/ipq806x/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch @@ -0,0 +1,212 @@ +From eda40b8c8c82e0f2789d6bc8bf63846dce2e8f32 Mon Sep 17 00:00:00 2001 +From: Kevin Darbyshire-Bryant +Date: Sat, 23 Mar 2019 09:29:49 +0000 +Subject: [PATCH] netfilter: connmark: introduce set-dscpmark + +set-dscpmark is a method of storing the DSCP of an ip packet into +conntrack mark. In combination with a suitable tc filter action +(act_ctinfo) DSCP values are able to be stored in the mark on egress and +restored on ingress across links that otherwise alter or bleach DSCP. + +This is useful for qdiscs such as CAKE which are able to shape according +to policies based on DSCP. + +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. + +x_tables CONNMARK set-dscpmark target solves the problem of storing the +DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc +action to restore. + +The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a +32bit 'statemask'. The dscp mask must be 6 contiguous bits and +represents the area where the DSCP will be stored in the connmark. The +state mask is a minimum 1 bit length mask that must not overlap with the +dscpmask. It represents a flag which is set when the DSCP has been +stored in the conntrack mark. 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 state +mask of zero disables the setting of a status bit/s. + +example syntax with a suitably modified iptables user space application: + +iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000 + +Would store the DSCP in the top 6 bits of the 32bit mark field, and use +the LSB of the top byte as the 'DSCP has been stored' marker. + +|----0xFC----conntrack mark----000000---| +| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| +| DSCP | unused | flag |unused | +|-----------------------0x01---000000---| + ^ ^ + | | + ---| Conditional flag + | set this when dscp +|-ip diffserv-| stored in mark +| 6 bits | +|-------------| + +an identically configured tc action to restore looks like: + +tc filter show dev eth0 ingress +filter parent ffff: protocol all pref 10 u32 chain 0 +filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1 +filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw + match 00000000/00000000 at 0 + action order 1: ctinfo zone 0 pipe + index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000 + + action order 2: mirred (Egress Redirect to device ifb4eth0) stolen + index 1 ref 1 bind 1 + +|----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 | +|-------------| + +Signed-off-by: Kevin Darbyshire-Bryant +--- + include/uapi/linux/netfilter/xt_connmark.h | 10 ++++ + net/netfilter/xt_connmark.c | 55 ++++++++++++++++++---- + 2 files changed, 57 insertions(+), 8 deletions(-) + +--- a/include/uapi/linux/netfilter/xt_connmark.h ++++ b/include/uapi/linux/netfilter/xt_connmark.h +@@ -20,6 +20,11 @@ enum { + }; + + enum { ++ XT_CONNMARK_VALUE = (1 << 0), ++ XT_CONNMARK_DSCP = (1 << 1) ++}; ++ ++enum { + D_SHIFT_LEFT = 0, + D_SHIFT_RIGHT, + }; +@@ -34,6 +39,11 @@ struct xt_connmark_tginfo2 { + __u8 shift_dir, shift_bits, mode; + }; + ++struct xt_connmark_tginfo3 { ++ __u32 ctmark, ctmask, nfmask; ++ __u8 shift_dir, shift_bits, mode, func; ++}; ++ + struct xt_connmark_mtinfo1 { + __u32 mark, mask; + __u8 invert; +--- a/net/netfilter/xt_connmark.c ++++ b/net/netfilter/xt_connmark.c +@@ -24,12 +24,13 @@ MODULE_ALIAS("ipt_connmark"); + MODULE_ALIAS("ip6t_connmark"); + + static unsigned int +-connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) ++connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info) + { + enum ip_conntrack_info ctinfo; + u_int32_t new_targetmark; + struct nf_conn *ct; + u_int32_t newmark; ++ u_int8_t dscp; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) +@@ -37,12 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, c + + switch (info->mode) { + case XT_CONNMARK_SET: +- newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; +- if (info->shift_dir == D_SHIFT_RIGHT) +- newmark >>= info->shift_bits; +- else +- newmark <<= info->shift_bits; ++ newmark = ct->mark; ++ if (info->func & XT_CONNMARK_VALUE) { ++ newmark = (newmark & ~info->ctmask) ^ info->ctmark; ++ if (info->shift_dir == D_SHIFT_RIGHT) ++ newmark >>= info->shift_bits; ++ else ++ newmark <<= info->shift_bits; ++ } else if (info->func & XT_CONNMARK_DSCP) { ++ if (skb->protocol == htons(ETH_P_IP)) ++ dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2; ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2; ++ else /* protocol doesn't have diffserv */ ++ break; + ++ newmark = (newmark & ~info->ctmark) | ++ (info->ctmask | (dscp << info->shift_bits)); ++ } + if (ct->mark != newmark) { + ct->mark = newmark; + nf_conntrack_event_cache(IPCT_MARK, ct); +@@ -81,20 +94,36 @@ static unsigned int + connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) + { + const struct xt_connmark_tginfo1 *info = par->targinfo; +- const struct xt_connmark_tginfo2 info2 = { ++ const struct xt_connmark_tginfo3 info3 = { + .ctmark = info->ctmark, + .ctmask = info->ctmask, + .nfmask = info->nfmask, + .mode = info->mode, ++ .func = XT_CONNMARK_VALUE + }; + +- return connmark_tg_shift(skb, &info2); ++ return connmark_tg_shift(skb, &info3); + } + + static unsigned int + connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) + { + const struct xt_connmark_tginfo2 *info = par->targinfo; ++ const struct xt_connmark_tginfo3 info3 = { ++ .ctmark = info->ctmark, ++ .ctmask = info->ctmask, ++ .nfmask = info->nfmask, ++ .mode = info->mode, ++ .func = XT_CONNMARK_VALUE ++ }; ++ ++ return connmark_tg_shift(skb, &info3); ++} ++ ++static unsigned int ++connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) ++{ ++ const struct xt_connmark_tginfo3 *info = par->targinfo; + + return connmark_tg_shift(skb, info); + } +@@ -165,6 +194,16 @@ static struct xt_target connmark_tg_reg[ + .targetsize = sizeof(struct xt_connmark_tginfo2), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, ++ }, ++ { ++ .name = "CONNMARK", ++ .revision = 3, ++ .family = NFPROTO_UNSPEC, ++ .checkentry = connmark_tg_check, ++ .target = connmark_tg_v3, ++ .targetsize = sizeof(struct xt_connmark_tginfo3), ++ .destroy = connmark_tg_destroy, ++ .me = THIS_MODULE, + } + }; + diff --git a/ipq806x/hack-5.4/647-netfilter-flow-acct.patch b/ipq806x/hack-5.4/647-netfilter-flow-acct.patch new file mode 100644 index 0000000..f9480d5 --- /dev/null +++ b/ipq806x/hack-5.4/647-netfilter-flow-acct.patch @@ -0,0 +1,70 @@ +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -160,6 +160,8 @@ struct nf_flow_table_hw { + int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload); + void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload); + ++void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir); ++ + extern struct work_struct nf_flow_offload_hw_work; + + #define MODULE_ALIAS_NF_FLOWTABLE(family) \ +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + struct flow_offload_entry { + struct flow_offload flow; +@@ -164,6 +165,22 @@ void flow_offload_free(struct flow_offlo + } + EXPORT_SYMBOL_GPL(flow_offload_free); + ++void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir) ++{ ++ struct flow_offload_entry *entry; ++ struct nf_conn_acct *acct; ++ ++ entry = container_of(flow, struct flow_offload_entry, flow); ++ acct = nf_conn_acct_find(entry->ct); ++ if (acct) { ++ struct nf_conn_counter *counter = acct->counter; ++ ++ atomic64_inc(&counter[dir].packets); ++ atomic64_add(skb->len, &counter[dir].bytes); ++ } ++} ++EXPORT_SYMBOL_GPL(nf_flow_table_acct); ++ + static u32 flow_offload_hash(const void *data, u32 len, u32 seed) + { + const struct flow_offload_tuple *tuple = data; +--- a/net/netfilter/nf_flow_table_ip.c ++++ b/net/netfilter/nf_flow_table_ip.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++ + /* For layer 4 checksum field offset. */ + #include + #include +@@ -296,6 +297,7 @@ nf_flow_offload_ip_hook(void *priv, stru + skb->dev = outdev; + nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr); + skb_dst_set_noref(skb, &rt->dst); ++ nf_flow_table_acct(flow, skb, dir); + neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb); + + return NF_STOLEN; +@@ -526,6 +528,7 @@ nf_flow_offload_ipv6_hook(void *priv, st + skb->dev = outdev; + nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6); + skb_dst_set_noref(skb, &rt->dst); ++ nf_flow_table_acct(flow, skb, dir); + neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb); + + return NF_STOLEN; diff --git a/ipq806x/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch b/ipq806x/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch new file mode 100644 index 0000000..d584cb5 --- /dev/null +++ b/ipq806x/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch @@ -0,0 +1,589 @@ +From: Felix Fietkau +Date: Tue, 20 Feb 2018 15:56:02 +0100 +Subject: [PATCH] netfilter: add xt_OFFLOAD target + +Signed-off-by: Felix Fietkau +--- + create mode 100644 net/netfilter/xt_OFFLOAD.c + +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -56,8 +56,6 @@ config NF_TABLES_ARP + help + This option enables the ARP support for nf_tables. + +-endif # NF_TABLES +- + config NF_FLOW_TABLE_IPV4 + tristate "Netfilter flow table IPv4 module" + depends on NF_FLOW_TABLE +@@ -66,6 +64,8 @@ config NF_FLOW_TABLE_IPV4 + + To compile it as a module, choose M here. + ++endif # NF_TABLES ++ + config NF_DUP_IPV4 + tristate "Netfilter IPv4 packet duplication to alternate destination" + depends on !NF_CONNTRACK || NF_CONNTRACK +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -45,7 +45,6 @@ config NFT_FIB_IPV6 + multicast or blackhole. + + endif # NF_TABLES_IPV6 +-endif # NF_TABLES + + config NF_FLOW_TABLE_IPV6 + tristate "Netfilter flow table IPv6 module" +@@ -55,6 +54,8 @@ config NF_FLOW_TABLE_IPV6 + + To compile it as a module, choose M here. + ++endif # NF_TABLES ++ + config NF_DUP_IPV6 + tristate "Netfilter IPv6 packet duplication to alternate destination" + depends on !NF_CONNTRACK || NF_CONNTRACK +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -690,8 +690,6 @@ config NFT_FIB_NETDEV + + endif # NF_TABLES_NETDEV + +-endif # NF_TABLES +- + config NF_FLOW_TABLE_INET + tristate "Netfilter flow table mixed IPv4/IPv6 module" + depends on NF_FLOW_TABLE +@@ -700,11 +698,12 @@ config NF_FLOW_TABLE_INET + + To compile it as a module, choose M here. + ++endif # NF_TABLES ++ + config NF_FLOW_TABLE + tristate "Netfilter flow table module" + depends on NETFILTER_INGRESS + depends on NF_CONNTRACK +- depends on NF_TABLES + help + This option adds the flow table core infrastructure. + +@@ -993,6 +992,15 @@ config NETFILTER_XT_TARGET_NOTRACK + depends on NETFILTER_ADVANCED + select NETFILTER_XT_TARGET_CT + ++config NETFILTER_XT_TARGET_FLOWOFFLOAD ++ tristate '"FLOWOFFLOAD" target support' ++ depends on NF_FLOW_TABLE ++ depends on NETFILTER_INGRESS ++ help ++ This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload ++ module to speed up processing of packets by bypassing the usual ++ netfilter chains ++ + config NETFILTER_XT_TARGET_RATEEST + tristate '"RATEEST" target support' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -141,6 +141,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF + obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o + obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o + obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o ++obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o + obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o + obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o + obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o +--- /dev/null ++++ b/net/netfilter/xt_FLOWOFFLOAD.c +@@ -0,0 +1,427 @@ ++/* ++ * Copyright (C) 2018 Felix Fietkau ++ * ++ * 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. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static struct nf_flowtable nf_flowtable; ++static HLIST_HEAD(hooks); ++static DEFINE_SPINLOCK(hooks_lock); ++static struct delayed_work hook_work; ++ ++struct xt_flowoffload_hook { ++ struct hlist_node list; ++ struct nf_hook_ops ops; ++ struct net *net; ++ bool registered; ++ bool used; ++}; ++ ++static unsigned int ++xt_flowoffload_net_hook(void *priv, struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ return nf_flow_offload_ip_hook(priv, skb, state); ++ case htons(ETH_P_IPV6): ++ return nf_flow_offload_ipv6_hook(priv, skb, state); ++ } ++ ++ return NF_ACCEPT; ++} ++ ++int nf_flow_table_iterate(struct nf_flowtable *flow_table, ++ void (*iter)(struct flow_offload *flow, void *data), ++ void *data); ++ ++static int ++xt_flowoffload_create_hook(struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ struct nf_hook_ops *ops; ++ ++ hook = kzalloc(sizeof(*hook), GFP_ATOMIC); ++ if (!hook) ++ return -ENOMEM; ++ ++ ops = &hook->ops; ++ ops->pf = NFPROTO_NETDEV; ++ ops->hooknum = NF_NETDEV_INGRESS; ++ ops->priority = 10; ++ ops->priv = &nf_flowtable; ++ ops->hook = xt_flowoffload_net_hook; ++ ops->dev = dev; ++ ++ hlist_add_head(&hook->list, &hooks); ++ mod_delayed_work(system_power_efficient_wq, &hook_work, 0); ++ ++ return 0; ++} ++ ++static struct xt_flowoffload_hook * ++flow_offload_lookup_hook(struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++ hlist_for_each_entry(hook, &hooks, list) { ++ if (hook->ops.dev == dev) ++ return hook; ++ } ++ ++ return NULL; ++} ++ ++static void ++xt_flowoffload_check_device(struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++ spin_lock_bh(&hooks_lock); ++ hook = flow_offload_lookup_hook(dev); ++ if (hook) ++ hook->used = true; ++ else ++ xt_flowoffload_create_hook(dev); ++ spin_unlock_bh(&hooks_lock); ++} ++ ++static void ++xt_flowoffload_register_hooks(void) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++restart: ++ hlist_for_each_entry(hook, &hooks, list) { ++ if (hook->registered) ++ continue; ++ ++ hook->registered = true; ++ hook->net = dev_net(hook->ops.dev); ++ spin_unlock_bh(&hooks_lock); ++ nf_register_net_hook(hook->net, &hook->ops); ++ spin_lock_bh(&hooks_lock); ++ goto restart; ++ } ++ ++} ++ ++static void ++xt_flowoffload_cleanup_hooks(void) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++restart: ++ hlist_for_each_entry(hook, &hooks, list) { ++ if (hook->used || !hook->registered) ++ continue; ++ ++ hlist_del(&hook->list); ++ spin_unlock_bh(&hooks_lock); ++ nf_unregister_net_hook(hook->net, &hook->ops); ++ kfree(hook); ++ spin_lock_bh(&hooks_lock); ++ goto restart; ++ } ++ ++} ++ ++static void ++xt_flowoffload_check_hook(struct flow_offload *flow, void *data) ++{ ++ struct flow_offload_tuple *tuple = &flow->tuplehash[0].tuple; ++ struct xt_flowoffload_hook *hook; ++ bool *found = data; ++ struct rtable *rt = (struct rtable *)tuple->dst_cache; ++ ++ spin_lock_bh(&hooks_lock); ++ hlist_for_each_entry(hook, &hooks, list) { ++ if (hook->ops.dev->ifindex != tuple->iifidx && ++ hook->ops.dev->ifindex != rt->dst.dev->ifindex) ++ continue; ++ ++ hook->used = true; ++ *found = true; ++ } ++ spin_unlock_bh(&hooks_lock); ++} ++ ++static void ++xt_flowoffload_hook_work(struct work_struct *work) ++{ ++ struct xt_flowoffload_hook *hook; ++ bool found = false; ++ int err; ++ ++ spin_lock_bh(&hooks_lock); ++ xt_flowoffload_register_hooks(); ++ hlist_for_each_entry(hook, &hooks, list) ++ hook->used = false; ++ spin_unlock_bh(&hooks_lock); ++ ++ err = nf_flow_table_iterate(&nf_flowtable, xt_flowoffload_check_hook, ++ &found); ++ if (err && err != -EAGAIN) ++ goto out; ++ ++ spin_lock_bh(&hooks_lock); ++ xt_flowoffload_cleanup_hooks(); ++ spin_unlock_bh(&hooks_lock); ++ ++out: ++ if (found) ++ queue_delayed_work(system_power_efficient_wq, &hook_work, HZ); ++} ++ ++static bool ++xt_flowoffload_skip(struct sk_buff *skb, int family) ++{ ++ if (skb_sec_path(skb)) ++ return true; ++ ++ if (family == NFPROTO_IPV4) { ++ const struct ip_options *opt = &(IPCB(skb)->opt); ++ ++ if (unlikely(opt->optlen)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static struct dst_entry * ++xt_flowoffload_dst(const struct nf_conn *ct, enum ip_conntrack_dir dir, ++ const struct xt_action_param *par, int ifindex) ++{ ++ struct dst_entry *dst = NULL; ++ struct flowi fl; ++ ++ memset(&fl, 0, sizeof(fl)); ++ switch (xt_family(par)) { ++ case NFPROTO_IPV4: ++ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; ++ fl.u.ip4.flowi4_oif = ifindex; ++ break; ++ case NFPROTO_IPV6: ++ fl.u.ip6.saddr = ct->tuplehash[dir].tuple.dst.u3.in6; ++ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; ++ fl.u.ip6.flowi6_oif = ifindex; ++ break; ++ } ++ ++ nf_route(xt_net(par), &dst, &fl, false, xt_family(par)); ++ ++ return dst; ++} ++ ++static int ++xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct, ++ const struct xt_action_param *par, ++ struct nf_flow_route *route, enum ip_conntrack_dir dir) ++{ ++ struct dst_entry *this_dst, *other_dst; ++ ++ this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex); ++ other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex); ++ ++ route->tuple[dir].dst = this_dst; ++ route->tuple[!dir].dst = other_dst; ++ ++ if (!this_dst || !other_dst) ++ return -ENOENT; ++ ++ if (dst_xfrm(this_dst) || dst_xfrm(other_dst)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static unsigned int ++flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par) ++{ ++ const struct xt_flowoffload_target_info *info = par->targinfo; ++ struct tcphdr _tcph, *tcph = NULL; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct nf_flow_route route; ++ struct flow_offload *flow = NULL; ++ struct nf_conn *ct; ++ struct net *net; ++ ++ if (xt_flowoffload_skip(skb, xt_family(par))) ++ return XT_CONTINUE; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (ct == NULL) ++ return XT_CONTINUE; ++ ++ switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) { ++ case IPPROTO_TCP: ++ if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) ++ return XT_CONTINUE; ++ ++ tcph = skb_header_pointer(skb, par->thoff, ++ sizeof(_tcph), &_tcph); ++ if (unlikely(!tcph || tcph->fin || tcph->rst)) ++ return XT_CONTINUE; ++ break; ++ case IPPROTO_UDP: ++ break; ++ default: ++ return XT_CONTINUE; ++ } ++ ++ if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) || ++ ct->status & IPS_SEQ_ADJUST) ++ return XT_CONTINUE; ++ ++ if (!nf_ct_is_confirmed(ct)) ++ return XT_CONTINUE; ++ ++ if (!xt_in(par) || !xt_out(par)) ++ return XT_CONTINUE; ++ ++ if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status)) ++ return XT_CONTINUE; ++ ++ dir = CTINFO2DIR(ctinfo); ++ ++ if (xt_flowoffload_route(skb, ct, par, &route, dir) == 0) ++ flow = flow_offload_alloc(ct, &route); ++ ++ dst_release(route.tuple[dir].dst); ++ dst_release(route.tuple[!dir].dst); ++ ++ if (!flow) ++ goto err_flow_route; ++ ++ if (tcph) { ++ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; ++ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; ++ } ++ ++ if (flow_offload_add(&nf_flowtable, flow) < 0) ++ goto err_flow_add; ++ ++ xt_flowoffload_check_device(xt_in(par)); ++ xt_flowoffload_check_device(xt_out(par)); ++ ++ net = read_pnet(&nf_flowtable.ft_net); ++ if (!net) ++ write_pnet(&nf_flowtable.ft_net, xt_net(par)); ++ ++ if (info->flags & XT_FLOWOFFLOAD_HW) ++ nf_flow_offload_hw_add(xt_net(par), flow, ct); ++ ++ return XT_CONTINUE; ++ ++err_flow_add: ++ flow_offload_free(flow); ++err_flow_route: ++ clear_bit(IPS_OFFLOAD_BIT, &ct->status); ++ return XT_CONTINUE; ++} ++ ++ ++static int flowoffload_chk(const struct xt_tgchk_param *par) ++{ ++ struct xt_flowoffload_target_info *info = par->targinfo; ++ ++ if (info->flags & ~XT_FLOWOFFLOAD_MASK) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static struct xt_target offload_tg_reg __read_mostly = { ++ .family = NFPROTO_UNSPEC, ++ .name = "FLOWOFFLOAD", ++ .revision = 0, ++ .targetsize = sizeof(struct xt_flowoffload_target_info), ++ .usersize = sizeof(struct xt_flowoffload_target_info), ++ .checkentry = flowoffload_chk, ++ .target = flowoffload_tg, ++ .me = THIS_MODULE, ++}; ++ ++static int xt_flowoffload_table_init(struct nf_flowtable *table) ++{ ++ table->flags = NF_FLOWTABLE_F_HW; ++ nf_flow_table_init(table); ++ return 0; ++} ++ ++static void xt_flowoffload_table_cleanup(struct nf_flowtable *table) ++{ ++ nf_flow_table_free(table); ++} ++ ++static int flow_offload_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct xt_flowoffload_hook *hook = NULL; ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ ++ if (event != NETDEV_UNREGISTER) ++ return NOTIFY_DONE; ++ ++ spin_lock_bh(&hooks_lock); ++ hook = flow_offload_lookup_hook(dev); ++ if (hook) { ++ hlist_del(&hook->list); ++ } ++ spin_unlock_bh(&hooks_lock); ++ if (hook) { ++ nf_unregister_net_hook(hook->net, &hook->ops); ++ kfree(hook); ++ } ++ ++ nf_flow_table_cleanup(dev); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block flow_offload_netdev_notifier = { ++ .notifier_call = flow_offload_netdev_event, ++}; ++ ++static int __init xt_flowoffload_tg_init(void) ++{ ++ int ret; ++ ++ register_netdevice_notifier(&flow_offload_netdev_notifier); ++ ++ INIT_DELAYED_WORK(&hook_work, xt_flowoffload_hook_work); ++ ++ ret = xt_flowoffload_table_init(&nf_flowtable); ++ if (ret) ++ return ret; ++ ++ ret = xt_register_target(&offload_tg_reg); ++ if (ret) ++ xt_flowoffload_table_cleanup(&nf_flowtable); ++ ++ return ret; ++} ++ ++static void __exit xt_flowoffload_tg_exit(void) ++{ ++ xt_unregister_target(&offload_tg_reg); ++ xt_flowoffload_table_cleanup(&nf_flowtable); ++ unregister_netdevice_notifier(&flow_offload_netdev_notifier); ++} ++ ++MODULE_LICENSE("GPL"); ++module_init(xt_flowoffload_tg_init); ++module_exit(xt_flowoffload_tg_exit); +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -338,8 +337,7 @@ flow_offload_lookup(struct nf_flowtable + } + EXPORT_SYMBOL_GPL(flow_offload_lookup); + +-static int +-nf_flow_table_iterate(struct nf_flowtable *flow_table, ++int nf_flow_table_iterate(struct nf_flowtable *flow_table, + void (*iter)(struct flow_offload *flow, void *data), + void *data) + { +@@ -372,6 +370,7 @@ nf_flow_table_iterate(struct nf_flowtabl + + return err; + } ++EXPORT_SYMBOL_GPL(nf_flow_table_iterate); + + static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data) + { +--- /dev/null ++++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#ifndef _XT_FLOWOFFLOAD_H ++#define _XT_FLOWOFFLOAD_H ++ ++#include ++ ++enum { ++ XT_FLOWOFFLOAD_HW = 1 << 0, ++ ++ XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW ++}; ++ ++struct xt_flowoffload_target_info { ++ __u32 flags; ++}; ++ ++#endif /* _XT_FLOWOFFLOAD_H */ +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -130,6 +130,10 @@ static inline void flow_offload_dead(str + flow->flags |= FLOW_OFFLOAD_DYING; + } + ++int nf_flow_table_iterate(struct nf_flowtable *flow_table, ++ void (*iter)(struct flow_offload *flow, void *data), ++ void *data); ++ + int nf_flow_snat_port(const struct flow_offload *flow, + struct sk_buff *skb, unsigned int thoff, + u8 protocol, enum flow_offload_tuple_dir dir); diff --git a/ipq806x/hack-5.4/651-wireless_mesh_header.patch b/ipq806x/hack-5.4/651-wireless_mesh_header.patch new file mode 100644 index 0000000..f545d8e --- /dev/null +++ b/ipq806x/hack-5.4/651-wireless_mesh_header.patch @@ -0,0 +1,24 @@ +From 6d3bc769657b0ee7c7506dad9911111c4226a7ea Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Fri, 7 Jul 2017 17:21:05 +0200 +Subject: mac80211: increase wireless mesh header size + +lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1 +Signed-off-by: Imre Kaloz +--- + include/linux/netdevice.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -138,8 +138,8 @@ static inline bool dev_xmit_complete(int + + #if defined(CONFIG_HYPERV_NET) + # define LL_MAX_HEADER 128 +-#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) +-# if defined(CONFIG_MAC80211_MESH) ++#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1 ++# if defined(CONFIG_MAC80211_MESH) || 1 + # define LL_MAX_HEADER 128 + # else + # define LL_MAX_HEADER 96 diff --git a/ipq806x/hack-5.4/660-fq_codel_defaults.patch b/ipq806x/hack-5.4/660-fq_codel_defaults.patch new file mode 100644 index 0000000..46bf0e3 --- /dev/null +++ b/ipq806x/hack-5.4/660-fq_codel_defaults.patch @@ -0,0 +1,27 @@ +From a6ccb238939b25851474a279b20367fd24a0e816 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:21:53 +0200 +Subject: hack: net: fq_codel: tune defaults for small devices + +Assume that x86_64 devices always have a big memory and do not need this +optimization compared to devices with only 32 MB or 64 MB RAM. + +Signed-off-by: Felix Fietkau +--- + net/sched/sch_fq_codel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -470,7 +470,11 @@ static int fq_codel_init(struct Qdisc *s + + sch->limit = 10*1024; + q->flows_cnt = 1024; ++#ifdef CONFIG_X86_64 + q->memory_limit = 32 << 20; /* 32 MBytes */ ++#else ++ q->memory_limit = 4 << 20; /* 4 MBytes */ ++#endif + q->drop_batch_size = 64; + q->quantum = psched_mtu(qdisc_dev(sch)); + INIT_LIST_HEAD(&q->new_flows); diff --git a/ipq806x/hack-5.4/661-use_fq_codel_by_default.patch b/ipq806x/hack-5.4/661-use_fq_codel_by_default.patch new file mode 100644 index 0000000..bbe43d2 --- /dev/null +++ b/ipq806x/hack-5.4/661-use_fq_codel_by_default.patch @@ -0,0 +1,100 @@ +From 1d418f7e88035ed7a94073f6354246c66e9193e9 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:22:58 +0200 +Subject: fq_codel: switch default qdisc from pfifo_fast to fq_codel and remove pfifo_fast + +Signed-off-by: Felix Fietkau +--- + include/net/sch_generic.h | 3 ++- + net/sched/Kconfig | 3 ++- + net/sched/sch_api.c | 2 +- + net/sched/sch_fq_codel.c | 3 ++- + net/sched/sch_generic.c | 4 ++-- + 5 files changed, 9 insertions(+), 6 deletions(-) + +--- a/include/net/sch_generic.h ++++ b/include/net/sch_generic.h +@@ -615,12 +615,13 @@ extern struct Qdisc_ops noop_qdisc_ops; + extern struct Qdisc_ops pfifo_fast_ops; + extern struct Qdisc_ops mq_qdisc_ops; + extern struct Qdisc_ops noqueue_qdisc_ops; ++extern struct Qdisc_ops fq_codel_qdisc_ops; + extern const struct Qdisc_ops *default_qdisc_ops; + static inline const struct Qdisc_ops * + get_default_qdisc_ops(const struct net_device *dev, int ntx) + { + return ntx < dev->real_num_tx_queues ? +- default_qdisc_ops : &pfifo_fast_ops; ++ default_qdisc_ops : &fq_codel_qdisc_ops; + } + + struct Qdisc_class_common { +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -4,8 +4,9 @@ + # + + menuconfig NET_SCHED +- bool "QoS and/or fair queueing" ++ def_bool y + select NET_SCH_FIFO ++ select NET_SCH_FQ_CODEL + ---help--- + When the kernel has several packets to send out over a network + device, it has to decide which ones to send first, which ones to +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -2278,7 +2278,7 @@ static int __init pktsched_init(void) + return err; + } + +- register_qdisc(&pfifo_fast_ops); ++ register_qdisc(&fq_codel_qdisc_ops); + register_qdisc(&pfifo_qdisc_ops); + register_qdisc(&bfifo_qdisc_ops); + register_qdisc(&pfifo_head_drop_qdisc_ops); +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -710,7 +710,7 @@ static const struct Qdisc_class_ops fq_c + .walk = fq_codel_walk, + }; + +-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { ++struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { + .cl_ops = &fq_codel_class_ops, + .id = "fq_codel", + .priv_size = sizeof(struct fq_codel_sched_data), +@@ -725,6 +725,7 @@ static struct Qdisc_ops fq_codel_qdisc_o + .dump_stats = fq_codel_dump_stats, + .owner = THIS_MODULE, + }; ++EXPORT_SYMBOL(fq_codel_qdisc_ops); + + static int __init fq_codel_module_init(void) + { +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -32,7 +32,7 @@ + #include + + /* Qdisc to use by default */ +-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; ++const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops; + EXPORT_SYMBOL(default_qdisc_ops); + + static void qdisc_maybe_clear_missed(struct Qdisc *q, +@@ -1079,12 +1079,12 @@ static void attach_one_default_qdisc(str + void *_unused) + { + struct Qdisc *qdisc; +- const struct Qdisc_ops *ops = default_qdisc_ops; ++ const struct Qdisc_ops *ops = &fq_codel_qdisc_ops; + + if (dev->priv_flags & IFF_NO_QUEUE) + ops = &noqueue_qdisc_ops; + else if(dev->type == ARPHRD_CAN) +- ops = &pfifo_fast_ops; ++ ops = &fq_codel_qdisc_ops; + + qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT, NULL); + if (!qdisc) { diff --git a/ipq806x/hack-5.4/662-remove_pfifo_fast.patch b/ipq806x/hack-5.4/662-remove_pfifo_fast.patch new file mode 100644 index 0000000..9df3a82 --- /dev/null +++ b/ipq806x/hack-5.4/662-remove_pfifo_fast.patch @@ -0,0 +1,243 @@ +From b531d492d5ef1cf9dba0f4888eb5fd8624a6d762 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:23:42 +0200 +Subject: net: sched: switch default qdisc from pfifo_fast to fq_codel and remove pfifo_fast + +Signed-off-by: Felix Fietkau +--- + net/sched/sch_generic.c | 140 ------------------------------------------------ + 1 file changed, 140 deletions(-) + +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -620,230 +620,6 @@ struct Qdisc_ops noqueue_qdisc_ops __rea + .owner = THIS_MODULE, + }; + +-static const u8 prio2band[TC_PRIO_MAX + 1] = { +- 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 +-}; +- +-/* 3-band FIFO queue: old style, but should be a bit faster than +- generic prio+fifo combination. +- */ +- +-#define PFIFO_FAST_BANDS 3 +- +-/* +- * Private data for a pfifo_fast scheduler containing: +- * - rings for priority bands +- */ +-struct pfifo_fast_priv { +- struct skb_array q[PFIFO_FAST_BANDS]; +-}; +- +-static inline struct skb_array *band2list(struct pfifo_fast_priv *priv, +- int band) +-{ +- return &priv->q[band]; +-} +- +-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, +- struct sk_buff **to_free) +-{ +- int band = prio2band[skb->priority & TC_PRIO_MAX]; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- struct skb_array *q = band2list(priv, band); +- unsigned int pkt_len = qdisc_pkt_len(skb); +- int err; +- +- err = skb_array_produce(q, skb); +- +- if (unlikely(err)) { +- if (qdisc_is_percpu_stats(qdisc)) +- return qdisc_drop_cpu(skb, qdisc, to_free); +- else +- return qdisc_drop(skb, qdisc, to_free); +- } +- +- qdisc_update_stats_at_enqueue(qdisc, pkt_len); +- return NET_XMIT_SUCCESS; +-} +- +-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- struct sk_buff *skb = NULL; +- bool need_retry = true; +- int band; +- +-retry: +- for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) { +- struct skb_array *q = band2list(priv, band); +- +- if (__skb_array_empty(q)) +- continue; +- +- skb = __skb_array_consume(q); +- } +- if (likely(skb)) { +- qdisc_update_stats_at_dequeue(qdisc, skb); +- } else if (need_retry && +- test_bit(__QDISC_STATE_MISSED, &qdisc->state)) { +- /* Delay clearing the STATE_MISSED here to reduce +- * the overhead of the second spin_trylock() in +- * qdisc_run_begin() and __netif_schedule() calling +- * in qdisc_run_end(). +- */ +- clear_bit(__QDISC_STATE_MISSED, &qdisc->state); +- +- /* Make sure dequeuing happens after clearing +- * STATE_MISSED. +- */ +- smp_mb__after_atomic(); +- +- need_retry = false; +- +- goto retry; +- } else { +- WRITE_ONCE(qdisc->empty, true); +- } +- +- return skb; +-} +- +-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- struct sk_buff *skb = NULL; +- int band; +- +- for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) { +- struct skb_array *q = band2list(priv, band); +- +- skb = __skb_array_peek(q); +- } +- +- return skb; +-} +- +-static void pfifo_fast_reset(struct Qdisc *qdisc) +-{ +- int i, band; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- +- for (band = 0; band < PFIFO_FAST_BANDS; band++) { +- struct skb_array *q = band2list(priv, band); +- struct sk_buff *skb; +- +- /* NULL ring is possible if destroy path is due to a failed +- * skb_array_init() in pfifo_fast_init() case. +- */ +- if (!q->ring.queue) +- continue; +- +- while ((skb = __skb_array_consume(q)) != NULL) +- kfree_skb(skb); +- } +- +- if (qdisc_is_percpu_stats(qdisc)) { +- for_each_possible_cpu(i) { +- struct gnet_stats_queue *q; +- +- q = per_cpu_ptr(qdisc->cpu_qstats, i); +- q->backlog = 0; +- q->qlen = 0; +- } +- } +-} +- +-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) +-{ +- struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; +- +- memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1); +- if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) +- goto nla_put_failure; +- return skb->len; +- +-nla_put_failure: +- return -1; +-} +- +-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt, +- struct netlink_ext_ack *extack) +-{ +- unsigned int qlen = qdisc_dev(qdisc)->tx_queue_len; +- struct pfifo_fast_priv *priv = qdisc_priv(qdisc); +- int prio; +- +- /* guard against zero length rings */ +- if (!qlen) +- return -EINVAL; +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { +- struct skb_array *q = band2list(priv, prio); +- int err; +- +- err = skb_array_init(q, qlen, GFP_KERNEL); +- if (err) +- return -ENOMEM; +- } +- +- /* Can by-pass the queue discipline */ +- qdisc->flags |= TCQ_F_CAN_BYPASS; +- return 0; +-} +- +-static void pfifo_fast_destroy(struct Qdisc *sch) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(sch); +- int prio; +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { +- struct skb_array *q = band2list(priv, prio); +- +- /* NULL ring is possible if destroy path is due to a failed +- * skb_array_init() in pfifo_fast_init() case. +- */ +- if (!q->ring.queue) +- continue; +- /* Destroy ring but no need to kfree_skb because a call to +- * pfifo_fast_reset() has already done that work. +- */ +- ptr_ring_cleanup(&q->ring, NULL); +- } +-} +- +-static int pfifo_fast_change_tx_queue_len(struct Qdisc *sch, +- unsigned int new_len) +-{ +- struct pfifo_fast_priv *priv = qdisc_priv(sch); +- struct skb_array *bands[PFIFO_FAST_BANDS]; +- int prio; +- +- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { +- struct skb_array *q = band2list(priv, prio); +- +- bands[prio] = q; +- } +- +- return skb_array_resize_multiple(bands, PFIFO_FAST_BANDS, new_len, +- GFP_KERNEL); +-} +- +-struct Qdisc_ops pfifo_fast_ops __read_mostly = { +- .id = "pfifo_fast", +- .priv_size = sizeof(struct pfifo_fast_priv), +- .enqueue = pfifo_fast_enqueue, +- .dequeue = pfifo_fast_dequeue, +- .peek = pfifo_fast_peek, +- .init = pfifo_fast_init, +- .destroy = pfifo_fast_destroy, +- .reset = pfifo_fast_reset, +- .dump = pfifo_fast_dump, +- .change_tx_queue_len = pfifo_fast_change_tx_queue_len, +- .owner = THIS_MODULE, +- .static_flags = TCQ_F_NOLOCK | TCQ_F_CPUSTATS, +-}; +-EXPORT_SYMBOL(pfifo_fast_ops); +- + struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, + const struct Qdisc_ops *ops, + struct netlink_ext_ack *extack) diff --git a/ipq806x/hack-5.4/700-swconfig_switch_drivers.patch b/ipq806x/hack-5.4/700-swconfig_switch_drivers.patch new file mode 100644 index 0000000..f30ad81 --- /dev/null +++ b/ipq806x/hack-5.4/700-swconfig_switch_drivers.patch @@ -0,0 +1,135 @@ +From 36e516290611e613aa92996cb4339561452695b4 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:24:23 +0200 +Subject: net: swconfig: adds openwrt switch layer + +Signed-off-by: Felix Fietkau +--- + drivers/net/phy/Kconfig | 83 +++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/phy/Makefile | 15 +++++++++ + include/uapi/linux/Kbuild | 1 + + 3 files changed, 99 insertions(+) + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -250,6 +250,85 @@ config LED_TRIGGER_PHY + for any speed known to the PHY. + + ++comment "Switch configuration API + drivers" ++ ++config SWCONFIG ++ tristate "Switch configuration API" ++ ---help--- ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ ++config SWCONFIG_LEDS ++ bool "Switch LED trigger support" ++ depends on (SWCONFIG && LEDS_TRIGGERS) ++ ++config ADM6996_PHY ++ tristate "Driver for ADM6996 switches" ++ select SWCONFIG ++ ---help--- ++ Currently supports the ADM6996FC and ADM6996M switches. ++ Support for FC is very limited. ++ ++config AR8216_PHY ++ tristate "Driver for Atheros AR8216 switches" ++ select ETHERNET_PACKET_MANGLE ++ select SWCONFIG ++ ++config AR8216_PHY_LEDS ++ bool "Atheros AR8216 switch LED support" ++ depends on (AR8216_PHY && LEDS_CLASS) ++ ++source "drivers/net/phy/b53/Kconfig" ++ ++config IP17XX_PHY ++ tristate "Driver for IC+ IP17xx switches" ++ select SWCONFIG ++ ++config MVSWITCH_PHY ++ tristate "Driver for Marvell 88E6060 switches" ++ select ETHERNET_PACKET_MANGLE ++ ++config PSB6970_PHY ++ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" ++ select SWCONFIG ++ select ETHERNET_PACKET_MANGLE ++ ++config RTL8306_PHY ++ tristate "Driver for Realtek RTL8306S switches" ++ select SWCONFIG ++ ++config RTL8366_SMI ++ tristate "Driver for the RTL8366 SMI interface" ++ depends on GPIOLIB ++ ---help--- ++ This module implements the SMI interface protocol which is used ++ by some RTL8366 ethernet switch devices via the generic GPIO API. ++ ++if RTL8366_SMI ++ ++config RTL8366_SMI_DEBUG_FS ++ bool "RTL8366 SMI interface debugfs support" ++ depends on DEBUG_FS ++ default n ++ ++config RTL8366S_PHY ++ tristate "Driver for the Realtek RTL8366S switch" ++ select SWCONFIG ++ ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ ++config RTL8367_PHY ++ tristate "Driver for the Realtek RTL8367R/M switches" ++ select SWCONFIG ++ ++config RTL8367B_PHY ++ tristate "Driver fot the Realtek RTL8367R-VB switch" ++ select SWCONFIG ++ ++endif # RTL8366_SMI ++ + comment "MII PHY device drivers" + + config SFP +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -22,6 +22,20 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_ + obj-$(CONFIG_PHYLINK) += phylink.o + obj-$(CONFIG_PHYLIB) += libphy.o + ++obj-$(CONFIG_SWCONFIG) += swconfig.o ++obj-$(CONFIG_ADM6996_PHY) += adm6996.o ++obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o ++obj-$(CONFIG_SWCONFIG_B53) += b53/ ++obj-$(CONFIG_IP17XX_PHY) += ip17xx.o ++obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o ++obj-$(CONFIG_PSB6970_PHY) += psb6970.o ++obj-$(CONFIG_RTL8306_PHY) += rtl8306.o ++obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o ++obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o ++obj-$(CONFIG_RTL8367_PHY) += rtl8367.o ++obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o ++ + obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o + obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o + obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o +--- a/include/linux/platform_data/b53.h ++++ b/include/linux/platform_data/b53.h +@@ -29,6 +29,9 @@ struct b53_platform_data { + u32 chip_id; + u16 enabled_ports; + ++ /* allow to specify an ethX alias */ ++ const char *alias; ++ + /* only used by MMAP'd driver */ + unsigned big_endian:1; + void __iomem *regs; diff --git a/ipq806x/hack-5.4/703-add_vsc8504_support.patch b/ipq806x/hack-5.4/703-add_vsc8504_support.patch new file mode 100644 index 0000000..afb6ca6 --- /dev/null +++ b/ipq806x/hack-5.4/703-add_vsc8504_support.patch @@ -0,0 +1,57 @@ +From: Roman Kuzmitskii +Date: Thu, 05 Nov 2020 02:00:00 +0000 +Subject: [PATCH] net: phy: vitesse: add vsc8504 support + +This patch adds support for vsc8504 phy. +That phy is changed owner: + vitesse -> microsemi -> microchip +So is its driver in kernel was changed and rewritten. + +there is no need to upstream this patch. +this vsc8504 is supported by newer kernels out of box. +support could be enabled by CONFIG_MICROSEMI_PHY. + +Tested-by: Johannes Kimmel +Signed-off-by: Roman Kuzmitskii +--- a/drivers/net/phy/vitesse.c ++++ b/drivers/net/phy/vitesse.c +@@ -61,6 +61,7 @@ + + #define PHY_ID_VSC8234 0x000fc620 + #define PHY_ID_VSC8244 0x000fc6c0 ++#define PHY_ID_VSC8504 0x000704c2 + #define PHY_ID_VSC8572 0x000704d0 + #define PHY_ID_VSC8601 0x00070420 + #define PHY_ID_VSC7385 0x00070450 +@@ -292,6 +293,7 @@ static int vsc82xx_config_intr(struct ph + err = phy_write(phydev, MII_VSC8244_IMASK, + (phydev->drv->phy_id == PHY_ID_VSC8234 || + phydev->drv->phy_id == PHY_ID_VSC8244 || ++ phydev->drv->phy_id == PHY_ID_VSC8504 || + phydev->drv->phy_id == PHY_ID_VSC8572 || + phydev->drv->phy_id == PHY_ID_VSC8601) ? + MII_VSC8244_IMASK_MASK : +@@ -402,6 +404,15 @@ static struct phy_driver vsc82xx_driver[ + .ack_interrupt = &vsc824x_ack_interrupt, + .config_intr = &vsc82xx_config_intr, + }, { ++ .phy_id = PHY_ID_VSC8504, ++ .name = "Vitesse VSC8504", ++ .phy_id_mask = 0x000ffff0, ++ /* PHY_GBIT_FEATURES */ ++ .config_init = &vsc824x_config_init, ++ .config_aneg = &vsc82x4_config_aneg, ++ .ack_interrupt = &vsc824x_ack_interrupt, ++ .config_intr = &vsc82xx_config_intr, ++}, { + .phy_id = PHY_ID_VSC8572, + .name = "Vitesse VSC8572", + .phy_id_mask = 0x000ffff0, +@@ -488,6 +499,7 @@ module_phy_driver(vsc82xx_driver); + static struct mdio_device_id __maybe_unused vitesse_tbl[] = { + { PHY_ID_VSC8234, 0x000ffff0 }, + { PHY_ID_VSC8244, 0x000fffc0 }, ++ { PHY_ID_VSC8504, 0x000ffff0 }, + { PHY_ID_VSC8572, 0x000ffff0 }, + { PHY_ID_VSC7385, 0x000ffff0 }, + { PHY_ID_VSC7388, 0x000ffff0 }, diff --git a/ipq806x/hack-5.4/710-net-dsa-mv88e6xxx-default-VID-1.patch b/ipq806x/hack-5.4/710-net-dsa-mv88e6xxx-default-VID-1.patch new file mode 100644 index 0000000..5dc5ac6 --- /dev/null +++ b/ipq806x/hack-5.4/710-net-dsa-mv88e6xxx-default-VID-1.patch @@ -0,0 +1,18 @@ +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -1930,6 +1930,7 @@ static int mv88e6xxx_port_fdb_add(struct + struct mv88e6xxx_chip *chip = ds->priv; + int err; + ++ vid = vid ? : 1; + mv88e6xxx_reg_lock(chip); + err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, + MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC); +@@ -1944,6 +1945,7 @@ static int mv88e6xxx_port_fdb_del(struct + struct mv88e6xxx_chip *chip = ds->priv; + int err; + ++ vid = vid ? : 1; + mv88e6xxx_reg_lock(chip); + err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid, 0); + mv88e6xxx_reg_unlock(chip); diff --git a/ipq806x/hack-5.4/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch b/ipq806x/hack-5.4/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch new file mode 100644 index 0000000..1da388c --- /dev/null +++ b/ipq806x/hack-5.4/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch @@ -0,0 +1,12 @@ +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -2492,6 +2492,9 @@ static int mv88e6xxx_setup_port(struct m + if (dsa_is_cpu_port(ds, port)) + reg = 0; + ++ /* Disable ATU member violation interrupt */ ++ reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG; ++ + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, + reg); + if (err) diff --git a/ipq806x/hack-5.4/721-phy_packets.patch b/ipq806x/hack-5.4/721-phy_packets.patch new file mode 100644 index 0000000..bc9b3a4 --- /dev/null +++ b/ipq806x/hack-5.4/721-phy_packets.patch @@ -0,0 +1,176 @@ +From ffe387740bbe88dd88bbe04d6375902708003d6e Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:25:00 +0200 +Subject: net: add packet mangeling patch + +Signed-off-by: Felix Fietkau +--- + include/linux/netdevice.h | 11 +++++++++++ + include/linux/skbuff.h | 14 ++++---------- + net/Kconfig | 6 ++++++ + net/core/dev.c | 18 ++++++++++++++---- + net/core/skbuff.c | 17 +++++++++++++++++ + net/ethernet/eth.c | 6 ++++++ + 6 files changed, 58 insertions(+), 14 deletions(-) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1549,6 +1549,7 @@ enum netdev_priv_flags { + IFF_FAILOVER_SLAVE = 1<<28, + IFF_L3MDEV_RX_HANDLER = 1<<29, + IFF_LIVE_RENAME_OK = 1<<30, ++ IFF_NO_IP_ALIGN = 1<<31, + }; + + #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN +@@ -1581,6 +1582,7 @@ enum netdev_priv_flags { + #define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE + #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER + #define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK ++#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN + + /* Specifies the type of the struct net_device::ml_priv pointer */ + enum netdev_ml_priv_type { +@@ -1889,6 +1891,11 @@ struct net_device { + const struct tlsdev_ops *tlsdev_ops; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); ++ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); ++#endif ++ + const struct header_ops *header_ops; + + unsigned int flags; +@@ -1971,6 +1978,10 @@ struct net_device { + struct mpls_dev __rcu *mpls_ptr; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void *phy_ptr; /* PHY device specific data */ ++#endif ++ + /* + * Cache lines mostly used on receive path (including eth_type_trans()) + */ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2684,6 +2684,10 @@ static inline int pskb_trim(struct sk_bu + return (len < skb->len) ? __pskb_trim(skb, len) : 0; + } + ++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp); ++ ++ + /** + * pskb_trim_unique - remove end from a paged unique (not cloned) buffer + * @skb: buffer to alter +@@ -2815,16 +2819,6 @@ static inline struct sk_buff *dev_alloc_ + } + + +-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, +- unsigned int length, gfp_t gfp) +-{ +- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); +- +- if (NET_IP_ALIGN && skb) +- skb_reserve(skb, NET_IP_ALIGN); +- return skb; +-} +- + static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length) + { +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -26,6 +26,12 @@ menuconfig NET + + if NET + ++config ETHERNET_PACKET_MANGLE ++ bool ++ help ++ This option can be selected by phy drivers that need to mangle ++ packets going in or out of an ethernet device. ++ + config WANT_COMPAT_NETLINK_MESSAGES + bool + help +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3198,10 +3198,20 @@ static int xmit_one(struct sk_buff *skb, + if (dev_nit_active(dev)) + dev_queue_xmit_nit(skb, dev); + +- len = skb->len; +- trace_net_dev_start_xmit(skb, dev); +- rc = netdev_start_xmit(skb, dev, txq, more); +- trace_net_dev_xmit(skb, rc, dev, len); ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (!dev->eth_mangle_tx || ++ (skb = dev->eth_mangle_tx(dev, skb)) != NULL) ++#else ++ if (1) ++#endif ++ { ++ len = skb->len; ++ trace_net_dev_start_xmit(skb, dev); ++ rc = netdev_start_xmit(skb, dev, txq, more); ++ trace_net_dev_xmit(skb, rc, dev, len); ++ } else { ++ rc = NETDEV_TX_OK; ++ } + + return rc; + } +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -60,6 +60,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -549,6 +550,22 @@ skb_fail: + } + EXPORT_SYMBOL(__napi_alloc_skb); + ++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp) ++{ ++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN)) ++ return skb; ++#endif ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); ++ + void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, + int size, unsigned int truesize) + { +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -171,6 +171,12 @@ __be16 eth_type_trans(struct sk_buff *sk + const struct ethhdr *eth; + + skb->dev = dev; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_rx) ++ dev->eth_mangle_rx(dev, skb); ++#endif ++ + skb_reset_mac_header(skb); + + eth = (struct ethhdr *)skb->data; diff --git a/ipq806x/hack-5.4/773-bgmac-add-srab-switch.patch b/ipq806x/hack-5.4/773-bgmac-add-srab-switch.patch new file mode 100644 index 0000000..89e0df4 --- /dev/null +++ b/ipq806x/hack-5.4/773-bgmac-add-srab-switch.patch @@ -0,0 +1,98 @@ +From 3cb240533ab787899dc7f17aa7d6c5b4810e2e58 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Fri, 7 Jul 2017 17:26:01 +0200 +Subject: bcm53xx: bgmac: use srab switch driver + +use the srab switch driver on these SoCs. + +Signed-off-by: Hauke Mehrtens +--- + drivers/net/ethernet/broadcom/bgmac-bcma.c | 1 + + drivers/net/ethernet/broadcom/bgmac.c | 24 ++++++++++++++++++++++++ + drivers/net/ethernet/broadcom/bgmac.h | 4 ++++ + 3 files changed, 29 insertions(+) + +--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c ++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c +@@ -268,6 +268,7 @@ static int bgmac_probe(struct bcma_devic + bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; + bgmac->feature_flags |= BGMAC_FEAT_NO_RESET; + bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500; ++ bgmac->feature_flags |= BGMAC_FEAT_SRAB; + break; + default: + bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1407,6 +1408,17 @@ static const struct ethtool_ops bgmac_et + .set_link_ksettings = phy_ethtool_set_link_ksettings, + }; + ++static struct b53_platform_data bgmac_b53_pdata = { ++}; ++ ++static struct platform_device bgmac_b53_dev = { ++ .name = "b53-srab-switch", ++ .id = -1, ++ .dev = { ++ .platform_data = &bgmac_b53_pdata, ++ }, ++}; ++ + /************************************************** + * MII + **************************************************/ +@@ -1538,6 +1550,14 @@ int bgmac_enet_probe(struct bgmac *bgmac + net_dev->hw_features = net_dev->features; + net_dev->vlan_features = net_dev->features; + ++ if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) { ++ bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000); ++ ++ err = platform_device_register(&bgmac_b53_dev); ++ if (!err) ++ bgmac->b53_device = &bgmac_b53_dev; ++ } ++ + err = register_netdev(bgmac->net_dev); + if (err) { + dev_err(bgmac->dev, "Cannot register net device\n"); +@@ -1560,6 +1580,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe); + + void bgmac_enet_remove(struct bgmac *bgmac) + { ++ if (bgmac->b53_device) ++ platform_device_unregister(&bgmac_b53_dev); ++ bgmac->b53_device = NULL; ++ + unregister_netdev(bgmac->net_dev); + phy_disconnect(bgmac->net_dev->phydev); + netif_napi_del(&bgmac->napi); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -427,6 +427,7 @@ + #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18) + #define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19) + #define BGMAC_FEAT_IDM_MASK BIT(20) ++#define BGMAC_FEAT_SRAB BIT(21) + + struct bgmac_slot_info { + union { +@@ -532,6 +533,9 @@ struct bgmac { + void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask, + u32 set); + int (*phy_connect)(struct bgmac *bgmac); ++ ++ /* platform device for associated switch */ ++ struct platform_device *b53_device; + }; + + struct bgmac *bgmac_alloc(struct device *dev); diff --git a/ipq806x/hack-5.4/901-debloat_sock_diag.patch b/ipq806x/hack-5.4/901-debloat_sock_diag.patch new file mode 100644 index 0000000..0abb672 --- /dev/null +++ b/ipq806x/hack-5.4/901-debloat_sock_diag.patch @@ -0,0 +1,145 @@ +From 3b6115d6b57a263bdc8c9b1df273bd4a7955eead Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:16:31 +0200 +Subject: debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS + +Signed-off-by: Felix Fietkau +--- + net/Kconfig | 3 +++ + net/core/Makefile | 3 ++- + net/core/sock.c | 2 ++ + net/ipv4/Kconfig | 1 + + net/netlink/Kconfig | 1 + + net/packet/Kconfig | 1 + + net/unix/Kconfig | 1 + + 7 files changed, 11 insertions(+), 1 deletion(-) + +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -103,6 +103,9 @@ source "net/netlabel/Kconfig" + + endif # if INET + ++config SOCK_DIAG ++ bool ++ + config NETWORK_SECMARK + bool "Security Marking" + help +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -10,9 +10,10 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. + + obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ + neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ +- sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ ++ dev_ioctl.o tso.o sock_reuseport.o \ + fib_notifier.o xdp.o flow_offload.o + ++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o + obj-y += net-sysfs.o + obj-$(CONFIG_PAGE_POOL) += page_pool.o + obj-$(CONFIG_PROC_FS) += net-procfs.o +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -140,6 +140,7 @@ + + static DEFINE_MUTEX(proto_list_mutex); + static LIST_HEAD(proto_list); ++static atomic64_t cookie_gen; + + static void sock_inuse_add(struct net *net, int val); + +@@ -539,6 +540,18 @@ discard_and_relse: + } + EXPORT_SYMBOL(__sk_receive_skb); + ++u64 sock_gen_cookie(struct sock *sk) ++{ ++ while (1) { ++ u64 res = atomic64_read(&sk->sk_cookie); ++ ++ if (res) ++ return res; ++ res = atomic64_inc_return(&cookie_gen); ++ atomic64_cmpxchg(&sk->sk_cookie, 0, res); ++ } ++} ++ + struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) + { + struct dst_entry *dst = __sk_dst_get(sk); +@@ -1760,9 +1773,11 @@ static void __sk_free(struct sock *sk) + if (likely(sk->sk_net_refcnt)) + sock_inuse_add(sock_net(sk), -1); + ++#ifdef CONFIG_SOCK_DIAG + if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk))) + sock_diag_broadcast_destroy(sk); + else ++#endif + sk_destruct(sk); + } + +--- a/net/core/sock_diag.c ++++ b/net/core/sock_diag.c +@@ -19,19 +19,6 @@ static const struct sock_diag_handler *s + static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); + static DEFINE_MUTEX(sock_diag_table_mutex); + static struct workqueue_struct *broadcast_wq; +-static atomic64_t cookie_gen; +- +-u64 sock_gen_cookie(struct sock *sk) +-{ +- while (1) { +- u64 res = atomic64_read(&sk->sk_cookie); +- +- if (res) +- return res; +- res = atomic64_inc_return(&cookie_gen); +- atomic64_cmpxchg(&sk->sk_cookie, 0, res); +- } +-} + + int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) + { +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -400,6 +400,7 @@ config INET_TUNNEL + + config INET_DIAG + tristate "INET: socket monitoring interface" ++ select SOCK_DIAG + default y + ---help--- + Support for INET (TCP, DCCP, etc) socket monitoring interface used by +--- a/net/netlink/Kconfig ++++ b/net/netlink/Kconfig +@@ -5,6 +5,7 @@ + + config NETLINK_DIAG + tristate "NETLINK: socket monitoring interface" ++ select SOCK_DIAG + default n + ---help--- + Support for NETLINK socket monitoring interface used by the ss tool. +--- a/net/packet/Kconfig ++++ b/net/packet/Kconfig +@@ -19,6 +19,7 @@ config PACKET + config PACKET_DIAG + tristate "Packet: sockets monitoring interface" + depends on PACKET ++ select SOCK_DIAG + default n + ---help--- + Support for PF_PACKET sockets monitoring interface used by the ss tool. +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -28,6 +28,7 @@ config UNIX_SCM + config UNIX_DIAG + tristate "UNIX: socket monitoring interface" + depends on UNIX ++ select SOCK_DIAG + default n + ---help--- + Support for UNIX socket monitoring interface used by the ss tool. diff --git a/ipq806x/hack-5.4/902-debloat_proc.patch b/ipq806x/hack-5.4/902-debloat_proc.patch new file mode 100644 index 0000000..042588a --- /dev/null +++ b/ipq806x/hack-5.4/902-debloat_proc.patch @@ -0,0 +1,408 @@ +From 9e3f1d0805b2d919904dd9a4ff0d956314cc3cba Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:20:09 +0200 +Subject: debloat: procfs + +Signed-off-by: Felix Fietkau +--- + fs/locks.c | 2 ++ + fs/proc/Kconfig | 5 +++++ + fs/proc/consoles.c | 3 +++ + fs/proc/proc_tty.c | 11 ++++++++++- + include/net/snmp.h | 18 +++++++++++++++++- + ipc/msg.c | 3 +++ + ipc/sem.c | 2 ++ + ipc/shm.c | 2 ++ + ipc/util.c | 3 +++ + kernel/exec_domain.c | 2 ++ + kernel/irq/proc.c | 9 +++++++++ + kernel/time/timer_list.c | 2 ++ + mm/vmalloc.c | 2 ++ + mm/vmstat.c | 8 +++++--- + net/8021q/vlanproc.c | 6 ++++++ + net/core/net-procfs.c | 18 ++++++++++++------ + net/core/sock.c | 2 ++ + net/ipv4/fib_trie.c | 18 ++++++++++++------ + net/ipv4/proc.c | 3 +++ + net/ipv4/route.c | 3 +++ + 20 files changed, 105 insertions(+), 17 deletions(-) + +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2989,6 +2989,8 @@ static const struct seq_operations locks + + static int __init proc_locks_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create_seq_private("locks", 0, NULL, &locks_seq_operations, + sizeof(struct locks_iterator), NULL); + return 0; +--- a/fs/proc/Kconfig ++++ b/fs/proc/Kconfig +@@ -100,6 +100,11 @@ config PROC_CHILDREN + Say Y if you are running any user-space software which takes benefit from + this interface. For example, rkt is such a piece of software. + ++config PROC_STRIPPED ++ default n ++ depends on EXPERT ++ bool "Strip non-essential /proc functionality to reduce code size" ++ + config PROC_PID_ARCH_STATUS + def_bool n + depends on PROC_FS +--- a/fs/proc/consoles.c ++++ b/fs/proc/consoles.c +@@ -92,6 +92,9 @@ static const struct seq_operations conso + + static int __init proc_consoles_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + proc_create_seq("consoles", 0, NULL, &consoles_op); + return 0; + } +--- a/fs/proc/proc_tty.c ++++ b/fs/proc/proc_tty.c +@@ -133,7 +133,10 @@ static const struct seq_operations tty_d + void proc_tty_register_driver(struct tty_driver *driver) + { + struct proc_dir_entry *ent; +- ++ ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!driver->driver_name || driver->proc_entry || + !driver->ops->proc_show) + return; +@@ -150,6 +153,9 @@ void proc_tty_unregister_driver(struct t + { + struct proc_dir_entry *ent; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ent = driver->proc_entry; + if (!ent) + return; +@@ -164,6 +170,9 @@ void proc_tty_unregister_driver(struct t + */ + void __init proc_tty_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!proc_mkdir("tty", NULL)) + return; + proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ +--- a/include/net/snmp.h ++++ b/include/net/snmp.h +@@ -118,6 +118,21 @@ struct linux_xfrm_mib { + #define DECLARE_SNMP_STAT(type, name) \ + extern __typeof__(type) __percpu *name + ++#ifdef CONFIG_PROC_STRIPPED ++#define __SNMP_STATS_DUMMY(mib) \ ++ do { (void) mib->mibs[0]; } while(0) ++ ++#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) ++#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) ++#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) ++#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) ++ ++#else ++ + #define __SNMP_INC_STATS(mib, field) \ + __this_cpu_inc(mib->mibs[field]) + +@@ -148,8 +163,9 @@ struct linux_xfrm_mib { + __this_cpu_add(ptr[basefield##OCTETS], addend); \ + } while (0) + ++#endif + +-#if BITS_PER_LONG==32 ++#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED) + + #define __SNMP_ADD_STATS64(mib, field, addend) \ + do { \ +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -1317,6 +1317,9 @@ void __init msg_init(void) + { + msg_init_ns(&init_ipc_ns); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ipc_init_proc_interface("sysvipc/msg", + " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", + IPC_MSG_IDS, sysvipc_msg_proc_show); +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -243,6 +243,8 @@ void sem_exit_ns(struct ipc_namespace *n + void __init sem_init(void) + { + sem_init_ns(&init_ipc_ns); ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/sem", + " key semid perms nsems uid gid cuid cgid otime ctime\n", + IPC_SEM_IDS, sysvipc_sem_proc_show); +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -144,6 +144,8 @@ pure_initcall(ipc_ns_init); + + void __init shm_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/shm", + #if BITS_PER_LONG <= 32 + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -140,6 +140,9 @@ void __init ipc_init_proc_interface(cons + struct proc_dir_entry *pde; + struct ipc_proc_iface *iface; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + iface = kmalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return; +--- a/kernel/exec_domain.c ++++ b/kernel/exec_domain.c +@@ -29,6 +29,8 @@ static int execdomains_proc_show(struct + + static int __init proc_execdomains_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create_single("execdomains", 0, NULL, execdomains_proc_show); + return 0; + } +--- a/kernel/irq/proc.c ++++ b/kernel/irq/proc.c +@@ -341,6 +341,9 @@ void register_irq_proc(unsigned int irq, + void __maybe_unused *irqp = (void *)(unsigned long) irq; + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip)) + return; + +@@ -394,6 +397,9 @@ void unregister_irq_proc(unsigned int ir + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || !desc->dir) + return; + #ifdef CONFIG_SMP +@@ -432,6 +438,9 @@ void init_irq_proc(void) + unsigned int irq; + struct irq_desc *desc; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + if (!root_irq_dir) +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -370,6 +370,8 @@ static int __init init_timer_list_procfs + { + struct proc_dir_entry *pe; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops, + sizeof(struct timer_list_iter), NULL); + if (!pe) +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -3564,6 +3564,8 @@ static const struct seq_operations vmall + + static int __init proc_vmalloc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + if (IS_ENABLED(CONFIG_NUMA)) + proc_create_seq_private("vmallocinfo", 0400, NULL, + &vmalloc_op, +--- a/mm/vmstat.c ++++ b/mm/vmstat.c +@@ -1988,10 +1988,12 @@ void __init init_mm_internals(void) + start_shepherd_timer(); + #endif + #ifdef CONFIG_PROC_FS +- proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); +- proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); ++ proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); ++ proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); ++ } + proc_create_seq("vmstat", 0444, NULL, &vmstat_op); +- proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); + #endif + } + +--- a/net/8021q/vlanproc.c ++++ b/net/8021q/vlanproc.c +@@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net) + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (vn->proc_vlan_conf) + remove_proc_entry(name_conf, vn->proc_vlan_dir); + +@@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); + if (!vn->proc_vlan_dir) + goto err; +--- a/net/core/net-procfs.c ++++ b/net/core/net-procfs.c +@@ -279,10 +279,12 @@ static int __net_init dev_proc_net_init( + if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops, + sizeof(struct seq_net_private))) + goto out; +- if (!proc_create_seq("softnet_stat", 0444, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_seq("softnet_stat", 0444, net->proc_net, + &softnet_seq_ops)) + goto out_dev; +- if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, + sizeof(struct seq_net_private))) + goto out_softnet; + +@@ -292,9 +294,11 @@ static int __net_init dev_proc_net_init( + out: + return rc; + out_ptype: +- remove_proc_entry("ptype", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("ptype", net->proc_net); + out_softnet: +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("softnet_stat", net->proc_net); + out_dev: + remove_proc_entry("dev", net->proc_net); + goto out; +@@ -304,8 +308,10 @@ static void __net_exit dev_proc_net_exit + { + wext_proc_exit(net); + +- remove_proc_entry("ptype", net->proc_net); +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("ptype", net->proc_net); ++ remove_proc_entry("softnet_stat", net->proc_net); ++ } + remove_proc_entry("dev", net->proc_net); + } + +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -3643,6 +3643,8 @@ static __net_initdata struct pernet_oper + + static int __init proto_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + return register_pernet_subsys(&proto_net_ops); + } + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2848,11 +2848,13 @@ static const struct seq_operations fib_r + + int __net_init fib_proc_init(struct net *net) + { +- if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, + sizeof(struct fib_trie_iter))) + goto out1; + +- if (!proc_create_net_single("fib_triestat", 0444, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net_single("fib_triestat", 0444, net->proc_net, + fib_triestat_seq_show, NULL)) + goto out2; + +@@ -2863,17 +2865,21 @@ int __net_init fib_proc_init(struct net + return 0; + + out3: +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_triestat", net->proc_net); + out2: +- remove_proc_entry("fib_trie", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_trie", net->proc_net); + out1: + return -ENOMEM; + } + + void __net_exit fib_proc_exit(struct net *net) + { +- remove_proc_entry("fib_trie", net->proc_net); +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("fib_trie", net->proc_net); ++ remove_proc_entry("fib_triestat", net->proc_net); ++ } + remove_proc_entry("route", net->proc_net); + } + +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -522,5 +522,8 @@ static __net_initdata struct pernet_oper + + int __init ip_misc_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_proc_ops); + } +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -410,6 +410,9 @@ static struct pernet_operations ip_rt_pr + + static int __init ip_rt_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_rt_proc_ops); + } + diff --git a/ipq806x/hack-5.4/904-debloat_dma_buf.patch b/ipq806x/hack-5.4/904-debloat_dma_buf.patch new file mode 100644 index 0000000..ad8636b --- /dev/null +++ b/ipq806x/hack-5.4/904-debloat_dma_buf.patch @@ -0,0 +1,74 @@ +From e3692cb2fcd5ba1244512a0f43b8118f65f1c375 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:20:43 +0200 +Subject: debloat: dmabuf + +Signed-off-by: Felix Fietkau +--- + drivers/base/Kconfig | 2 +- + drivers/dma-buf/Makefile | 10 +++++++--- + drivers/dma-buf/dma-buf.c | 4 +++- + kernel/sched/core.c | 1 + + 4 files changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -179,7 +179,7 @@ config SOC_BUS + source "drivers/base/regmap/Kconfig" + + config DMA_SHARED_BUFFER +- bool ++ tristate + default n + select IRQ_WORK + help +--- a/drivers/dma-buf/Makefile ++++ b/drivers/dma-buf/Makefile +@@ -1,9 +1,13 @@ + # SPDX-License-Identifier: GPL-2.0-only +-obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ +- dma-resv.o seqno-fence.o +-obj-$(CONFIG_SYNC_FILE) += sync_file.o +-obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +-obj-$(CONFIG_UDMABUF) += udmabuf.o ++obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o ++ ++dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ ++ dma-resv.o seqno-fence.o ++dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o ++dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o ++dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o ++ ++dma-shared-buffer-objs := $(dma-buf-objs-y) + + dmabuf_selftests-y := \ + selftest.o \ +--- a/drivers/dma-buf/dma-buf.c ++++ b/drivers/dma-buf/dma-buf.c +@@ -1313,4 +1313,5 @@ static void __exit dma_buf_deinit(void) + dma_buf_uninit_debugfs(); + kern_unmount(dma_buf_mnt); + } +-__exitcall(dma_buf_deinit); ++module_exit(dma_buf_deinit); ++MODULE_LICENSE("GPL"); +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -2767,6 +2767,7 @@ int wake_up_state(struct task_struct *p, + { + return try_to_wake_up(p, state, 0); + } ++EXPORT_SYMBOL_GPL(wake_up_state); + + /* + * Perform scheduler related setup for a newly forked process p. +--- a/fs/d_path.c ++++ b/fs/d_path.c +@@ -311,6 +311,7 @@ char *dynamic_dname(struct dentry *dentr + buffer += buflen - sz; + return memcpy(buffer, temp, sz); + } ++EXPORT_SYMBOL_GPL(dynamic_dname); + + char *simple_dname(struct dentry *dentry, char *buffer, int buflen) + { diff --git a/ipq806x/hack-5.4/910-kobject_uevent.patch b/ipq806x/hack-5.4/910-kobject_uevent.patch new file mode 100644 index 0000000..c4c41ca --- /dev/null +++ b/ipq806x/hack-5.4/910-kobject_uevent.patch @@ -0,0 +1,32 @@ +From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 16 Jul 2017 16:56:10 +0200 +Subject: lib: add uevent_next_seqnum() + +Signed-off-by: Felix Fietkau +--- + include/linux/kobject.h | 5 +++++ + lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -179,6 +179,18 @@ out: + return r; + } + ++u64 uevent_next_seqnum(void) ++{ ++ u64 seq; ++ ++ mutex_lock(&uevent_sock_mutex); ++ seq = ++uevent_seqnum; ++ mutex_unlock(&uevent_sock_mutex); ++ ++ return seq; ++} ++EXPORT_SYMBOL_GPL(uevent_next_seqnum); ++ + /** + * kobject_synth_uevent - send synthetic uevent with arguments + * diff --git a/ipq806x/hack-5.4/911-kobject_add_broadcast_uevent.patch b/ipq806x/hack-5.4/911-kobject_add_broadcast_uevent.patch new file mode 100644 index 0000000..6f5e50d --- /dev/null +++ b/ipq806x/hack-5.4/911-kobject_add_broadcast_uevent.patch @@ -0,0 +1,76 @@ +From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 16 Jul 2017 16:56:10 +0200 +Subject: lib: add uevent_next_seqnum() + +Signed-off-by: Felix Fietkau +--- + include/linux/kobject.h | 5 +++++ + lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -32,6 +32,8 @@ + #define UEVENT_NUM_ENVP 32 /* number of env pointers */ + #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ + ++struct sk_buff; ++ + #ifdef CONFIG_UEVENT_HELPER + /* path to the userspace helper executed on an event */ + extern char uevent_helper[]; +@@ -245,4 +247,7 @@ int kobject_synth_uevent(struct kobject + __printf(2, 3) + int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); + ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation); ++ + #endif /* _KOBJECT_H_ */ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -691,6 +691,43 @@ int add_uevent_var(struct kobj_uevent_en + EXPORT_SYMBOL_GPL(add_uevent_var); + + #if defined(CONFIG_NET) ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ struct uevent_sock *ue_sk; ++ int err = 0; ++ ++ /* send netlink message */ ++ mutex_lock(&uevent_sock_mutex); ++ list_for_each_entry(ue_sk, &uevent_sock_list, list) { ++ struct sock *uevent_sock = ue_sk->sk; ++ struct sk_buff *skb2; ++ ++ skb2 = skb_clone(skb, allocation); ++ if (!skb2) ++ break; ++ ++ err = netlink_broadcast(uevent_sock, skb2, pid, group, ++ allocation); ++ if (err) ++ break; ++ } ++ mutex_unlock(&uevent_sock_mutex); ++ ++ kfree_skb(skb); ++ return err; ++} ++#else ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ kfree_skb(skb); ++ return 0; ++} ++#endif ++EXPORT_SYMBOL_GPL(broadcast_uevent); ++ ++#if defined(CONFIG_NET) + static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb, + struct netlink_ext_ack *extack) + { diff --git a/ipq806x/hack-5.4/921-always-create-console-node-in-initramfs.patch b/ipq806x/hack-5.4/921-always-create-console-node-in-initramfs.patch new file mode 100644 index 0000000..e437579 --- /dev/null +++ b/ipq806x/hack-5.4/921-always-create-console-node-in-initramfs.patch @@ -0,0 +1,40 @@ +From 5d301596fdc72f6cb672f72eb3c66e7cddefb103 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:26:02 +0200 +Subject: initramfs: always create console node + +Signed-off-by: Felix Fietkau +--- + usr/gen_initramfs_list.sh | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/usr/gen_initramfs_list.sh ++++ b/usr/gen_initramfs_list.sh +@@ -59,6 +59,18 @@ default_initramfs() { + EOF + } + ++list_openwrt_initramfs() { ++ : ++} ++ ++openwrt_initramfs() { ++ # make sure that /dev/console exists ++ cat <<-EOF >> ${output} ++ dir /dev 0755 0 0 ++ nod /dev/console 0600 0 0 c 5 1 ++ EOF ++} ++ + filetype() { + local argv1="$1" + +@@ -180,6 +192,8 @@ dir_filelist() { + if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then + ${dep_list}print_mtime "$1" + ++ ${dep_list}openwrt_initramfs ++ + echo "${dirlist}" | \ + while read x; do + ${dep_list}parse ${x} diff --git a/ipq806x/image/Makefile b/ipq806x/image/Makefile new file mode 100644 index 0000000..8c00007 --- /dev/null +++ b/ipq806x/image/Makefile @@ -0,0 +1,438 @@ +# Copyright (c) 2014 The Linux Foundation. All rights reserved. +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID +DEVICE_VARS += TPLINK_BOARD_ID + +define Build/buffalo-rootfs-cksum + ( \ + echo -ne "\x$$(od -A n -t u1 $@ | tr -s ' ' '\n' | \ + $(STAGING_DIR_HOST)/bin/awk '{s+=$$0}END{printf "%x", 255-s%256}')"; \ + ) >> $@ +endef + +define Build/edimax-header + $(eval edimax_model=$(word 1,$(1))) + + $(STAGING_DIR_HOST)/bin/mkedimaximg \ + -b -s CSYS -m $(edimax_model) \ + -f 0x70000 -S 0x1200000 \ + -i $@ -o $@.new + @mv $@.new $@ +endef + +define Device/Default + PROFILES := Default + KERNEL_DEPENDS = $$(wildcard $(DTS_DIR)/$$(DEVICE_DTS).dts) + KERNEL_LOADADDR = 0x42208000 + DEVICE_DTS = $$(SOC)-$(lastword $(subst _, ,$(1))) + DEVICE_DTS_CONFIG := config@1 + IMAGES := sysupgrade.bin + IMAGE/sysupgrade.bin = sysupgrade-tar | append-metadata + IMAGE/sysupgrade.bin/squashfs := +endef + +define Device/LegacyImage + KERNEL_SUFFIX := -uImage + KERNEL = kernel-bin | append-dtb | uImage none + KERNEL_NAME := zImage +endef + +define Device/FitImage + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := Image +endef + +define Device/FitImageLzma + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := Image +endef + +define Device/UbiFit + KERNEL_IN_UBI := 1 + IMAGES := nand-factory.bin nand-sysupgrade.bin + IMAGE/nand-factory.bin := append-ubi + IMAGE/nand-sysupgrade.bin := sysupgrade-tar | append-metadata +endef + +define Device/DniImage + KERNEL_SUFFIX := -uImage + KERNEL = kernel-bin | append-dtb | uImage none + KERNEL_NAME := zImage + NETGEAR_BOARD_ID := + NETGEAR_HW_ID := + UBINIZE_OPTS := -E 5 + IMAGES += factory.img + IMAGE/factory.img := append-kernel | pad-offset $$$$(BLOCKSIZE) 64 | append-uImage-fakehdr filesystem | pad-to $$$$(KERNEL_SIZE) | append-ubi | netgear-dni + IMAGE/sysupgrade.bin := append-kernel | pad-offset $$$$(BLOCKSIZE) 64 | append-uImage-fakehdr filesystem | sysupgrade-tar kernel=$$$$@ | append-metadata +endef + +define Device/TpSafeImage + KERNEL_SUFFIX := -uImage + KERNEL = kernel-bin | append-dtb | uImage none + KERNEL_NAME := zImage + TPLINK_BOARD_ID := + IMAGES += factory.bin + IMAGE/factory.bin := append-rootfs | tplink-safeloader factory + IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade | append-metadata +endef + +define Device/ZyXELImage + KERNEL_SUFFIX := -uImage + KERNEL = kernel-bin | append-dtb | uImage none | pad-to $$(KERNEL_SIZE) + KERNEL_NAME := zImage + IMAGES += factory.bin + IMAGE/factory.bin := append-rootfs | pad-rootfs | pad-to $$$$(BLOCKSIZE) | zyxel-ras-image separate-kernel + IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-to $$$$(BLOCKSIZE) | sysupgrade-tar rootfs=$$$$@ | append-metadata +endef + +define Device/askey_rt4230w-rev6 + $(call Device/LegacyImage) + DEVICE_VENDOR := Askey + DEVICE_MODEL := RT4230W + DEVICE_VARIANT := REV6 + SOC := qcom-ipq8065 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct + KERNEL_IN_UBI := 1 +endef +TARGET_DEVICES += askey_rt4230w-rev6 + +define Device/asrock_g10 + $(call Device/FitImage) + $(call Device/UbiFit) + SOC := qcom-ipq8064 + DEVICE_VENDOR := ASRock + DEVICE_MODEL := G10 + BLOCKSIZE := 128k + PAGESIZE := 2048 + KERNEL_SIZE := 5332k + DEVICE_PACKAGES := kmod-i2c-gpio ath10k-firmware-qca99x0-ct + IMAGE/nand-factory.bin := append-ubi | edimax-header RN67 +endef +TARGET_DEVICES += asrock_g10 + +define Device/buffalo_wxr-2533dhp + $(call Device/LegacyImage) + SOC := qcom-ipq8064 + DEVICE_VENDOR := Buffalo + DEVICE_MODEL := WXR-2533DHP + BLOCKSIZE := 128k + PAGESIZE := 2048 + IMAGE_SIZE := 65536k + KERNEL_IN_UBI := 1 + IMAGE/sysupgrade.bin := append-rootfs | buffalo-rootfs-cksum | \ + sysupgrade-tar rootfs=$$$$@ | append-metadata + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += buffalo_wxr-2533dhp + +define Device/compex_wpq864 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Compex + DEVICE_MODEL := WPQ864 + BLOCKSIZE := 128k + PAGESIZE := 2048 + SOC := qcom-ipq8064 + DEVICE_PACKAGES := kmod-gpio-beeper +endef +TARGET_DEVICES += compex_wpq864 + +define Device/edgecore_ecw5410 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Edgecore + DEVICE_MODEL := ECW5410 + SOC := qcom-ipq8068 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_DTS_CONFIG := config@v2.0-ap160 + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct ipq-wifi-edgecore_ecw5410 +endef +TARGET_DEVICES += edgecore_ecw5410 + +define Device/edgecore_ssw2ac2600 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Edgecore + DEVICE_MODEL := SSW2AC2600 + SOC := qcom-ipq8068 + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_DTS := qcom-ipq8068-ssw2ac2600 + DEVICE_DTS_CONFIG := config@v2.0-ap160 + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct ipq-wifi-edgecore_ssw2ac2600 +endef +TARGET_DEVICES += edgecore_ssw2ac2600 + +define Device/linksys_ea7500-v1 + $(call Device/LegacyImage) + DEVICE_VENDOR := Linksys + DEVICE_MODEL := EA7500 + DEVICE_VARIANT := v1 + SOC := qcom-ipq8064 + PAGESIZE := 2048 + BLOCKSIZE := 128k + KERNEL_SIZE := 3072k + KERNEL = kernel-bin | append-dtb | uImage none | append-uImage-fakehdr filesystem + UBINIZE_OPTS := -E 5 + IMAGES := factory.bin sysupgrade.bin + IMAGE/factory.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi | pad-to $$$$(PAGESIZE) + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += linksys_ea7500-v1 + +define Device/linksys_ea8500 + $(call Device/LegacyImage) + DEVICE_VENDOR := Linksys + DEVICE_MODEL := EA8500 + SOC := qcom-ipq8064 + PAGESIZE := 2048 + BLOCKSIZE := 128k + KERNEL_SIZE := 3072k + KERNEL = kernel-bin | append-dtb | uImage none | append-uImage-fakehdr filesystem + BOARD_NAME := ea8500 + SUPPORTED_DEVICES += ea8500 + UBINIZE_OPTS := -E 5 + IMAGES += factory.bin + IMAGE/factory.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += linksys_ea8500 + +define Device/nec_wg2600hp + $(call Device/LegacyImage) + DEVICE_VENDOR := NEC + DEVICE_MODEL := Aterm WG2600HP + SOC := qcom-ipq8064 + BLOCKSIZE := 64k + BOARD_NAME := wg2600hp + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += nec_wg2600hp + +define Device/nec_wg2600hp3 + $(call Device/LegacyImage) + DEVICE_VENDOR := NEC Platforms + DEVICE_MODEL := Aterm WG2600HP3 + SOC := qcom-ipq8062 + BLOCKSIZE := 64k + IMAGES := sysupgrade.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | append-metadata + DEVICE_PACKAGES := -kmod-ata-ahci -kmod-ata-ahci-platform -kmod-usb-ohci -kmod-usb2 \ + -kmod-usb-ledtrig-usbport -kmod-usb-phy-qcom-dwc3 -kmod-usb3 -kmod-usb-dwc3-qcom \ + ath10k-firmware-qca9984-ct ipq-wifi-nec_wg2600hp3 +endef +TARGET_DEVICES += nec_wg2600hp3 + +define Device/netgear_d7800 + $(call Device/DniImage) + DEVICE_VENDOR := NETGEAR + DEVICE_MODEL := Nighthawk X4 D7800 + SOC := qcom-ipq8064 + KERNEL_SIZE := 4096k + NETGEAR_BOARD_ID := D7800 + NETGEAR_HW_ID := 29764958+0+128+512+4x4+4x4 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := d7800 + SUPPORTED_DEVICES += d7800 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += netgear_d7800 + +define Device/netgear_r7500 + $(call Device/DniImage) + DEVICE_VENDOR := NETGEAR + DEVICE_MODEL := Nighthawk X4 R7500 + DEVICE_VARIANT := v1 + SOC := qcom-ipq8064 + KERNEL_SIZE := 4096k + NETGEAR_BOARD_ID := R7500 + NETGEAR_HW_ID := 29764841+0+128+256+3x3+4x4 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := r7500 + SUPPORTED_DEVICES += r7500 + DEVICE_PACKAGES := ath10k-firmware-qca988x-ct +endef +TARGET_DEVICES += netgear_r7500 + +define Device/netgear_r7500v2 + $(call Device/DniImage) + DEVICE_VENDOR := NETGEAR + DEVICE_MODEL := Nighthawk X4 R7500 + DEVICE_VARIANT := v2 + SOC := qcom-ipq8064 + KERNEL_SIZE := 4096k + NETGEAR_BOARD_ID := R7500v2 + NETGEAR_HW_ID := 29764958+0+128+512+3x3+4x4 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := r7500v2 + SUPPORTED_DEVICES += r7500v2 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct ath10k-firmware-qca988x-ct +endef +TARGET_DEVICES += netgear_r7500v2 + +define Device/netgear_r7800 + $(call Device/DniImage) + DEVICE_VENDOR := NETGEAR + DEVICE_MODEL := Nighthawk X4S R7800 + SOC := qcom-ipq8065 + KERNEL_SIZE := 4096k + NETGEAR_BOARD_ID := R7800 + NETGEAR_HW_ID := 29764958+0+128+512+4x4+4x4+cascade + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := r7800 + SUPPORTED_DEVICES += r7800 + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct +endef +TARGET_DEVICES += netgear_r7800 + +define Device/qcom_ipq8064-ap148 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Qualcomm + DEVICE_MODEL := AP148 + DEVICE_VARIANT := standard + SOC := qcom-ipq8064 + DEVICE_DTS := qcom-ipq8064-ap148 + KERNEL_INSTALL := 1 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := ap148 + SUPPORTED_DEVICES += ap148 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += qcom_ipq8064-ap148 + +define Device/qcom_ipq8064-ap148-legacy + $(call Device/LegacyImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Qualcomm + DEVICE_MODEL := AP148 + DEVICE_VARIANT := legacy + SOC := qcom-ipq8064 + DEVICE_DTS := qcom-ipq8064-ap148 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := ap148 + SUPPORTED_DEVICES := qcom,ipq8064-ap148 ap148 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += qcom_ipq8064-ap148-legacy + +define Device/qcom_ipq8064-ap161 + $(call Device/FitImage) + $(call Device/UbiFit) + DEVICE_VENDOR := Qualcomm + DEVICE_MODEL := AP161 + SOC := qcom-ipq8064 + DEVICE_DTS := qcom-ipq8064-ap161 + KERNEL_INSTALL := 1 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := ap161 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += qcom_ipq8064-ap161 + +define Device/qcom_ipq8064-db149 + $(call Device/FitImage) + DEVICE_VENDOR := Qualcomm + DEVICE_MODEL := DB149 + SOC := qcom-ipq8064 + DEVICE_DTS := qcom-ipq8064-db149 + KERNEL_INSTALL := 1 + BOARD_NAME := db149 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += qcom_ipq8064-db149 + +define Device/tplink_ad7200 + $(call Device/TpSafeImage) + DEVICE_VENDOR := TP-Link + DEVICE_MODEL := AD7200 + DEVICE_VARIANT := v1/v2 + DEVICE_ALT0_VENDOR := TP-Link + DEVICE_ALT0_MODEL := Talon AD7200 + DEVICE_ALT0_VARIANT := v1/v2 + SOC := qcom-ipq8064 + BLOCKSIZE := 128k + PAGESIZE := 2048 + TPLINK_BOARD_ID := AD7200 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct kmod-wil6210 +endef +TARGET_DEVICES += tplink_ad7200 + +define Device/tplink_c2600 + $(call Device/TpSafeImage) + DEVICE_VENDOR := TP-Link + DEVICE_MODEL := Archer C2600 + DEVICE_VARIANT := v1 + SOC := qcom-ipq8064 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := c2600 + SUPPORTED_DEVICES += c2600 + TPLINK_BOARD_ID := C2600 + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct +endef +TARGET_DEVICES += tplink_c2600 + +define Device/tplink_vr2600v + DEVICE_VENDOR := TP-Link + DEVICE_MODEL := Archer VR2600v + DEVICE_VARIANT := v1 + KERNEL_SUFFIX := -uImage + KERNEL = kernel-bin | append-dtb | uImage none + KERNEL_NAME := zImage + KERNEL_SIZE := 3072k + SOC := qcom-ipq8064 + BLOCKSIZE := 128k + PAGESIZE := 2048 + BOARD_NAME := vr2600v + SUPPORTED_DEVICES += vr2600v + DEVICE_PACKAGES := ath10k-firmware-qca99x0-ct + IMAGE/sysupgrade.bin := pad-extra 512 | append-kernel | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | append-metadata +endef +TARGET_DEVICES += tplink_vr2600v + +define Device/ubnt_unifi-ac-hd + $(call Device/FitImageLzma) + DEVICE_VENDOR := Ubiquiti + DEVICE_MODEL := UniFi AC HD + SOC := qcom-ipq8064 + BLOCKSIZE := 64k + IMAGE_SIZE := 14784k + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct + IMAGE/sysupgrade.bin := append-kernel | pad-to $$$$(BLOCKSIZE) | append-rootfs | pad-rootfs | check-size | append-metadata +endef +TARGET_DEVICES += ubnt_unifi-ac-hd + +define Device/zyxel_nbg6817 + DEVICE_VENDOR := ZyXEL + DEVICE_MODEL := NBG6817 + SOC := qcom-ipq8065 + KERNEL_SIZE := 4096k + BLOCKSIZE := 64k + BOARD_NAME := nbg6817 + RAS_BOARD := NBG6817 + RAS_ROOTFS_SIZE := 20934k + RAS_VERSION := "V1.99(OWRT.9999)C0" + SUPPORTED_DEVICES += nbg6817 + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct e2fsprogs kmod-fs-ext4 losetup + $(call Device/ZyXELImage) +endef +TARGET_DEVICES += zyxel_nbg6817 + +$(eval $(call BuildImage)) diff --git a/ipq806x/modules.mk b/ipq806x/modules.mk new file mode 100644 index 0000000..605504b --- /dev/null +++ b/ipq806x/modules.mk @@ -0,0 +1,16 @@ +define KernelPackage/phy-qcom-ipq806x-usb + TITLE:=Qualcomm IPQ806x DWC3 USB PHY driver + DEPENDS:=@TARGET_ipq806x + KCONFIG:= CONFIG_PHY_QCOM_IPQ806X_USB + FILES:= \ + $(LINUX_DIR)/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.ko + AUTOLOAD:=$(call AutoLoad,45,phy-qcom-ipq806x-usb,1) + $(call AddDepends/usb) +endef + +define KernelPackage/phy-qcom-ipq806x-usb/description + This driver provides support for the integrated DesignWare + USB3 IP Core within the QCOM SoCs. +endef + +$(eval $(call KernelPackage,phy-qcom-ipq806x-usb)) diff --git a/ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch b/ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch new file mode 100644 index 0000000..83d7bbc --- /dev/null +++ b/ipq806x/patches-5.10/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch @@ -0,0 +1,71 @@ +From 28d0ed88f536dd639adf1b0c7c08e04be3c8f294 Mon Sep 17 00:00:00 2001 +From: Thomas Pedersen +Date: Mon, 16 May 2016 17:58:50 -0700 +Subject: [PATCH 01/69] dtbindings: qcom_adm: Fix channel specifiers + +Original patch from Andy Gross. + +This patch removes the crci information from the dma +channel property. At least one client device requires +using more than one CRCI value for a channel. This does +not match the current binding and the crci information +needs to be removed. + +Instead, the client device will provide this information +via other means. + +Signed-off-by: Andy Gross +Signed-off-by: Thomas Pedersen +--- + Documentation/devicetree/bindings/dma/qcom_adm.txt | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +--- a/Documentation/devicetree/bindings/dma/qcom_adm.txt ++++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt +@@ -4,8 +4,7 @@ Required properties: + - compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960 + - reg: Address range for DMA registers + - interrupts: Should contain one interrupt shared by all channels +-- #dma-cells: must be <2>. First cell denotes the channel number. Second cell +- denotes CRCI (client rate control interface) flow control assignment. ++- #dma-cells: must be <1>. First cell denotes the channel number. + - clocks: Should contain the core clock and interface clock. + - clock-names: Must contain "core" for the core clock and "iface" for the + interface clock. +@@ -22,7 +21,7 @@ Example: + compatible = "qcom,adm"; + reg = <0x18300000 0x100000>; + interrupts = <0 170 0>; +- #dma-cells = <2>; ++ #dma-cells = <1>; + + clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; + clock-names = "core", "iface"; +@@ -35,15 +34,12 @@ Example: + qcom,ee = <0>; + }; + +-DMA clients must use the format descripted in the dma.txt file, using a three ++DMA clients must use the format descripted in the dma.txt file, using a two + cell specifier for each channel. + +-Each dmas request consists of 3 cells: ++Each dmas request consists of two cells: + 1. phandle pointing to the DMA controller + 2. channel number +- 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0. +- The CRCI is used for flow control. It identifies the peripheral device that +- is the source/destination for the transferred data. + + Example: + +@@ -55,7 +51,7 @@ Example: + + cs-gpios = <&qcom_pinmux 20 0>; + +- dmas = <&adm_dma 6 9>, +- <&adm_dma 5 10>; ++ dmas = <&adm_dma 6>, ++ <&adm_dma 5>; + dma-names = "rx", "tx"; + }; diff --git a/ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch b/ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch new file mode 100644 index 0000000..a12aa72 --- /dev/null +++ b/ipq806x/patches-5.10/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch @@ -0,0 +1,29 @@ +From 48051ece78136e4235a2415a52797db56f8a4478 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Tue, 21 Apr 2015 19:09:07 -0700 +Subject: [PATCH 33/69] ARM: qcom: automatically select PCI_DOMAINS if PCI is + enabled + +If multiple PCIe devices are present in the system, the kernel will +panic at boot time when trying to scan the PCI buses. This happens on +IPQ806x based platforms, which has 3 PCIe ports. + +Enabling this option allows the kernel to assign the pci-domains +according to the device-tree content. This allows multiple PCIe +controllers to coexist in the system. + +Signed-off-by: Mathieu Olivari +--- + arch/arm/mach-qcom/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/mach-qcom/Kconfig ++++ b/arch/arm/mach-qcom/Kconfig +@@ -7,6 +7,7 @@ menuconfig ARCH_QCOM + select ARM_AMBA + select PINCTRL + select QCOM_SCM if SMP ++ select PCI_DOMAINS if PCI + help + Support for Qualcomm's devicetree based systems. + diff --git a/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch new file mode 100644 index 0000000..b56480d --- /dev/null +++ b/ipq806x/patches-5.10/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch @@ -0,0 +1,62 @@ +From fa71139b55e114aa8c3c4823ff8ee7d49ee810d4 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Wed, 29 Apr 2015 15:21:46 -0700 +Subject: [PATCH 60/69] HACK: arch: arm: force ZRELADDR on arch-qcom + +ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended +on most ARM architectures. This automatically calculate ZRELADDR by +masking PHYS_OFFSET with 0xf8000000. + +However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware +network accelerators, and the bootloader removes this section from the +layout passed from the ATAGS (when used). + +For newer bootloader, when DT is used, this is not a problem, we just +reserve this memory in the device tree. But if the bootloader doesn't +have DT support, then ATAGS have to be used. In this case, the ARM +decompressor will position the kernel in this low mem, which will not be +in the RAM section mapped by the bootloader, which means the kernel will +freeze in the middle of the boot process trying to map the memory. + +As a work around, this patch allows disabling AUTO_ZRELADDR when +ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders +which don't support device-tree, which is the case on certain early +IPQ806x based designs. + +Signed-off-by: Mathieu Olivari +--- + arch/arm/Kconfig | 2 +- + arch/arm/Makefile | 2 ++ + arch/arm/mach-qcom/Makefile.boot | 1 + + 3 files changed, 4 insertions(+), 1 deletion(-) + create mode 100644 arch/arm/mach-qcom/Makefile.boot + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -321,7 +321,7 @@ config ARCH_MULTIPLATFORM + select ARCH_SELECT_MEMORY_MODEL + select ARM_HAS_SG_CHAIN + select ARM_PATCH_PHYS_VIRT +- select AUTO_ZRELADDR ++ select AUTO_ZRELADDR if !ARCH_QCOM + select TIMER_OF + select COMMON_CLK + select GENERIC_CLOCKEVENTS +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -251,9 +251,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac + else + MACHINE := + endif ++ifeq ($(CONFIG_ARCH_QCOM),) + ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y) + MACHINE := + endif ++endif + + machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) + platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y))) +--- /dev/null ++++ b/arch/arm/mach-qcom/Makefile.boot +@@ -0,0 +1 @@ ++zreladdr-y+= 0x42208000 diff --git a/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch b/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch new file mode 100644 index 0000000..5a970e8 --- /dev/null +++ b/ipq806x/patches-5.10/0065-arm-override-compiler-flags.patch @@ -0,0 +1,21 @@ +From 4d8e29642661397a339ac3485f212c6360445421 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:33:32 +0100 +Subject: [PATCH 65/69] arm: override compiler flags + +Signed-off-by: John Crispin +--- + arch/arm/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -61,7 +61,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-i + # macro, but instead defines a whole series of macros which makes + # testing for a specific architecture or later rather impossible. + arch-$(CONFIG_CPU_32v7M) =-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m +-arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a) ++arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-a15 + arch-$(CONFIG_CPU_32v6) =-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6) + # Only override the compiler option if ARMv6. The ARMv6K extensions are + # always available in ARMv7 diff --git a/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch new file mode 100644 index 0000000..c38e0a4 --- /dev/null +++ b/ipq806x/patches-5.10/0067-generic-Mangle-bootloader-s-kernel-arguments.patch @@ -0,0 +1,210 @@ +From 71270226b14733a4b1f2cde58ea9265caa50b38d Mon Sep 17 00:00:00 2001 +From: Adrian Panella +Date: Thu, 9 Mar 2017 09:37:17 +0100 +Subject: [PATCH 67/69] generic: Mangle bootloader's kernel arguments + +The command-line arguments provided by the boot loader will be +appended to a new device tree property: bootloader-args. +If there is a property "append-rootblock" in DT under /chosen +and a root= option in bootloaders command line it will be parsed +and added to DT bootargs with the form: XX. +Only command line ATAG will be processed, the rest of the ATAGs +sent by bootloader will be ignored. +This is usefull in dual boot systems, to get the current root partition +without afecting the rest of the system. + +Signed-off-by: Adrian Panella +--- + arch/arm/Kconfig | 11 +++++ + arch/arm/boot/compressed/atags_to_fdt.c | 72 ++++++++++++++++++++++++++++++++- + init/main.c | 16 ++++++++ + 3 files changed, 98 insertions(+), 1 deletion(-) + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1780,6 +1780,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN + The command-line arguments provided by the boot loader will be + appended to the the device tree bootargs property. + ++config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ bool "Append rootblock parsing bootloader's kernel arguments" ++ help ++ The command-line arguments provided by the boot loader will be ++ appended to a new device tree property: bootloader-args. ++ If there is a property "append-rootblock" in DT under /chosen ++ and a root= option in bootloaders command line it will be parsed ++ and added to DT bootargs with the form: XX. ++ Only command line ATAG will be processed, the rest of the ATAGs ++ sent by bootloader will be ignored. ++ + endchoice + + config CMDLINE +--- a/arch/arm/boot/compressed/atags_to_fdt.c ++++ b/arch/arm/boot/compressed/atags_to_fdt.c +@@ -5,6 +5,8 @@ + + #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND) + #define do_extend_cmdline 1 ++#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#define do_extend_cmdline 1 + #else + #define do_extend_cmdline 0 + #endif +@@ -69,6 +71,80 @@ static uint32_t get_cell_size(const void + return cell_size; + } + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++/** ++ * taken from arch/x86/boot/string.c ++ * local_strstr - Find the first substring in a %NUL terminated string ++ * @s1: The string to be searched ++ * @s2: The string to search for ++ */ ++static char *local_strstr(const char *s1, const char *s2) ++{ ++ size_t l1, l2; ++ ++ l2 = strlen(s2); ++ if (!l2) ++ return (char *)s1; ++ l1 = strlen(s1); ++ while (l1 >= l2) { ++ l1--; ++ if (!memcmp(s1, s2, l2)) ++ return (char *)s1; ++ s1++; ++ } ++ return NULL; ++} ++ ++static char *append_rootblock(char *dest, const char *str, int len, void *fdt) ++{ ++ char *ptr, *end, *tmp; ++ char *root="root="; ++ char *find_rootblock; ++ int i, l; ++ const char *rootblock; ++ ++ find_rootblock = getprop(fdt, "/chosen", "find-rootblock", &l); ++ if(!find_rootblock) ++ find_rootblock = root; ++ ++ //ARM doesn't have __HAVE_ARCH_STRSTR, so it was copied from x86 ++ ptr = local_strstr(str, find_rootblock); ++ ++ if(!ptr) ++ return dest; ++ ++ end = strchr(ptr, ' '); ++ end = end ? (end - 1) : (strchr(ptr, 0) - 1); ++ ++ // Some boards ubi.mtd=XX,ZZZZ, so let's check for '," too. ++ tmp = strchr(ptr, ','); ++ ++ if(tmp) ++ end = end < tmp ? end : tmp - 1; ++ ++ //find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX | ubi.mtd=XX,ZZZZ ) ++ for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++); ++ ptr = end + 1; ++ ++ /* if append-rootblock property is set use it to append to command line */ ++ rootblock = getprop(fdt, "/chosen", "append-rootblock", &l); ++ if(rootblock != NULL) { ++ if(*dest != ' ') { ++ *dest = ' '; ++ dest++; ++ len++; ++ } ++ if (len + l + i <= COMMAND_LINE_SIZE) { ++ memcpy(dest, rootblock, l); ++ dest += l - 1; ++ memcpy(dest, ptr, i); ++ dest += i; ++ } ++ } ++ return dest; ++} ++#endif ++ + static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) + { + char cmdline[COMMAND_LINE_SIZE]; +@@ -88,12 +164,21 @@ static void merge_fdt_bootargs(void *fdt + + /* and append the ATAG_CMDLINE */ + if (fdt_cmdline) { ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //save original bootloader args ++ //and append ubi.mtd with root partition number to current cmdline ++ setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline); ++ ptr = append_rootblock(ptr, fdt_cmdline, len, fdt); ++ ++#else + len = strlen(fdt_cmdline); + if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) { + *ptr++ = ' '; + memcpy(ptr, fdt_cmdline, len); + ptr += len; + } ++#endif + } + *ptr = '\0'; + +@@ -168,7 +253,9 @@ int atags_to_fdt(void *atag_list, void * + else + setprop_string(fdt, "/chosen", "bootargs", + atag->u.cmdline.cmdline); +- } else if (atag->hdr.tag == ATAG_MEM) { ++ } ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ else if (atag->hdr.tag == ATAG_MEM) { + if (memcount >= sizeof(mem_reg_property)/4) + continue; + if (!atag->u.mem.size) +@@ -212,6 +299,10 @@ int atags_to_fdt(void *atag_list, void * + setprop(fdt, "/memory", "reg", mem_reg_property, + 4 * memcount * memsize); + } ++#else ++ ++ } ++#endif + + return fdt_pack(fdt); + } +--- a/init/main.c ++++ b/init/main.c +@@ -110,6 +110,10 @@ + + #include + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#include ++#endif ++ + static int kernel_init(void *); + + extern void init_IRQ(void); +@@ -905,6 +909,18 @@ asmlinkage __visible void __init __no_sa + pr_notice("Kernel command line: %s\n", saved_command_line); + /* parameters may set static keys */ + jump_label_init(); ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //Show bootloader's original command line for reference ++ if(of_chosen) { ++ const char *prop = of_get_property(of_chosen, "bootloader-args", NULL); ++ if(prop) ++ pr_notice("Bootloader command line (ignored): %s\n", prop); ++ else ++ pr_notice("Bootloader command line not present\n"); ++ } ++#endif ++ + parse_early_param(); + after_dashes = parse_args("Booting kernel", + static_command_line, __start___param, diff --git a/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch b/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch new file mode 100644 index 0000000..87d6b65 --- /dev/null +++ b/ipq806x/patches-5.10/0069-arm-boot-add-dts-files.patch @@ -0,0 +1,39 @@ +From 8f68331e14dff9a101f2d0e1d6bec84a031f27ee Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 11:03:18 +0100 +Subject: [PATCH 69/69] arm: boot: add dts files + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/Makefile | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -907,8 +907,26 @@ dtb-$(CONFIG_ARCH_QCOM) += \ + qcom-ipq4019-ap.dk04.1-c3.dtb \ + qcom-ipq4019-ap.dk07.1-c1.dtb \ + qcom-ipq4019-ap.dk07.1-c2.dtb \ ++ qcom-ipq8062-wg2600hp3.dtb \ + qcom-ipq8064-ap148.dtb \ + qcom-ipq8064-rb3011.dtb \ ++ qcom-ipq8064-c2600.dtb \ ++ qcom-ipq8064-d7800.dtb \ ++ qcom-ipq8064-db149.dtb \ ++ qcom-ipq8064-ap161.dtb \ ++ qcom-ipq8064-ea7500-v1.dtb \ ++ qcom-ipq8064-ea8500.dtb \ ++ qcom-ipq8064-g10.dtb \ ++ qcom-ipq8064-r7500.dtb \ ++ qcom-ipq8064-r7500v2.dtb \ ++ qcom-ipq8064-unifi-ac-hd.dtb \ ++ qcom-ipq8064-wg2600hp.dtb \ ++ qcom-ipq8064-wpq864.dtb \ ++ qcom-ipq8064-wxr-2533dhp.dtb \ ++ qcom-ipq8065-nbg6817.dtb \ ++ qcom-ipq8065-r7800.dtb \ ++ qcom-ipq8065-rt4230w-rev6.dtb \ ++ qcom-ipq8068-ecw5410.dtb \ + qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ + qcom-msm8974-fairphone-fp2.dtb \ diff --git a/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch b/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch new file mode 100644 index 0000000..62bba1d --- /dev/null +++ b/ipq806x/patches-5.10/0072-add-ipq806x-with-no-clocks.patch @@ -0,0 +1,10 @@ +--- a/drivers/firmware/qcom_scm.c ++++ b/drivers/firmware/qcom_scm.c +@@ -1275,6 +1275,7 @@ static const struct of_device_id qcom_sc + SCM_HAS_BUS_CLK) + }, + { .compatible = "qcom,scm-ipq4019" }, ++ { .compatible = "qcom,scm-ipq806x" }, + { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK }, + { .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK }, + { .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK | diff --git a/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch b/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch new file mode 100644 index 0000000..c91fb68 --- /dev/null +++ b/ipq806x/patches-5.10/082-ipq8064-dtsi-tweaks.patch @@ -0,0 +1,211 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -20,7 +20,7 @@ + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "qcom,krait"; + enable-method = "qcom,kpss-acc-v1"; + device_type = "cpu"; +@@ -30,7 +30,7 @@ + qcom,saw = <&saw0>; + }; + +- cpu@1 { ++ cpu1: cpu@1 { + compatible = "qcom,krait"; + enable-method = "qcom,kpss-acc-v1"; + device_type = "cpu"; +@@ -67,7 +67,7 @@ + no-map; + }; + +- smem@41000000 { ++ smem: smem@41000000 { + reg = <0x41000000 0x200000>; + no-map; + }; +@@ -128,6 +128,7 @@ + gpio-ranges = <&qcom_pinmux 0 0 69>; + #gpio-cells = <2>; + interrupt-controller; ++ #address-cells = <0>; + #interrupt-cells = <2>; + interrupts = ; + +@@ -155,6 +156,7 @@ + function = "pcie3_rst"; + drive-strength = <12>; + bias-disable; ++ output-low; + }; + }; + +@@ -190,6 +192,7 @@ + intc: interrupt-controller@2000000 { + compatible = "qcom,msm-qgic2"; + interrupt-controller; ++ #address-cells = <0>; + #interrupt-cells = <3>; + reg = <0x02000000 0x1000>, + <0x02002000 0x1000>; +@@ -219,21 +222,23 @@ + acc0: clock-controller@2088000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02088000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu0_aux"; + }; + + acc1: clock-controller@2098000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02098000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu1_aux"; + }; + + saw0: regulator@2089000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + + saw1: regulator@2099000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02099000 0x1000>, <0x02009000 0x1000>; + regulator; + }; +@@ -251,7 +256,7 @@ + + syscon-tcsr = <&tcsr>; + +- serial@12490000 { ++ gsbi2_serial: serial@12490000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x12490000 0x1000>, + <0x12480000 0x1000>; +@@ -326,7 +331,7 @@ + + syscon-tcsr = <&tcsr>; + +- serial@1a240000 { ++ gsbi5_serial: serial@1a240000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x1a240000 0x1000>, + <0x1a200000 0x1000>; +@@ -397,7 +402,7 @@ + status = "disabled"; + }; + +- sata@29000000 { ++ sata: sata@29000000 { + compatible = "qcom,ipq806x-ahci", "generic-ahci"; + reg = <0x29000000 0x180>; + +@@ -430,13 +435,35 @@ + reg = <0x00700000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ tsens_calib: calib@400 { ++ reg = <0x400 0xb>; ++ }; ++ tsens_backup: backup@410 { ++ reg = <0x410 0xb>; ++ }; ++ speedbin_efuse: speedbin@0c0 { ++ reg = <0x0c0 0x4>; ++ }; + }; + + gcc: clock-controller@900000 { +- compatible = "qcom,gcc-ipq8064"; ++ compatible = "qcom,gcc-ipq8064", "syscon"; + reg = <0x00900000 0x4000>; + #clock-cells = <1>; + #reset-cells = <1>; ++ #power-domain-cells = <1>; ++ ++ tsens: thermal-sensor@900000 { ++ compatible = "qcom,ipq8064-tsens"; ++ ++ nvmem-cells = <&tsens_calib>, <&tsens_backup>; ++ nvmem-cell-names = "calib", "calib_backup"; ++ interrupts = ; ++ interrupt-names = "uplow"; ++ #thermal-sensor-cells = <1>; ++ #qcom,sensors = <11>; ++ }; + }; + + tcsr: syscon@1a400000 { +@@ -622,7 +649,7 @@ + + gmac0: ethernet@37000000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37000000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -645,7 +672,7 @@ + + gmac1: ethernet@37200000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37200000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -668,7 +695,7 @@ + + gmac2: ethernet@37400000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37400000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -691,7 +718,7 @@ + + gmac3: ethernet@37600000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37600000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -740,13 +767,13 @@ + qcom,ee = <0>; + }; + +- amba { +- compatible = "simple-bus"; ++ amba: amba { ++ compatible = "arm,amba-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + +- sdcc@12400000 { ++ sdcc1: sdcc@12400000 { + status = "disabled"; + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; +@@ -760,13 +787,12 @@ + non-removable; + cap-sd-highspeed; + cap-mmc-highspeed; +- mmc-ddr-1_8v; + vmmc-supply = <&vsdcc_fixed>; + dmas = <&sdcc1bam 2>, <&sdcc1bam 1>; + dma-names = "tx", "rx"; + }; + +- sdcc@12180000 { ++ sdcc3: sdcc@12180000 { + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; + status = "disabled"; diff --git a/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch b/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch new file mode 100644 index 0000000..fac8b17 --- /dev/null +++ b/ipq806x/patches-5.10/083-ipq8064-dtsi-additions.patch @@ -0,0 +1,754 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -8,6 +8,8 @@ + #include + #include + #include ++#include ++#include + + / { + #address-cells = <1>; +@@ -28,6 +30,16 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc0>; + qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2a>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; + }; + + cpu1: cpu@1 { +@@ -38,14 +50,347 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc1>; + qcom,saw = <&saw1>; ++ clocks = <&kraitcc 1>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2b>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; ++ }; ++ ++ idle-states { ++ CPU_SPC: spc { ++ compatible = "qcom,idle-state-spc"; ++ status = "disabled"; ++ entry-latency-us = <400>; ++ exit-latency-us = <900>; ++ min-residency-us = <3000>; ++ }; + }; ++ }; + +- L2: l2-cache { +- compatible = "cache"; +- cache-level = <2>; ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; + }; + }; + ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <950000 1000000 1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <878750 925000 971250>; ++ opp-microvolt-speed0-pvs2-v0 = <831250 875000 918750>; ++ opp-microvolt-speed0-pvs3-v0 = <760000 800000 840000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <997500 1050000 1102500>; ++ opp-microvolt-speed0-pvs1-v0 = <926250 975000 1023750>; ++ opp-microvolt-speed0-pvs2-v0 = <878750 925000 971250>; ++ opp-microvolt-speed0-pvs3-v0 = <807500 850000 892500>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1045000 1100000 1155000>; ++ opp-microvolt-speed0-pvs1-v0 = <973750 1025000 1076250>; ++ opp-microvolt-speed0-pvs2-v0 = <945250 995000 1044750>; ++ opp-microvolt-speed0-pvs3-v0 = <855000 900000 945000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1092500 1150000 1207500>; ++ opp-microvolt-speed0-pvs1-v0 = <1021250 1075000 1128750>; ++ opp-microvolt-speed0-pvs2-v0 = <973750 1025000 1076250>; ++ opp-microvolt-speed0-pvs3-v0 = <902500 950000 997500>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1140000 1200000 1260000>; ++ opp-microvolt-speed0-pvs1-v0 = <1068750 1125000 1181250>; ++ opp-microvolt-speed0-pvs2-v0 = <1021250 1075000 1128750>; ++ opp-microvolt-speed0-pvs3-v0 = <950000 1000000 1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1187500 1250000 1312500>; ++ opp-microvolt-speed0-pvs1-v0 = <1116250 1175000 1233750>; ++ opp-microvolt-speed0-pvs2-v0 = <1068750 1125000 1181250>; ++ opp-microvolt-speed0-pvs3-v0 = <997500 1050000 1102500>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ thermal-zones { ++ tsens_tz_sensor0 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 0>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor1 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 1>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor2 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 2>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor3 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 3>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor4 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 4>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor5 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 5>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor6 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 6>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor7 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 7>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor8 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 8>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor9 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 9>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor10 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 10>; ++ ++ trips { ++ cpu-critical { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ ++ cpu-hot { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "hot"; ++ }; ++ }; ++ }; ++ }; ++ + memory { + device_type = "memory"; + reg = <0x0 0x0>; +@@ -93,6 +438,15 @@ + }; + }; + ++ fab-scaling { ++ compatible = "qcom,fab-scaling"; ++ clocks = <&rpmcc RPM_APPS_FABRIC_A_CLK>, <&rpmcc RPM_EBI1_A_CLK>; ++ clock-names = "apps-fab-clk", "ddr-fab-clk"; ++ fab_freq_high = <533000000>; ++ fab_freq_nominal = <400000000>; ++ cpu_freq_threshold = <1000000000>; ++ }; ++ + firmware { + scm { + compatible = "qcom,scm-ipq806x", "qcom,scm"; +@@ -120,6 +474,78 @@ + reg-names = "lpass-lpaif"; + }; + ++ L2: l2-cache { ++ compatible = "qcom,krait-cache", "cache"; ++ cache-level = <2>; ++ qcom,saw = <&saw_l2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ l2-supply = <&smb208_s1a>; ++ operating-points-v2 = <&opp_table_l2>; ++ }; ++ ++ rpm: rpm@108000 { ++ compatible = "qcom,rpm-ipq8064"; ++ reg = <0x108000 0x1000>; ++ qcom,ipc = <&l2cc 0x8 2>; ++ ++ interrupts = , ++ , ++ ; ++ interrupt-names = "ack", "err", "wakeup"; ++ ++ clocks = <&gcc RPM_MSG_RAM_H_CLK>; ++ clock-names = "ram"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rpmcc: clock-controller { ++ compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc"; ++ #clock-cells = <1>; ++ }; ++ ++ regulators { ++ compatible = "qcom,rpm-smb208-regulators"; ++ ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2a: s2a { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2b: s2b { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ }; ++ }; ++ ++ rng@1a500000 { ++ compatible = "qcom,prng"; ++ reg = <0x1a500000 0x200>; ++ clocks = <&gcc PRNG_CLK>; ++ clock-names = "core"; ++ }; ++ + qcom_pinmux: pinmux@800000 { + compatible = "qcom,ipq8064-pinctrl"; + reg = <0x800000 0x4000>; +@@ -160,6 +586,15 @@ + }; + }; + ++ i2c4_pins: i2c4_pinmux { ++ mux { ++ pins = "gpio12", "gpio13"; ++ function = "gsbi4"; ++ drive-strength = <12>; ++ bias-disable; ++ }; ++ }; ++ + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; +@@ -169,6 +604,53 @@ + }; + }; + ++ nand_pins: nand_pins { ++ disable { ++ pins = "gpio34", "gpio35", "gpio36", ++ "gpio37", "gpio38"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-disable; ++ }; ++ ++ pullups { ++ pins = "gpio39"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-pull-up; ++ }; ++ ++ hold { ++ pins = "gpio40", "gpio41", "gpio42", ++ "gpio43", "gpio44", "gpio45", ++ "gpio46", "gpio47"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-bus-hold; ++ }; ++ }; ++ ++ mdio0_pins: mdio0_pins { ++ mux { ++ pins = "gpio0", "gpio1"; ++ function = "mdio"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; ++ ++ rgmii2_pins: rgmii2_pins { ++ mux { ++ pins = "gpio27", "gpio28", "gpio29", ++ "gpio30", "gpio31", "gpio32", ++ "gpio51", "gpio52", "gpio59", ++ "gpio60", "gpio61", "gpio62"; ++ function = "rgmii2"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; ++ + leds_pins: leds_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", +@@ -231,6 +713,17 @@ + clock-output-names = "acpu1_aux"; + }; + ++ l2cc: clock-controller@2011000 { ++ compatible = "qcom,kpss-gcc", "syscon"; ++ reg = <0x2011000 0x1000>; ++ clock-output-names = "acpu_l2_aux"; ++ }; ++ ++ kraitcc: clock-controller { ++ compatible = "qcom,krait-cc-v1"; ++ #clock-cells = <1>; ++ }; ++ + saw0: regulator@2089000 { + compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; +@@ -243,6 +736,17 @@ + regulator; + }; + ++ saw_l2: regulator@02012000 { ++ compatible = "qcom,saw2", "syscon"; ++ reg = <0x02012000 0x1000>; ++ regulator; ++ }; ++ ++ sic_non_secure: sic-non-secure@12100000 { ++ compatible = "syscon"; ++ reg = <0x12100000 0x10000>; ++ }; ++ + gsbi2: gsbi@12480000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <2>; +@@ -478,6 +982,95 @@ + #reset-cells = <1>; + }; + ++ sfpb_mutex_block: syscon@1200600 { ++ compatible = "syscon"; ++ reg = <0x01200600 0x100>; ++ }; ++ ++ hs_phy_0: hs_phy_0 { ++ compatible = "qcom,ipq806x-usb-phy-hs"; ++ reg = <0x110f8800 0x30>; ++ clocks = <&gcc USB30_0_UTMI_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ ss_phy_0: ss_phy_0 { ++ compatible = "qcom,ipq806x-usb-phy-ss"; ++ reg = <0x110f8830 0x30>; ++ clocks = <&gcc USB30_0_MASTER_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ usb3_0: usb3@110f8800 { ++ compatible = "qcom,dwc3", "syscon"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x110f8800 0x8000>; ++ clocks = <&gcc USB30_0_MASTER_CLK>; ++ clock-names = "core"; ++ ++ ranges; ++ ++ resets = <&gcc USB30_0_MASTER_RESET>; ++ reset-names = "master"; ++ ++ status = "disabled"; ++ ++ dwc3_0: dwc3@11000000 { ++ compatible = "snps,dwc3"; ++ reg = <0x11000000 0xcd00>; ++ interrupts = ; ++ phys = <&hs_phy_0>, <&ss_phy_0>; ++ phy-names = "usb2-phy", "usb3-phy"; ++ dr_mode = "host"; ++ snps,dis_u3_susphy_quirk; ++ }; ++ }; ++ ++ hs_phy_1: hs_phy_1 { ++ compatible = "qcom,ipq806x-usb-phy-hs"; ++ reg = <0x100f8800 0x30>; ++ clocks = <&gcc USB30_1_UTMI_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ ss_phy_1: ss_phy_1 { ++ compatible = "qcom,ipq806x-usb-phy-ss"; ++ reg = <0x100f8830 0x30>; ++ clocks = <&gcc USB30_1_MASTER_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ usb3_1: usb3@100f8800 { ++ compatible = "qcom,dwc3", "syscon"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x100f8800 0x8000>; ++ clocks = <&gcc USB30_1_MASTER_CLK>; ++ clock-names = "core"; ++ ++ ranges; ++ ++ resets = <&gcc USB30_1_MASTER_RESET>; ++ reset-names = "master"; ++ ++ status = "disabled"; ++ ++ dwc3_1: dwc3@10000000 { ++ compatible = "snps,dwc3"; ++ reg = <0x10000000 0xcd00>; ++ interrupts = ; ++ phys = <&hs_phy_1>, <&ss_phy_1>; ++ phy-names = "usb2-phy", "usb3-phy"; ++ dr_mode = "host"; ++ snps,dis_u3_susphy_quirk; ++ }; ++ }; ++ + pcie0: pci@1b500000 { + compatible = "qcom,pcie-ipq8064"; + reg = <0x1b500000 0x1000 +@@ -739,6 +1332,59 @@ + status = "disabled"; + }; + ++ adm_dma: dma@18300000 { ++ compatible = "qcom,adm"; ++ reg = <0x18300000 0x100000>; ++ interrupts = ; ++ #dma-cells = <1>; ++ ++ clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; ++ clock-names = "core", "iface"; ++ ++ resets = <&gcc ADM0_RESET>, ++ <&gcc ADM0_PBUS_RESET>, ++ <&gcc ADM0_C0_RESET>, ++ <&gcc ADM0_C1_RESET>, ++ <&gcc ADM0_C2_RESET>; ++ reset-names = "clk", "pbus", "c0", "c1", "c2"; ++ qcom,ee = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ nand_controller: nand-controller@1ac00000 { ++ compatible = "qcom,ipq806x-nand"; ++ reg = <0x1ac00000 0x800>; ++ ++ clocks = <&gcc EBI2_CLK>, ++ <&gcc EBI2_AON_CLK>; ++ clock-names = "core", "aon"; ++ ++ dmas = <&adm_dma 3>; ++ dma-names = "rxtx"; ++ qcom,cmd-crci = <15>; ++ qcom,data-crci = <3>; ++ ++ status = "disabled"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ mdio0: mdio@37000000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ compatible = "qcom,ipq8064-mdio", "syscon"; ++ reg = <0x37000000 0x200000>; ++ resets = <&gcc GMAC_CORE1_RESET>; ++ reset-names = "stmmaceth"; ++ clocks = <&gcc GMAC_CORE1_CLK>; ++ clock-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ + vsdcc_fixed: vsdcc-regulator { + compatible = "regulator-fixed"; + regulator-name = "SDCC Power"; +@@ -814,4 +1460,17 @@ + }; + }; + }; ++ ++ sfpb_mutex: sfpb-mutex { ++ compatible = "qcom,sfpb-mutex"; ++ syscon = <&sfpb_mutex_block 4 4>; ++ ++ #hwlock-cells = <1>; ++ }; ++ ++ smem { ++ compatible = "qcom,smem"; ++ memory-region = <&smem>; ++ hwlocks = <&sfpb_mutex 3>; ++ }; + }; diff --git a/ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch b/ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch new file mode 100644 index 0000000..e5ea8e6 --- /dev/null +++ b/ipq806x/patches-5.10/084-ipq8064-v1.0-dtsi-cleanup.patch @@ -0,0 +1,89 @@ +This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches +instead of keeping a local version. +We drop partitions, LEDs and keys from the file as we will implement +them differently anyway. + +--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi +@@ -42,16 +42,6 @@ + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; +- +- partition@0 { +- label = "rootfs"; +- reg = <0x0 0x1000000>; +- }; +- +- partition@1 { +- label = "scratch"; +- reg = <0x1000000 0x1000000>; +- }; + }; + }; + }; +@@ -64,64 +54,5 @@ + ports-implemented = <0x1>; + status = "ok"; + }; +- +- gpio_keys { +- compatible = "gpio-keys"; +- pinctrl-0 = <&buttons_pins>; +- pinctrl-names = "default"; +- +- button@1 { +- label = "reset"; +- linux,code = ; +- gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; +- linux,input-type = <1>; +- debounce-interval = <60>; +- }; +- button@2 { +- label = "wps"; +- linux,code = ; +- gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; +- linux,input-type = <1>; +- debounce-interval = <60>; +- }; +- }; +- +- leds { +- compatible = "gpio-leds"; +- pinctrl-0 = <&leds_pins>; +- pinctrl-names = "default"; +- +- led@7 { +- label = "led_usb1"; +- gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "usbdev"; +- default-state = "off"; +- }; +- +- led@8 { +- label = "led_usb3"; +- gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "usbdev"; +- default-state = "off"; +- }; +- +- led@9 { +- label = "status_led_fail"; +- gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- +- led@26 { +- label = "sata_led"; +- gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- +- led@53 { +- label = "status_led_pass"; +- gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- }; + }; + }; diff --git a/ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch b/ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch new file mode 100644 index 0000000..58f6a46 --- /dev/null +++ b/ipq806x/patches-5.10/085-ipq8064-v1.0-dtsi-additions.patch @@ -0,0 +1,14 @@ +This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches +instead of keeping a local version. This patch adds our local adjustments +for the (local) additional contents of qcom-ipq8064.dtsi + +--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi +@@ -56,3 +56,7 @@ + }; + }; + }; ++ ++&CPU_SPC { ++ status = "okay"; ++}; diff --git a/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch b/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch new file mode 100644 index 0000000..8423fd1 --- /dev/null +++ b/ipq806x/patches-5.10/086-ipq8064-fix-duplicate-node.patch @@ -0,0 +1,145 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts ++++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts +@@ -24,73 +24,6 @@ + device_type = "memory"; + }; + +- mdio0: mdio@0 { +- status = "okay"; +- compatible = "virtual,mdio-gpio"; +- gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH>, +- <&qcom_pinmux 0 GPIO_ACTIVE_HIGH>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pinctrl-0 = <&mdio0_pins>; +- pinctrl-names = "default"; +- +- switch0: switch@10 { +- compatible = "qca,qca8337"; +- #address-cells = <1>; +- #size-cells = <0>; +- +- dsa,member = <0 0>; +- +- pinctrl-0 = <&sw0_reset_pin>; +- pinctrl-names = "default"; +- +- reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; +- reg = <0x10>; +- +- ports { +- #address-cells = <1>; +- #size-cells = <0>; +- +- switch0cpu: port@0 { +- reg = <0>; +- label = "cpu"; +- ethernet = <&gmac0>; +- phy-mode = "rgmii-id"; +- fixed-link { +- speed = <1000>; +- full-duplex; +- }; +- }; +- +- port@1 { +- reg = <1>; +- label = "sw1"; +- }; +- +- port@2 { +- reg = <2>; +- label = "sw2"; +- }; +- +- port@3 { +- reg = <3>; +- label = "sw3"; +- }; +- +- port@4 { +- reg = <4>; +- label = "sw4"; +- }; +- +- port@5 { +- reg = <5>; +- label = "sw5"; +- }; +- }; +- }; +- }; +- + mdio1: mdio@1 { + status = "okay"; + compatible = "virtual,mdio-gpio"; +@@ -216,6 +149,68 @@ + }; + }; + ++&mdio0 { ++ status = "okay"; ++ ++ pinctrl-0 = <&mdio0_pins>; ++ pinctrl-names = "default"; ++ ++ switch0: switch@10 { ++ compatible = "qca,qca8337"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dsa,member = <0 0>; ++ ++ pinctrl-0 = <&sw0_reset_pin>; ++ pinctrl-names = "default"; ++ ++ reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; ++ reg = <0x10>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ switch0cpu: port@0 { ++ reg = <0>; ++ label = "cpu"; ++ ethernet = <&gmac0>; ++ phy-mode = "rgmii-id"; ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "sw1"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "sw2"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "sw3"; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "sw4"; ++ }; ++ ++ port@5 { ++ reg = <5>; ++ label = "sw5"; ++ }; ++ }; ++ }; ++}; ++ + &gmac0 { + status = "okay"; + diff --git a/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch b/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch new file mode 100644 index 0000000..19c3d09 --- /dev/null +++ b/ipq806x/patches-5.10/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch @@ -0,0 +1,51 @@ +From a206d4061f1cc2c5cd17ee45c53a0ba711e48e6d Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 16:42:52 +0100 +Subject: [PATCH 3/3] drivers: cpufreq: qcom-cpufreq-nvmem: support specific + cpufreq driver + +Add support for specific cpufreq driver for qcom-cpufreq-nvmem driver. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -52,6 +52,7 @@ struct qcom_cpufreq_match_data { + char **pvs_name, + struct qcom_cpufreq_drv *drv); + const char **genpd_names; ++ const char *cpufreq_driver; + }; + + struct qcom_cpufreq_drv { +@@ -250,6 +251,7 @@ static const struct qcom_cpufreq_match_d + + static const struct qcom_cpufreq_match_data match_data_krait = { + .get_version = qcom_cpufreq_krait_name_version, ++ .cpufreq_driver = "krait-cpufreq", + }; + + static const char *qcs404_genpd_names[] = { "cpr", NULL }; +@@ -385,6 +387,19 @@ static int qcom_cpufreq_probe(struct pla + } + } + ++ if (drv->data->cpufreq_driver) { ++ cpufreq_dt_pdev = platform_device_register_simple( ++ drv->data->cpufreq_driver, -1, NULL, 0); ++ if (!IS_ERR(cpufreq_dt_pdev)) { ++ platform_set_drvdata(pdev, drv); ++ return 0; ++ } else { ++ dev_err(cpu_dev, ++ "Failed to register dedicated %s cpufreq\n", ++ drv->data->cpufreq_driver); ++ } ++ } ++ + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) { diff --git a/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch b/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch new file mode 100644 index 0000000..3067ec7 --- /dev/null +++ b/ipq806x/patches-5.10/097-1-ipq806x-gcc-add-missing-clk-flag.patch @@ -0,0 +1,115 @@ +From 0af44917941cbfecdc86bb9bf05ff01d22a88973 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 16:52:56 +0100 +Subject: [PATCH 1/4] ipq806x: gcc: add missing clk flag + +Some flag are missing from the original code. +These clk can't be set using the protected-clock proprities as they +cause the malfunction of the serial interface. +These clks are needed for the rpm interface to work proprely or the +cpu regulators starts to fail as soon as they are disabled by the +kernel. + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/gcc-ipq806x.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -65,6 +65,7 @@ static struct clk_pll pll3 = { + .parent_names = (const char *[]){ "pxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, ++ .flags = CLK_IS_CRITICAL, + }, + }; + +@@ -782,7 +783,7 @@ static struct clk_rcg gsbi4_qup_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -798,7 +799,7 @@ static struct clk_branch gsbi4_qup_clk = + .parent_names = (const char *[]){ "gsbi4_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -880,7 +881,7 @@ static struct clk_rcg gsbi6_qup_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -945,7 +946,7 @@ static struct clk_branch gsbi7_qup_clk = + .parent_names = (const char *[]){ "gsbi7_qup_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -991,6 +992,7 @@ static struct clk_branch gsbi4_h_clk = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_h_clk", + .ops = &clk_branch_ops, ++ .flags = CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -1293,6 +1295,7 @@ static struct clk_rcg sdc1_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, ++ .flags = CLK_SET_RATE_GATE, + }, + } + }; +@@ -1341,6 +1344,7 @@ static struct clk_rcg sdc3_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, ++ .flags = CLK_SET_RATE_GATE, + }, + } + }; +@@ -1424,6 +1428,7 @@ static struct clk_rcg tsif_ref_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, ++ .flags = CLK_SET_RATE_GATE, + }, + } + }; +@@ -2694,7 +2699,8 @@ static struct clk_dyn_rcg ubi32_core1_sr + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, +- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, ++ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE | ++ CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -2747,7 +2753,8 @@ static struct clk_dyn_rcg ubi32_core2_sr + .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, +- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, ++ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE | ++ CLK_IGNORE_UNUSED, + }, + }, + }; diff --git a/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch b/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch new file mode 100644 index 0000000..cd2cb33 --- /dev/null +++ b/ipq806x/patches-5.10/097-2-ipq806x-lcc-add-missing-reset.patch @@ -0,0 +1,59 @@ +From 3a5f1793c0bf4a6b536751886b0a44589fe05f35 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 17:00:07 +0100 +Subject: [PATCH 2/4] ipq806x: lcc: add missing reset + +Add missing reset for ipq806x lcc clk + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/lcc-ipq806x.c | 8 ++++++++ + include/dt-bindings/clock/qcom,lcc-ipq806x.h | 1 + + 2 files changed, 9 insertions(+) + +--- a/drivers/clk/qcom/lcc-ipq806x.c ++++ b/drivers/clk/qcom/lcc-ipq806x.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include + +@@ -22,6 +23,7 @@ + #include "clk-branch.h" + #include "clk-regmap-divider.h" + #include "clk-regmap-mux.h" ++#include "reset.h" + + static struct clk_pll pll4 = { + .l_reg = 0x4, +@@ -39,6 +41,10 @@ static struct clk_pll pll4 = { + }, + }; + ++static const struct qcom_reset_map lcc_ipq806x_resets[] = { ++ [LCC_PCM_RESET] = { 0x54, 13 }, ++}; ++ + static const struct pll_config pll4_config = { + .l = 0xf, + .m = 0x91, +@@ -417,6 +423,8 @@ static const struct qcom_cc_desc lcc_ipq + .config = &lcc_ipq806x_regmap_config, + .clks = lcc_ipq806x_clks, + .num_clks = ARRAY_SIZE(lcc_ipq806x_clks), ++ .resets = lcc_ipq806x_resets, ++ .num_resets = ARRAY_SIZE(lcc_ipq806x_resets), + }; + + static const struct of_device_id lcc_ipq806x_match_table[] = { +--- a/include/dt-bindings/clock/qcom,lcc-ipq806x.h ++++ b/include/dt-bindings/clock/qcom,lcc-ipq806x.h +@@ -19,4 +19,5 @@ + #define SPDIF_CLK 10 + #define AHBIX_CLK 11 + ++#define LCC_PCM_RESET 0 + #endif diff --git a/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch b/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch new file mode 100644 index 0000000..bf1c1a4 --- /dev/null +++ b/ipq806x/patches-5.10/097-3-clk-qcom-krait-add-missing-enable-disable.patch @@ -0,0 +1,57 @@ +From f8fdbecdaca97f0f2eebd77256e2eca4a8da6c39 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 17:08:16 +0100 +Subject: [PATCH 3/4] clk: qcom: krait: add missing enable disable + +Add missing enable disable mux function. Add extra check to +div2_round_rate. + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/clk-krait.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +--- a/drivers/clk/qcom/clk-krait.c ++++ b/drivers/clk/qcom/clk-krait.c +@@ -68,7 +68,25 @@ static u8 krait_mux_get_parent(struct cl + return clk_mux_val_to_index(hw, mux->parent_map, 0, sel); + } + ++static int krait_mux_enable(struct clk_hw *hw) ++{ ++ struct krait_mux_clk *mux = to_krait_mux_clk(hw); ++ ++ __krait_mux_set_sel(mux, mux->en_mask); ++ ++ return 0; ++} ++ ++static void krait_mux_disable(struct clk_hw *hw) ++{ ++ struct krait_mux_clk *mux = to_krait_mux_clk(hw); ++ ++ __krait_mux_set_sel(mux, mux->safe_sel); ++} ++ + const struct clk_ops krait_mux_clk_ops = { ++ .enable = krait_mux_enable, ++ .disable = krait_mux_disable, + .set_parent = krait_mux_set_parent, + .get_parent = krait_mux_get_parent, + .determine_rate = __clk_mux_determine_rate_closest, +@@ -79,8 +97,13 @@ EXPORT_SYMBOL_GPL(krait_mux_clk_ops); + static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) + { +- *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2); +- return DIV_ROUND_UP(*parent_rate, 2); ++ struct clk_hw *hw_parent = clk_hw_get_parent(hw); ++ ++ if (hw_parent) { ++ *parent_rate = clk_hw_round_rate(hw_parent, rate * 2); ++ return DIV_ROUND_UP(*parent_rate, 2); ++ } else ++ return -1; + } + + static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, diff --git a/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch b/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch new file mode 100644 index 0000000..f8f4924 --- /dev/null +++ b/ipq806x/patches-5.10/097-4-ipq806x-gcc-add-missing-clk-and-reset-for-crypto-eng.patch @@ -0,0 +1,372 @@ +From 22a0f55b0e505fbbbb680e451a62878bc97f7ff1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 17:23:38 +0100 +Subject: [PATCH 4/4] ipq806x: gcc: add missing clk and reset for crypto engine + +Add missing clk and reset needed for nss additional core and crypto +engine. + +Signed-off-by: Ansuel Smith +--- + drivers/clk/qcom/gcc-ipq806x.c | 250 +++++++++++++++++++ + include/dt-bindings/clock/qcom,gcc-ipq806x.h | 5 +- + include/dt-bindings/reset/qcom,gcc-ipq806x.h | 5 + + 3 files changed, 259 insertions(+), 1 deletion(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -223,7 +223,9 @@ static struct clk_regmap pll14_vote = { + + static struct pll_freq_tbl pll18_freq_tbl[] = { + NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625), ++ NSS_PLL_RATE(600000000, 48, 0, 1, 0x01495625), + NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625), ++ NSS_PLL_RATE(800000000, 64, 0, 1, 0x01495625), + }; + + static struct clk_pll pll18 = { +@@ -245,6 +247,22 @@ static struct clk_pll pll18 = { + }, + }; + ++static struct clk_pll pll11 = { ++ .l_reg = 0x3184, ++ .m_reg = 0x3188, ++ .n_reg = 0x318c, ++ .config_reg = 0x3194, ++ .mode_reg = 0x3180, ++ .status_reg = 0x3198, ++ .status_bit = 16, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "pll11", ++ .parent_names = (const char *[]){ "pxo" }, ++ .num_parents = 1, ++ .ops = &clk_pll_ops, ++ }, ++}; ++ + enum { + P_PXO, + P_PLL8, +@@ -253,6 +271,7 @@ enum { + P_CXO, + P_PLL14, + P_PLL18, ++ P_PLL11, + }; + + static const struct parent_map gcc_pxo_pll8_map[] = { +@@ -320,6 +339,42 @@ static const char * const gcc_pxo_pll8_p + "pll18", + }; + ++static const struct parent_map gcc_pxo_pll8_pll0_pll14_pll18_pll11_map[] = { ++ { P_PXO, 0 }, ++ { P_PLL8, 4 }, ++ { P_PLL0, 2 }, ++ { P_PLL14, 5 }, ++ { P_PLL18, 1 }, ++ { P_PLL11, 3 }, ++}; ++ ++static const char *gcc_pxo_pll8_pll0_pll14_pll18_pll11[] = { ++ "pxo", ++ "pll8_vote", ++ "pll0_vote", ++ "pll14", ++ "pll18", ++ "pll11" ++}; ++ ++static const struct parent_map gcc_pxo_pll3_pll0_pll14_pll18_pll11_map[] = { ++ { P_PXO, 0 }, ++ { P_PLL3, 6 }, ++ { P_PLL0, 2 }, ++ { P_PLL14, 5 }, ++ { P_PLL18, 1 }, ++ { P_PLL11, 3 }, ++}; ++ ++static const char *gcc_pxo_pll3_pll0_pll14_pll18_pll11[] = { ++ "pxo", ++ "pll3", ++ "pll0_vote", ++ "pll14", ++ "pll18", ++ "pll11" ++}; ++ + static struct freq_tbl clk_tbl_gsbi_uart[] = { + { 1843200, P_PLL8, 2, 6, 625 }, + { 3686400, P_PLL8, 2, 12, 625 }, +@@ -1261,6 +1316,7 @@ static const struct freq_tbl clk_tbl_sdc + { 20210000, P_PLL8, 1, 1, 19 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 48000000, P_PLL8, 4, 1, 2 }, ++ { 52000000, P_PLL8, 1, 2, 15 }, /* 51.2 Mhz */ + { 64000000, P_PLL8, 3, 1, 2 }, + { 96000000, P_PLL8, 4, 0, 0 }, + { 192000000, P_PLL8, 2, 0, 0 }, +@@ -2647,7 +2703,9 @@ static const struct freq_tbl clk_tbl_nss + { 110000000, P_PLL18, 1, 1, 5 }, + { 275000000, P_PLL18, 2, 0, 0 }, + { 550000000, P_PLL18, 1, 0, 0 }, ++ { 600000000, P_PLL18, 1, 0, 0 }, + { 733000000, P_PLL18, 1, 0, 0 }, ++ { 800000000, P_PLL18, 1, 0, 0 }, + { } + }; + +@@ -2759,6 +2817,186 @@ static struct clk_dyn_rcg ubi32_core2_sr + }, + }; + ++static const struct freq_tbl clk_tbl_ce5_core[] = { ++ { 150000000, P_PLL3, 8, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_core_src = { ++ .ns_reg[0] = 0x36C4, ++ .ns_reg[1] = 0x36C8, ++ .bank_reg = 0x36C0, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_core, ++ .clkr = { ++ .enable_reg = 0x36C0, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_core_src", ++ .parent_names = gcc_pxo_pll3_pll0_pll14_pll18_pll11, ++ .num_parents = 6, ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_core_clk = { ++ .halt_reg = 0x2FDC, ++ .halt_bit = 5, ++ .hwcg_reg = 0x36CC, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x36CC, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_core_clk", ++ .parent_names = (const char *[]){ ++ "ce5_core_src", ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ ++static const struct freq_tbl clk_tbl_ce5_a_clk[] = { ++ { 160000000, P_PLL0, 5, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_a_clk_src = { ++ .ns_reg[0] = 0x3d84, ++ .ns_reg[1] = 0x3d88, ++ .bank_reg = 0x3d80, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_a_clk, ++ .clkr = { ++ .enable_reg = 0x3d80, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_a_clk_src", ++ .parent_names = gcc_pxo_pll8_pll0_pll14_pll18_pll11, ++ .num_parents = 6, ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_a_clk = { ++ .halt_reg = 0x3c20, ++ .halt_bit = 12, ++ .hwcg_reg = 0x3d8c, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x3d8c, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_a_clk", ++ .parent_names = (const char *[]){ ++ "ce5_a_clk_src", ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ ++static const struct freq_tbl clk_tbl_ce5_h_clk[] = { ++ { 160000000, P_PLL0, 5, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_h_clk_src = { ++ .ns_reg[0] = 0x3c64, ++ .ns_reg[1] = 0x3c68, ++ .bank_reg = 0x3c60, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_h_clk, ++ .clkr = { ++ .enable_reg = 0x3c60, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_h_clk_src", ++ .parent_names = gcc_pxo_pll8_pll0_pll14_pll18_pll11, ++ .num_parents = 6, ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_h_clk = { ++ .halt_reg = 0x3c20, ++ .halt_bit = 11, ++ .hwcg_reg = 0x3c6c, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x3c6c, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_h_clk", ++ .parent_names = (const char *[]){ ++ "ce5_h_clk_src", ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ + static struct clk_regmap *gcc_ipq806x_clks[] = { + [PLL0] = &pll0.clkr, + [PLL0_VOTE] = &pll0_vote, +@@ -2766,6 +3004,7 @@ static struct clk_regmap *gcc_ipq806x_cl + [PLL4_VOTE] = &pll4_vote, + [PLL8] = &pll8.clkr, + [PLL8_VOTE] = &pll8_vote, ++ [PLL11] = &pll11.clkr, + [PLL14] = &pll14.clkr, + [PLL14_VOTE] = &pll14_vote, + [PLL18] = &pll18.clkr, +@@ -2880,6 +3119,12 @@ static struct clk_regmap *gcc_ipq806x_cl + [PLL9] = &hfpll0.clkr, + [PLL10] = &hfpll1.clkr, + [PLL12] = &hfpll_l2.clkr, ++ [CE5_A_CLK_SRC] = &ce5_a_clk_src.clkr, ++ [CE5_A_CLK] = &ce5_a_clk.clkr, ++ [CE5_H_CLK_SRC] = &ce5_h_clk_src.clkr, ++ [CE5_H_CLK] = &ce5_h_clk.clkr, ++ [CE5_CORE_CLK_SRC] = &ce5_core_src.clkr, ++ [CE5_CORE_CLK] = &ce5_core_clk.clkr, + }; + + static const struct qcom_reset_map gcc_ipq806x_resets[] = { +@@ -3011,6 +3256,11 @@ static const struct qcom_reset_map gcc_i + [GMAC_CORE3_RESET] = { 0x3cfc, 0 }, + [GMAC_CORE4_RESET] = { 0x3d1c, 0 }, + [GMAC_AHB_RESET] = { 0x3e24, 0 }, ++ [CRYPTO_ENG1_RESET] = { 0x3e00, 0}, ++ [CRYPTO_ENG2_RESET] = { 0x3e04, 0}, ++ [CRYPTO_ENG3_RESET] = { 0x3e08, 0}, ++ [CRYPTO_ENG4_RESET] = { 0x3e0c, 0}, ++ [CRYPTO_AHB_RESET] = { 0x3e10, 0}, + [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 }, + [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 }, + [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 }, +--- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h ++++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h +@@ -240,7 +240,7 @@ + #define PLL14 232 + #define PLL14_VOTE 233 + #define PLL18 234 +-#define CE5_SRC 235 ++#define CE5_A_CLK 235 + #define CE5_H_CLK 236 + #define CE5_CORE_CLK 237 + #define CE3_SLEEP_CLK 238 +@@ -283,5 +283,8 @@ + #define EBI2_AON_CLK 281 + #define NSSTCM_CLK_SRC 282 + #define NSSTCM_CLK 283 ++#define CE5_A_CLK_SRC 285 ++#define CE5_H_CLK_SRC 286 ++#define CE5_CORE_CLK_SRC 287 + + #endif +--- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h ++++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h +@@ -163,5 +163,10 @@ + #define NSS_CAL_PRBS_RST_N_RESET 154 + #define NSS_LCKDT_RST_N_RESET 155 + #define NSS_SRDS_N_RESET 156 ++#define CRYPTO_ENG1_RESET 157 ++#define CRYPTO_ENG2_RESET 158 ++#define CRYPTO_ENG3_RESET 159 ++#define CRYPTO_ENG4_RESET 160 ++#define CRYPTO_AHB_RESET 161 + + #endif diff --git a/ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch b/ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch new file mode 100644 index 0000000..7696862 --- /dev/null +++ b/ipq806x/patches-5.10/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch @@ -0,0 +1,681 @@ +From cc41a266280cad0b55319e614167c88dff344248 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 16:33:10 +0100 +Subject: [PATCH 1/8] cpufreq: add Krait dedicated scaling driver + +This new driver is based on generic cpufreq-dt driver. +Krait SoCs have 2-4 cpu and one shared L2 cache that can +operate at different frequency based on the maximum cpu clk +across all core. +L2 frequency and voltage are scaled on every frequency change +if needed. On Krait SoCs is present a bug that can cause +transition problem between frequency bin, to workaround this +on more than one transition, the L2 frequency is first set to the +base rate and then to the target rate. +The L2 frequency use the OPP framework and use the opp-level +bindings to link the l2 freq to different cpu freq. This is needed +as the Krait l2 clk are note mapped 1:1 to the core clks and some +of the l2 clk is set based on a range of the cpu clks. If the driver +find a broken config (for example no opp-level set) the l2 scaling is +skipped. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/Kconfig.arm | 14 +- + drivers/cpufreq/Makefile | 2 + + drivers/cpufreq/qcom-cpufreq-krait.c | 589 +++++++++++++++++++++++++++ + 3 files changed, 604 insertions(+), 1 deletion(-) + create mode 100644 drivers/cpufreq/qcom-cpufreq-krait.c + +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -150,6 +150,18 @@ config ARM_QCOM_CPUFREQ_HW + The driver implements the cpufreq interface for this HW engine. + Say Y if you want to support CPUFreq HW. + ++config ARM_QCOM_CPUFREQ_KRAIT ++ tristate "CPU Frequency scaling support for Krait SoCs" ++ depends on ARCH_QCOM || COMPILE_TEST ++ select PM_OPP ++ select ARM_QCOM_CPUFREQ_NVMEM ++ help ++ This adds the CPUFreq driver for Qualcomm Krait SoC based boards. ++ This scale the cache clk and regulator based on the different cpu ++ clks when scaling the different cores clk. ++ ++ If in doubt, say N. ++ + config ARM_RASPBERRYPI_CPUFREQ + tristate "Raspberry Pi cpufreq support" + depends on CLK_RASPBERRYPI || COMPILE_TEST +@@ -339,4 +351,4 @@ config ARM_PXA2xx_CPUFREQ + help + This add the CPUFreq driver support for Intel PXA2xx SOCs. + +- If in doubt, say N. ++ If in doubt, say N. +\ No newline at end of file +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -63,6 +63,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2 + obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o ++obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRAIT) += qcom-cpufreq-krait.o + obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o + obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o + obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o +@@ -86,6 +87,7 @@ obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += te + obj-$(CONFIG_ARM_TEGRA194_CPUFREQ) += tegra194-cpufreq.o + obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o + obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o ++obj-$(CONFIG_ARM_KRAIT_CPUFREQ) += krait-cpufreq.o + + + ################################################################################## +--- /dev/null ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -0,0 +1,603 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpufreq-dt.h" ++ ++static struct platform_device *l2_pdev; ++ ++struct private_data { ++ struct opp_table *opp_table; ++ struct device *cpu_dev; ++ const char *reg_name; ++ bool have_static_opps; ++}; ++ ++static int set_target(struct cpufreq_policy *policy, unsigned int index) ++{ ++ struct private_data *priv = policy->driver_data; ++ unsigned long freq = policy->freq_table[index].frequency; ++ unsigned long target_freq = freq * 1000; ++ struct dev_pm_opp *opp; ++ unsigned int level; ++ int cpu, ret; ++ ++ if (l2_pdev) { ++ int policy_cpu = policy->cpu; ++ ++ /* find the max freq across all core */ ++ for_each_present_cpu(cpu) ++ if (cpu != policy_cpu) ++ target_freq = max( ++ target_freq, ++ (unsigned long)cpufreq_quick_get(cpu)); ++ ++ opp = dev_pm_opp_find_freq_exact(priv->cpu_dev, target_freq, ++ true); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, "failed to find OPP for %ld\n", ++ target_freq); ++ return PTR_ERR(opp); ++ } ++ level = dev_pm_opp_get_level(opp); ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Hardware constraint: ++ * Krait CPU cannot operate at 384MHz with L2 at 1Ghz. ++ * Assume index 0 with the idle freq and level > 0 as ++ * any L2 freq > 384MHz. ++ * Skip CPU freq change in this corner case. ++ */ ++ if (unlikely(index == 0 && level != 0)) { ++ dev_err(priv->cpu_dev, "Krait CPU can't operate at idle freq with L2 at 1GHz"); ++ return -EINVAL; ++ } ++ ++ opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, ++ "failed to find level OPP for %d\n", level); ++ return PTR_ERR(opp); ++ } ++ target_freq = dev_pm_opp_get_freq(opp); ++ dev_pm_opp_put(opp); ++ ++ ret = dev_pm_opp_set_rate(&l2_pdev->dev, target_freq); ++ if (ret) ++ return ret; ++ } ++ ++ ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); ++ if (ret) ++ return ret; ++ ++ arch_set_freq_scale(policy->related_cpus, freq, ++ policy->cpuinfo.max_freq); ++ ++ return 0; ++} ++ ++/* ++ * An earlier version of opp-v1 bindings used to name the regulator ++ * "cpu0-supply", we still need to handle that for backwards compatibility. ++ */ ++static const char *find_supply_name(struct device *dev) ++{ ++ struct device_node *np; ++ struct property *pp; ++ int cpu = dev->id; ++ const char *name = NULL; ++ ++ np = of_node_get(dev->of_node); ++ ++ /* This must be valid for sure */ ++ if (WARN_ON(!np)) ++ return NULL; ++ ++ /* Try "cpu0" for older DTs */ ++ if (!cpu) { ++ pp = of_find_property(np, "cpu0-supply", NULL); ++ if (pp) { ++ name = "cpu0"; ++ goto node_put; ++ } ++ } ++ ++ pp = of_find_property(np, "cpu-supply", NULL); ++ if (pp) { ++ name = "cpu"; ++ goto node_put; ++ } ++ ++ dev_dbg(dev, "no regulator for cpu%d\n", cpu); ++node_put: ++ of_node_put(np); ++ return name; ++} ++ ++static int resources_available(void) ++{ ++ struct device *cpu_dev; ++ struct regulator *cpu_reg; ++ struct clk *cpu_clk; ++ int ret = 0; ++ const char *name; ++ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ ret = PTR_ERR_OR_ZERO(cpu_clk); ++ if (ret) { ++ /* ++ * If cpu's clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "clock not ready, retry\n"); ++ else ++ dev_err(cpu_dev, "failed to get clock: %d\n", ret); ++ ++ return ret; ++ } ++ ++ clk_put(cpu_clk); ++ ++ name = find_supply_name(cpu_dev); ++ /* Platform doesn't require regulator */ ++ if (!name) ++ return 0; ++ ++ cpu_reg = regulator_get_optional(cpu_dev, name); ++ ret = PTR_ERR_OR_ZERO(cpu_reg); ++ if (ret) { ++ /* ++ * If cpu's regulator supply node is present, but regulator is ++ * not yet registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n"); ++ else ++ dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret); ++ ++ return ret; ++ } ++ ++ regulator_put(cpu_reg); ++ return 0; ++} ++ ++static int cpufreq_init(struct cpufreq_policy *policy) ++{ ++ struct cpufreq_frequency_table *freq_table; ++ struct opp_table *opp_table = NULL; ++ unsigned int transition_latency; ++ struct private_data *priv; ++ struct device *cpu_dev; ++ bool fallback = false; ++ struct clk *cpu_clk; ++ const char *name; ++ int ret; ++ ++ cpu_dev = get_cpu_device(policy->cpu); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu%d device\n", policy->cpu); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ if (IS_ERR(cpu_clk)) { ++ ret = PTR_ERR(cpu_clk); ++ dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ /* Get OPP-sharing information from "operating-points-v2" bindings */ ++ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) { ++ if (ret != -ENOENT) ++ goto out_put_clk; ++ ++ /* ++ * operating-points-v2 not supported, fallback to old method of ++ * finding shared-OPPs for backward compatibility if the ++ * platform hasn't set sharing CPUs. ++ */ ++ if (dev_pm_opp_get_sharing_cpus(cpu_dev, policy->cpus)) ++ fallback = true; ++ } ++ ++ /* ++ * OPP layer will be taking care of regulators now, but it needs to know ++ * the name of the regulator first. ++ */ ++ name = find_supply_name(cpu_dev); ++ if (name) { ++ opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ dev_err(cpu_dev, ++ "Failed to set regulator for cpu%d: %d\n", ++ policy->cpu, ret); ++ goto out_put_clk; ++ } ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto out_put_regulator; ++ } ++ ++ priv->reg_name = name; ++ priv->opp_table = opp_table; ++ ++ /* ++ * Initialize OPP tables for all policy->cpus. They will be shared by ++ * all CPUs which have marked their CPUs shared with OPP bindings. ++ * ++ * For platforms not using operating-points-v2 bindings, we do this ++ * before updating policy->cpus. Otherwise, we will end up creating ++ * duplicate OPPs for policy->cpus. ++ * ++ * OPPs might be populated at runtime, don't check for error here ++ */ ++ if (!dev_pm_opp_of_cpumask_add_table(policy->cpus)) ++ priv->have_static_opps = true; ++ ++ /* ++ * But we need OPP table to function so if it is not there let's ++ * give platform code chance to provide it for us. ++ */ ++ ret = dev_pm_opp_get_opp_count(cpu_dev); ++ if (ret <= 0) { ++ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); ++ ret = -EPROBE_DEFER; ++ goto out_free_opp; ++ } ++ ++ if (fallback) { ++ cpumask_setall(policy->cpus); ++ ++ /* ++ * OPP tables are initialized only for policy->cpu, do it for ++ * others as well. ++ */ ++ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) ++ dev_err(cpu_dev, ++ "%s: failed to mark OPPs as shared: %d\n", ++ __func__, ret); ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); ++ goto out_free_opp; ++ } ++ ++ priv->cpu_dev = cpu_dev; ++ ++ policy->driver_data = priv; ++ policy->clk = cpu_clk; ++ policy->freq_table = freq_table; ++ ++ policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; ++ ++ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); ++ if (!transition_latency) ++ transition_latency = CPUFREQ_ETERNAL; ++ ++ policy->cpuinfo.transition_latency = transition_latency; ++ policy->dvfs_possible_from_any_cpu = true; ++ ++ dev_pm_opp_of_register_em(cpu_dev, policy->cpus); ++ ++ return 0; ++ ++out_free_opp: ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->cpus); ++ kfree(priv); ++out_put_regulator: ++ if (name) ++ dev_pm_opp_put_regulators(opp_table); ++out_put_clk: ++ clk_put(cpu_clk); ++ ++ return ret; ++} ++ ++static int cpufreq_online(struct cpufreq_policy *policy) ++{ ++ /* We did light-weight tear down earlier, nothing to do here */ ++ return 0; ++} ++ ++static int cpufreq_offline(struct cpufreq_policy *policy) ++{ ++ /* ++ * Preserve policy->driver_data and don't free resources on light-weight ++ * tear down. ++ */ ++ return 0; ++} ++ ++static int cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ struct private_data *priv = policy->driver_data; ++ ++ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); ++ if (priv->reg_name) ++ dev_pm_opp_put_regulators(priv->opp_table); ++ ++ clk_put(policy->clk); ++ kfree(priv); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver krait_cpufreq_driver = { ++ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | ++ CPUFREQ_IS_COOLING_DEV, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = set_target, ++ .get = cpufreq_generic_get, ++ .init = cpufreq_init, ++ .exit = cpufreq_exit, ++ .online = cpufreq_online, ++ .offline = cpufreq_offline, ++ .name = "krait-cpufreq", ++ .suspend = cpufreq_generic_suspend, ++}; ++ ++struct krait_data { ++ unsigned long idle_freq; ++ bool regulator_enabled; ++}; ++ ++static int krait_cache_set_opp(struct dev_pm_set_opp_data *data) ++{ ++ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; ++ struct dev_pm_opp_supply *supply = &data->new_opp.supplies[0]; ++ struct regulator *reg = data->regulators[0]; ++ struct clk *clk = data->clk; ++ struct krait_data *kdata; ++ unsigned long idle_freq; ++ int ret; ++ ++ kdata = (struct krait_data *)dev_get_drvdata(data->dev); ++ idle_freq = kdata->idle_freq; ++ ++ /* Scaling up? Scale voltage before frequency */ ++ if (freq >= old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ if (ret) ++ goto exit; ++ } ++ ++ /* ++ * Set to idle bin if switching from normal to high bin ++ * or vice versa. It has been notice that a bug is triggered ++ * in cache scaling when more than one bin is scaled, to fix ++ * this we first need to transition to the base rate and then ++ * to target rate ++ */ ++ if (likely(freq != idle_freq && old_freq != idle_freq)) { ++ ret = clk_set_rate(clk, idle_freq); ++ if (ret) ++ goto exit; ++ } ++ ++ ret = clk_set_rate(clk, freq); ++ if (ret) ++ goto exit; ++ ++ /* Scaling down? Scale voltage after frequency */ ++ if (freq < old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ } ++ ++ if (unlikely(!kdata->regulator_enabled)) { ++ ret = regulator_enable(reg); ++ if (ret < 0) ++ dev_warn(data->dev, "Failed to enable regulator: %d", ret); ++ else ++ kdata->regulator_enabled = true; ++ } ++ ++exit: ++ return ret; ++}; ++ ++static int krait_cache_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct krait_data *data; ++ struct opp_table *table; ++ struct dev_pm_opp *opp; ++ struct device *cpu_dev; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ table = dev_pm_opp_set_regulators(dev, (const char *[]){ "l2" }, 1); ++ if (IS_ERR(table)) { ++ ret = PTR_ERR(table); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to set regulators %d\n", ret); ++ ++ return ret; ++ } ++ ++ ret = PTR_ERR_OR_ZERO( ++ dev_pm_opp_register_set_opp_helper(dev, krait_cache_set_opp)); ++ if (ret) ++ return ret; ++ ++ ret = dev_pm_opp_of_add_table(dev); ++ if (ret) { ++ dev_err(dev, "failed to parse L2 freq thresholds\n"); ++ return ret; ++ } ++ ++ opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq); ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check opp-level configuration ++ * At least 2 level must be set or the cache will always be scaled ++ * the idle freq causing some performance problem ++ * ++ * In case of invalid configuration, the l2 scaling is skipped ++ */ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ /* ++ * Check if we have at least opp-level 1, 0 should always be set to ++ * the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of l2 opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check if we have at least opp-level 1 in the cpu opp, 0 should always ++ * be set to the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(cpu_dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of cpu opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ platform_set_drvdata(pdev, data); ++ ++ /* The l2 scaling is enabled by linking the cpufreq driver */ ++ l2_pdev = pdev; ++ ++ return 0; ++ ++invalid_conf: ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return -EINVAL; ++}; ++ ++static int krait_cache_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct opp_table *table = dev_pm_opp_get_opp_table(dev); ++ ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return 0; ++}; ++ ++static const struct of_device_id krait_cache_match_table[] = { ++ { .compatible = "qcom,krait-cache" }, ++ {} ++}; ++ ++static struct platform_driver krait_cache_driver = { ++ .driver = { ++ .name = "krait-cache", ++ .of_match_table = krait_cache_match_table, ++ }, ++ .probe = krait_cache_probe, ++ .remove = krait_cache_remove, ++}; ++module_platform_driver(krait_cache_driver); ++ ++static int krait_cpufreq_probe(struct platform_device *pdev) ++{ ++ struct cpufreq_dt_platform_data *data = dev_get_platdata(&pdev->dev); ++ int ret; ++ ++ /* ++ * All per-cluster (CPUs sharing clock/voltages) initialization is done ++ * from ->init(). In probe(), we just need to make sure that clk and ++ * regulators are available. Else defer probe and retry. ++ * ++ * FIXME: Is checking this only for CPU0 sufficient ? ++ */ ++ ret = resources_available(); ++ if (ret) ++ return ret; ++ ++ if (data) { ++ if (data->have_governor_per_policy) ++ krait_cpufreq_driver.flags |= ++ CPUFREQ_HAVE_GOVERNOR_PER_POLICY; ++ ++ krait_cpufreq_driver.resume = data->resume; ++ if (data->suspend) ++ krait_cpufreq_driver.suspend = data->suspend; ++ } ++ ++ ret = cpufreq_register_driver(&krait_cpufreq_driver); ++ if (ret) ++ dev_err(&pdev->dev, "failed register driver: %d\n", ret); ++ ++ return ret; ++} ++ ++static int krait_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&krait_cpufreq_driver); ++ return 0; ++} ++ ++static struct platform_driver krait_cpufreq_platdrv = { ++ .driver = { ++ .name = "krait-cpufreq", ++ }, ++ .probe = krait_cpufreq_probe, ++ .remove = krait_cpufreq_remove, ++}; ++module_platform_driver(krait_cpufreq_platdrv); ++ ++MODULE_ALIAS("platform:krait-cpufreq"); ++MODULE_AUTHOR("Ansuel Smith "); ++MODULE_DESCRIPTION("Dedicated Krait SoC cpufreq driver"); ++MODULE_LICENSE("GPL"); diff --git a/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch b/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch new file mode 100644 index 0000000..316e18b --- /dev/null +++ b/ipq806x/patches-5.10/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch @@ -0,0 +1,237 @@ +From c9ecd920324a647bf1f2b47f771c8f599cc7b551 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 18:02:17 +0100 +Subject: [PATCH 2/8] Documentation: cpufreq: add qcom,krait-cache bindings + +Document dedicated cpufreq for Krait CPUs. + +Signed-off-by: Ansuel Smith +--- + .../bindings/cpufreq/qcom-cpufreq-krait.yaml | 221 ++++++++++++++++++ + 1 file changed, 221 insertions(+) + create mode 100644 Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml +@@ -0,0 +1,221 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/cpufreq/qcom-cpufreq-krait.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: CPU Frequency scaling driver for Krait SoCs ++ ++maintainers: ++ - Ansuel Smith ++ ++description: | ++ The krait cpufreq driver is a dedicated frequency scaling driver ++ based on cpufreq-dt generic driver that scale L2 cache and the ++ cores. TEST ++ ++ The L2 cache is scaled based on the max clk across all cores and ++ the clock is decided based on the opp-level set in the device tree. ++ ++ Different core freq can be linked to a specific l2 freq and the driver ++ on frequency change will scale the core and the l2 clk based of the ++ linked freq. ++ ++ On Krait SoC is present a bug and on every L2 clk change the driver ++ needs to set the clk to the idle freq before changing it to the new value. ++ ++ This requires the qcom cpufreq nvmem driver to parse the different opp ++ core clk and an additional opp table for the l2 scaling. ++ ++ If the driver detect broken config (for example missing opp-level) the ++ cpufreq driver skips the l2 scaling ++ ++ Referring to this example opp-level can be used to link a range of cpu freq ++ to a specific l2 freq: ++ cpu opp freq 384000000 has opp-level 0 ++ l2 opp freq 384000000 has opp-level 0 ++ The driver will scale l2 to 384000000 ++ ++ cpu opp freq 600000000-1000000000 has opp-level 1 ++ l2 opp freq 1000000000 has opp-level 1 ++ The driver will scale l2 to 1000000000 ++ ++allOf: ++ - $ref: /schemas/cache-controller.yaml# ++ ++select: ++ properties: ++ compatible: ++ items: ++ - enum: ++ - qcom,krait-cache ++ ++ required: ++ - compatible ++ ++properties: ++ compatible: ++ items: ++ - const: qcom,krait-cache ++ - const: cache ++ ++ cache-level: ++ const: 2 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ const: l2 ++ ++ l2-supply: true ++ ++ operating-points-v2: true ++ ++required: ++ - compatible ++ - cache-level ++ - clocks ++ - clock-names ++ - l2-supply ++ - operating-points-v2 ++ ++additionalProperties: false ++ ++examples: ++ - | ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "qcom,krait"; ++ enable-method = "qcom,kpss-acc-v1"; ++ device_type = "cpu"; ++ reg = <0>; ++ next-level-cache = <&L2>; ++ qcom,acc = <&acc0>; ++ qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2a>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; ++ }; ++ ++ /* ... */ ++ ++ }; ++ ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1000000>; ++ opp-microvolt-speed0-pvs1-v0 = <925000>; ++ opp-microvolt-speed0-pvs2-v0 = <875000>; ++ opp-microvolt-speed0-pvs3-v0 = <800000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <975000>; ++ opp-microvolt-speed0-pvs2-v0 = <925000>; ++ opp-microvolt-speed0-pvs3-v0 = <850000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1100000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000>; ++ opp-microvolt-speed0-pvs2-v0 = <995000>; ++ opp-microvolt-speed0-pvs3-v0 = <900000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1150000>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000>; ++ opp-microvolt-speed0-pvs3-v0 = <950000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1200000>; ++ opp-microvolt-speed0-pvs1-v0 = <1125000>; ++ opp-microvolt-speed0-pvs2-v0 = <1075000>; ++ opp-microvolt-speed0-pvs3-v0 = <1000000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1250000>; ++ opp-microvolt-speed0-pvs1-v0 = <1175000>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000>; ++ opp-microvolt-speed0-pvs3-v0 = <1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ soc { ++ L2: l2-cache { ++ compatible = "qcom,krait-cache", "cache"; ++ cache-level = <2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ l2-supply = <&smb208_s1a>; ++ operating-points-v2 = <&opp_table_l2>; ++ }; ++ }; ++ ++... diff --git a/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch b/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch new file mode 100644 index 0000000..8ce3f06 --- /dev/null +++ b/ipq806x/patches-5.10/098-3-add-fab-scaling-support-with-cpufreq.patch @@ -0,0 +1,243 @@ +--- a/drivers/clk/qcom/Makefile ++++ b/drivers/clk/qcom/Makefile +@@ -15,6 +15,7 @@ clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-k + clk-qcom-y += clk-hfpll.o + clk-qcom-y += reset.o + clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o ++clk-qcom-y += fab_scaling.o + + # Keep alphabetically sorted by config + obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o +--- /dev/null ++++ b/drivers/clk/qcom/fab_scaling.c +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct qcom_fab_scaling_data { ++ u32 fab_freq_high; ++ u32 fab_freq_nominal; ++ u32 cpu_freq_threshold; ++ struct clk *apps_fab_clk; ++ struct clk *ddr_fab_clk; ++}; ++ ++static struct qcom_fab_scaling_data *drv_data; ++ ++int scale_fabrics(unsigned long max_cpu_freq) ++{ ++ struct clk *apps_fab_clk = drv_data->apps_fab_clk, ++ *ddr_fab_clk = drv_data->ddr_fab_clk; ++ unsigned long target_freq, cur_freq; ++ int ret; ++ ++ /* Skip fab scaling if the driver is not ready */ ++ if (!apps_fab_clk || !ddr_fab_clk) ++ return 0; ++ ++ if (max_cpu_freq > drv_data->cpu_freq_threshold) ++ target_freq = drv_data->fab_freq_high; ++ else ++ target_freq = drv_data->fab_freq_nominal; ++ ++ cur_freq = clk_get_rate(ddr_fab_clk); ++ ++ if (target_freq != cur_freq) { ++ ret = clk_set_rate(apps_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ ret = clk_set_rate(ddr_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(scale_fabrics); ++ ++static int ipq806x_fab_scaling_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct clk *apps_fab_clk, *ddr_fab_clk; ++ int ret; ++ ++ if (!np) ++ return -ENODEV; ++ ++ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); ++ if (!drv_data) ++ return -ENOMEM; ++ ++ if (of_property_read_u32(np, "fab_freq_high", &drv_data->fab_freq_high)) { ++ pr_err("FABRICS turbo freq not found. Using defaults...\n"); ++ drv_data->fab_freq_high = 533000000; ++ } ++ ++ if (of_property_read_u32(np, "fab_freq_nominal", &drv_data->fab_freq_nominal)) { ++ pr_err("FABRICS nominal freq not found. Using defaults...\n"); ++ drv_data->fab_freq_nominal = 400000000; ++ } ++ ++ if (of_property_read_u32(np, "cpu_freq_threshold", &drv_data->cpu_freq_threshold)) { ++ pr_err("FABRICS cpu freq threshold not found. Using defaults...\n"); ++ drv_data->cpu_freq_threshold = 1000000000; ++ } ++ ++ apps_fab_clk = devm_clk_get(&pdev->dev, "apps-fab-clk"); ++ ret = PTR_ERR_OR_ZERO(apps_fab_clk); ++ if (ret) { ++ /* ++ * If apps fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get APPS FABRIC clock: %d\n", ret); ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_prepare_enable(apps_fab_clk); ++ clk_set_rate(apps_fab_clk, drv_data->fab_freq_high); ++ drv_data->apps_fab_clk = apps_fab_clk; ++ ++ ddr_fab_clk = devm_clk_get(&pdev->dev, "ddr-fab-clk"); ++ ret = PTR_ERR_OR_ZERO(ddr_fab_clk); ++ if (ret) { ++ /* ++ * If ddr fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get DDR FABRIC clock: %d\n", ret); ++ ddr_fab_clk = NULL; ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_prepare_enable(ddr_fab_clk); ++ clk_set_rate(ddr_fab_clk, drv_data->fab_freq_high); ++ drv_data->ddr_fab_clk = ddr_fab_clk; ++ ++ return 0; ++err: ++ kfree(drv_data); ++ return ret; ++} ++ ++static int ipq806x_fab_scaling_remove(struct platform_device *pdev) ++{ ++ kfree(drv_data); ++ return 0; ++} ++ ++static const struct of_device_id fab_scaling_ipq806x_match_table[] = { ++ { .compatible = "qcom,fab-scaling" }, ++ { } ++}; ++ ++static struct platform_driver fab_scaling_ipq806x_driver = { ++ .probe = ipq806x_fab_scaling_probe, ++ .remove = ipq806x_fab_scaling_remove, ++ .driver = { ++ .name = "fab-scaling", ++ .of_match_table = fab_scaling_ipq806x_match_table, ++ }, ++}; ++ ++static int __init fab_scaling_ipq806x_init(void) ++{ ++ return platform_driver_register(&fab_scaling_ipq806x_driver); ++} ++late_initcall(fab_scaling_ipq806x_init); ++ ++static void __exit fab_scaling_ipq806x_exit(void) ++{ ++ platform_driver_unregister(&fab_scaling_ipq806x_driver); ++} ++module_exit(fab_scaling_ipq806x_exit); +--- /dev/null ++++ b/include/linux/fab_scaling.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++ ++#ifndef __FAB_SCALING_H ++#define __FAB_SCALING_H ++ ++/** ++ * scale_fabrics - Scale DDR and APPS FABRICS ++ * ++ * This function monitors all the registered clocks and does APPS ++ * and DDR FABRIC scaling based on the idle frequencies with which ++ * it was registered. ++ * ++ */ ++int scale_fabrics(unsigned long max_cpu_freq); ++ ++#endif +--- a/drivers/cpufreq/qcom-cpufreq-krait.c ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include "cpufreq-dt.h" + +@@ -68,6 +69,13 @@ static int set_target(struct cpufreq_pol + return -EINVAL; + } + ++ /* ++ * Scale fabrics with max freq across all cores ++ */ ++ ret = scale_fabrics(target_freq); ++ if (ret) ++ return ret; ++ + opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); + if (IS_ERR(opp)) { + dev_err(&l2_pdev->dev, diff --git a/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch b/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch new file mode 100644 index 0000000..6106dfb --- /dev/null +++ b/ipq806x/patches-5.10/099-1-mtd-nand-raw-qcom_nandc-add-boot_layout_mode-support.patch @@ -0,0 +1,239 @@ +From 6949d651e3be3ebbfedb6bbd5b541cfda6ee58a9 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 10 Feb 2021 10:40:17 +0100 +Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: add boot_layout_mode support + +ipq806x nand have a special ecc configuration for the boot pages. The +use of the non-boot pages configuration on boot pages cause I/O error +and can cause broken data written to the nand. Add support for this +special configuration if the page to be read/write is in the size of the +boot pages set by the dts. + +Signed-off-by: Ansuel Smith +--- + drivers/mtd/nand/raw/qcom_nandc.c | 82 +++++++++++++++++++++++++++++-- + 1 file changed, 77 insertions(+), 5 deletions(-) + +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -159,6 +159,11 @@ + /* NAND_CTRL bits */ + #define BAM_MODE_EN BIT(0) + ++ ++#define UD_SIZE_BYTES_MASK (0x3ff << UD_SIZE_BYTES) ++#define SPARE_SIZE_BYTES_MASK (0xf << SPARE_SIZE_BYTES) ++#define ECC_NUM_DATA_BYTES_MASK (0x3ff << ECC_NUM_DATA_BYTES) ++ + /* + * the NAND controller performs reads/writes with ECC in 516 byte chunks. + * the driver calls the chunks 'step' or 'codeword' interchangeably +@@ -430,6 +435,13 @@ struct qcom_nand_controller { + * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for + * ecc/non-ecc mode for the current nand flash + * device ++ * ++ * @boot_pages_conf: keep track of the current ecc configuration used by ++ * the driver for read/write operation. (boot pages ++ * have different configuration than normal page) ++ * @boot_pages: number of pages starting from 0 used as boot pages ++ * where the driver will use the boot pages ecc ++ * configuration for read/write operation + */ + struct qcom_nand_host { + struct nand_chip chip; +@@ -452,6 +464,9 @@ struct qcom_nand_host { + u32 ecc_bch_cfg; + u32 clrflashstatus; + u32 clrreadstatus; ++ ++ bool boot_pages_conf; ++ u32 boot_pages; + }; + + /* +@@ -460,12 +475,14 @@ struct qcom_nand_host { + * @ecc_modes - ecc mode for NAND + * @is_bam - whether NAND controller is using BAM + * @is_qpic - whether NAND CTRL is part of qpic IP ++ * @has_boot_pages - whether NAND has different ecc settings for boot pages + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset + */ + struct qcom_nandc_props { + u32 ecc_modes; + bool is_bam; + bool is_qpic; ++ bool has_boot_pages; + u32 dev_cmd_reg_start; + }; + +@@ -1604,7 +1621,7 @@ qcom_nandc_read_cw_raw(struct mtd_info * + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); + oob_size1 = host->bbm_size; + +- if (cw == (ecc->steps - 1)) { ++ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size2 = ecc->size - data_size1 - + ((ecc->steps - 1) * 4); + oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + +@@ -1685,7 +1702,7 @@ check_for_erased_page(struct qcom_nand_h + } + + for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { +- if (cw == (ecc->steps - 1)) { ++ if (cw == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size = ecc->size - ((ecc->steps - 1) * 4); + oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; + } else { +@@ -1844,7 +1861,7 @@ static int read_page_ecc(struct qcom_nan + for (i = 0; i < ecc->steps; i++) { + int data_size, oob_size; + +- if (i == (ecc->steps - 1)) { ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size = ecc->size - ((ecc->steps - 1) << 2); + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + + host->spare_bytes; +@@ -1941,6 +1958,30 @@ static int copy_last_cw(struct qcom_nand + return ret; + } + ++static void ++check_boot_pages_conf(struct qcom_nand_host *host, int page) ++{ ++ bool boot_pages_conf = page < host->boot_pages; ++ ++ /* Skip conf write if we are already in the correct mode */ ++ if (boot_pages_conf != host->boot_pages_conf) { ++ host->boot_pages_conf = boot_pages_conf; ++ ++ host->cw_data = boot_pages_conf ? 512 : 516; ++ host->spare_bytes = host->cw_size - host->ecc_bytes_hw - ++ host->bbm_size - host->cw_data; ++ ++ host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK); ++ host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES | ++ host->cw_data << UD_SIZE_BYTES; ++ ++ host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK; ++ host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES; ++ host->ecc_buf_cfg = (boot_pages_conf ? 0x1ff : 0x203) << ++ NUM_STEPS; ++ } ++} ++ + /* implements ecc->read_page() */ + static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +@@ -1949,6 +1990,9 @@ static int qcom_nandc_read_page(struct n + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + u8 *data_buf, *oob_buf = NULL; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + nand_read_page_op(chip, page, 0, NULL, 0); + data_buf = buf; + oob_buf = oob_required ? chip->oob_poi : NULL; +@@ -1968,6 +2012,9 @@ static int qcom_nandc_read_page_raw(stru + int cw, ret; + u8 *data_buf = buf, *oob_buf = chip->oob_poi; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + for (cw = 0; cw < ecc->steps; cw++) { + ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, + page, cw); +@@ -1988,6 +2035,9 @@ static int qcom_nandc_read_oob(struct na + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + clear_read_regs(nandc); + clear_bam_transaction(nandc); + +@@ -2008,6 +2058,9 @@ static int qcom_nandc_write_page(struct + u8 *data_buf, *oob_buf; + int i, ret; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + + clear_read_regs(nandc); +@@ -2023,7 +2076,7 @@ static int qcom_nandc_write_page(struct + for (i = 0; i < ecc->steps; i++) { + int data_size, oob_size; + +- if (i == (ecc->steps - 1)) { ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size = ecc->size - ((ecc->steps - 1) << 2); + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + + host->spare_bytes; +@@ -2080,6 +2133,9 @@ static int qcom_nandc_write_page_raw(str + u8 *data_buf, *oob_buf; + int i, ret; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + clear_read_regs(nandc); + clear_bam_transaction(nandc); +@@ -2098,7 +2154,7 @@ static int qcom_nandc_write_page_raw(str + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); + oob_size1 = host->bbm_size; + +- if (i == (ecc->steps - 1)) { ++ if (i == (ecc->steps - 1) && !host->boot_pages_conf) { + data_size2 = ecc->size - data_size1 - + ((ecc->steps - 1) << 2); + oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + +@@ -2158,6 +2214,9 @@ static int qcom_nandc_write_oob(struct n + int data_size, oob_size; + int ret; + ++ if (host->boot_pages) ++ check_boot_pages_conf(host, page); ++ + host->use_ecc = true; + clear_bam_transaction(nandc); + +@@ -2806,6 +2865,7 @@ static int qcom_nand_host_init_and_regis + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + struct device *dev = nandc->dev; ++ u32 boot_pages_size; + int ret; + + ret = of_property_read_u32(dn, "reg", &host->cs); +@@ -2866,6 +2926,17 @@ static int qcom_nand_host_init_and_regis + if (ret) + nand_cleanup(chip); + ++ if (nandc->props->has_boot_pages && ++ of_property_read_bool(dn, "nand-is-boot-medium")) { ++ ret = of_property_read_u32(dn, "qcom,boot_pages_size", ++ &boot_pages_size); ++ if (ret) ++ dev_warn(dev, "can't get boot pages size"); ++ else ++ /* Convert size to nand pages */ ++ host->boot_pages = boot_pages_size / mtd->writesize; ++ } ++ + return ret; + } + +@@ -3032,6 +3103,7 @@ static int qcom_nandc_remove(struct plat + static const struct qcom_nandc_props ipq806x_nandc_props = { + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), + .is_bam = false, ++ .has_boot_pages = true, + .dev_cmd_reg_start = 0x0, + }; + diff --git a/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch b/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch new file mode 100644 index 0000000..79036cb --- /dev/null +++ b/ipq806x/patches-5.10/099-2-Documentation-devicetree-mtd-qcom_nandc-document-qco.patch @@ -0,0 +1,42 @@ +From 6fb003a7a117f97a35b078ba726c84adeae29c4c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 10 Feb 2021 10:54:19 +0100 +Subject: [PATCH 2/2] Documentation: devicetree: mtd: qcom_nandc: document + qcom,boot_layout_size binding + +Document new qcom,boot_layout_size binding used to apply special +read/write confituation to boots partitions. + +Signed-off-by: Ansuel Smith +--- + Documentation/devicetree/bindings/mtd/qcom_nandc.txt | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt ++++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt +@@ -52,6 +52,15 @@ Optional properties: + be used according to chip requirement and available + OOB size. + ++EBI2 specific properties: ++- nand-is-boot-medium: nand contains boot partitions and different ecc configuration ++ should be used for these partitions. ++- qcom,boot_pages_size: should contain the size of the total boot partitions ++ where the boot layout read/write specific configuration ++ should be used. The boot layout is considered from the ++ start of the nand to the value set in this binding. ++ Only used in combination with 'nand-is-boot-medium'. ++ + Each nandcs device node may optionally contain a 'partitions' sub-node, which + further contains sub-nodes describing the flash partition mapping. See + partition.txt for more detail. +@@ -80,6 +89,9 @@ nand-controller@1ac00000 { + nand-ecc-strength = <4>; + nand-bus-width = <8>; + ++ nand-is-boot-medium; ++ qcom,boot_pages_size: <0x58a0000>; ++ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; diff --git a/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch b/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch new file mode 100644 index 0000000..2d24da0 --- /dev/null +++ b/ipq806x/patches-5.10/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -0,0 +1,965 @@ +From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001 +From: Jonathan McDowell +Date: Sat, 14 Nov 2020 14:02:33 +0000 +Subject: dmaengine: qcom: Add ADM driver + +Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA +controller found in the MSM8x60 and IPQ/APQ8064 platforms. + +The ADM supports both memory to memory transactions and memory +to/from peripheral device transactions. The controller also provides +flow control capabilities for transactions to/from peripheral devices. + +The initial release of this driver supports slave transfers to/from +peripherals and also incorporates CRCI (client rate control interface) +flow control. + +The hardware only supports a 32 bit physical address, so specifying +!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to +spend effort on kludging things in the code that will never actually be +needed on real hardware. + +Signed-off-by: Andy Gross +Signed-off-by: Thomas Pedersen +Signed-off-by: Jonathan McDowell +Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li +Signed-off-by: Vinod Koul +--- + drivers/dma/qcom/Kconfig | 11 + + drivers/dma/qcom/Makefile | 1 + + drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 915 insertions(+) + create mode 100644 drivers/dma/qcom/qcom_adm.c + +--- a/drivers/dma/qcom/Kconfig ++++ b/drivers/dma/qcom/Kconfig +@@ -1,4 +1,15 @@ + # SPDX-License-Identifier: GPL-2.0-only ++config QCOM_ADM ++ tristate "Qualcomm ADM support" ++ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT ++ select DMA_ENGINE ++ select DMA_VIRTUAL_CHANNELS ++ help ++ Enable support for the Qualcomm Application Data Mover (ADM) DMA ++ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. ++ This controller provides DMA capabilities for both general purpose ++ and on-chip peripheral devices. ++ + config QCOM_BAM_DMA + tristate "QCOM BAM DMA support" + depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) +--- a/drivers/dma/qcom/Makefile ++++ b/drivers/dma/qcom/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_QCOM_ADM) += qcom_adm.o + obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o + obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o + hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o +--- /dev/null ++++ b/drivers/dma/qcom/qcom_adm.c +@@ -0,0 +1,903 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../dmaengine.h" ++#include "../virt-dma.h" ++ ++/* ADM registers - calculated from channel number and security domain */ ++#define ADM_CHAN_MULTI 0x4 ++#define ADM_CI_MULTI 0x4 ++#define ADM_CRCI_MULTI 0x4 ++#define ADM_EE_MULTI 0x800 ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) ++#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) ++#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) ++#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) ++#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) ++#define ADM_GP_CTL 0x3d8 ++#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ ++ ADM_EE_OFFS(ee)) ++ ++/* channel status */ ++#define ADM_CH_STATUS_VALID BIT(1) ++ ++/* channel result */ ++#define ADM_CH_RSLT_VALID BIT(31) ++#define ADM_CH_RSLT_ERR BIT(3) ++#define ADM_CH_RSLT_FLUSH BIT(2) ++#define ADM_CH_RSLT_TPD BIT(1) ++ ++/* channel conf */ ++#define ADM_CH_CONF_SHADOW_EN BIT(12) ++#define ADM_CH_CONF_MPU_DISABLE BIT(11) ++#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) ++#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) ++#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) ++ ++/* channel result conf */ ++#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) ++#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) ++ ++/* CRCI CTL */ ++#define ADM_CRCI_CTL_MUX_SEL BIT(18) ++#define ADM_CRCI_CTL_RST BIT(17) ++ ++/* CI configuration */ ++#define ADM_CI_RANGE_END(x) ((x) << 24) ++#define ADM_CI_RANGE_START(x) ((x) << 16) ++#define ADM_CI_BURST_4_WORDS BIT(2) ++#define ADM_CI_BURST_8_WORDS BIT(3) ++ ++/* GP CTL */ ++#define ADM_GP_CTL_LP_EN BIT(12) ++#define ADM_GP_CTL_LP_CNT(x) ((x) << 8) ++ ++/* Command pointer list entry */ ++#define ADM_CPLE_LP BIT(31) ++#define ADM_CPLE_CMD_PTR_LIST BIT(29) ++ ++/* Command list entry */ ++#define ADM_CMD_LC BIT(31) ++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) ++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) ++ ++#define ADM_CMD_TYPE_SINGLE 0x0 ++#define ADM_CMD_TYPE_BOX 0x3 ++ ++#define ADM_CRCI_MUX_SEL BIT(4) ++#define ADM_DESC_ALIGN 8 ++#define ADM_MAX_XFER (SZ_64K - 1) ++#define ADM_MAX_ROWS (SZ_64K - 1) ++#define ADM_MAX_CHANNELS 16 ++ ++struct adm_desc_hw_box { ++ u32 cmd; ++ u32 src_addr; ++ u32 dst_addr; ++ u32 row_len; ++ u32 num_rows; ++ u32 row_offset; ++}; ++ ++struct adm_desc_hw_single { ++ u32 cmd; ++ u32 src_addr; ++ u32 dst_addr; ++ u32 len; ++}; ++ ++struct adm_async_desc { ++ struct virt_dma_desc vd; ++ struct adm_device *adev; ++ ++ size_t length; ++ enum dma_transfer_direction dir; ++ dma_addr_t dma_addr; ++ size_t dma_len; ++ ++ void *cpl; ++ dma_addr_t cp_addr; ++ u32 crci; ++ u32 mux; ++ u32 blk_size; ++}; ++ ++struct adm_chan { ++ struct virt_dma_chan vc; ++ struct adm_device *adev; ++ ++ /* parsed from DT */ ++ u32 id; /* channel id */ ++ ++ struct adm_async_desc *curr_txd; ++ struct dma_slave_config slave; ++ struct list_head node; ++ ++ int error; ++ int initialized; ++}; ++ ++static inline struct adm_chan *to_adm_chan(struct dma_chan *common) ++{ ++ return container_of(common, struct adm_chan, vc.chan); ++} ++ ++struct adm_device { ++ void __iomem *regs; ++ struct device *dev; ++ struct dma_device common; ++ struct device_dma_parameters dma_parms; ++ struct adm_chan *channels; ++ ++ u32 ee; ++ ++ struct clk *core_clk; ++ struct clk *iface_clk; ++ ++ struct reset_control *clk_reset; ++ struct reset_control *c0_reset; ++ struct reset_control *c1_reset; ++ struct reset_control *c2_reset; ++ int irq; ++}; ++ ++/** ++ * adm_free_chan - Frees dma resources associated with the specific channel ++ * ++ * Free all allocated descriptors associated with this channel ++ * ++ */ ++static void adm_free_chan(struct dma_chan *chan) ++{ ++ /* free all queued descriptors */ ++ vchan_free_chan_resources(to_virt_chan(chan)); ++} ++ ++/** ++ * adm_get_blksize - Get block size from burst value ++ * ++ */ ++static int adm_get_blksize(unsigned int burst) ++{ ++ int ret; ++ ++ switch (burst) { ++ case 16: ++ case 32: ++ case 64: ++ case 128: ++ ret = ffs(burst >> 4) - 1; ++ break; ++ case 192: ++ ret = 4; ++ break; ++ case 256: ++ ret = 5; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/** ++ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers ++ * ++ * @achan: ADM channel ++ * @desc: Descriptor memory pointer ++ * @sg: Scatterlist entry ++ * @crci: CRCI value ++ * @burst: Burst size of transaction ++ * @direction: DMA transfer direction ++ */ ++static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, u32 crci, ++ u32 burst, ++ enum dma_transfer_direction direction) ++{ ++ struct adm_desc_hw_box *box_desc = NULL; ++ struct adm_desc_hw_single *single_desc; ++ u32 remainder = sg_dma_len(sg); ++ u32 rows, row_offset, crci_cmd; ++ u32 mem_addr = sg_dma_address(sg); ++ u32 *incr_addr = &mem_addr; ++ u32 *src, *dst; ++ ++ if (direction == DMA_DEV_TO_MEM) { ++ crci_cmd = ADM_CMD_SRC_CRCI(crci); ++ row_offset = burst; ++ src = &achan->slave.src_addr; ++ dst = &mem_addr; ++ } else { ++ crci_cmd = ADM_CMD_DST_CRCI(crci); ++ row_offset = burst << 16; ++ src = &mem_addr; ++ dst = &achan->slave.dst_addr; ++ } ++ ++ while (remainder >= burst) { ++ box_desc = desc; ++ box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd; ++ box_desc->row_offset = row_offset; ++ box_desc->src_addr = *src; ++ box_desc->dst_addr = *dst; ++ ++ rows = remainder / burst; ++ rows = min_t(u32, rows, ADM_MAX_ROWS); ++ box_desc->num_rows = rows << 16 | rows; ++ box_desc->row_len = burst << 16 | burst; ++ ++ *incr_addr += burst * rows; ++ remainder -= burst * rows; ++ desc += sizeof(*box_desc); ++ } ++ ++ /* if leftover bytes, do one single descriptor */ ++ if (remainder) { ++ single_desc = desc; ++ single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd; ++ single_desc->len = remainder; ++ single_desc->src_addr = *src; ++ single_desc->dst_addr = *dst; ++ desc += sizeof(*single_desc); ++ ++ if (sg_is_last(sg)) ++ single_desc->cmd |= ADM_CMD_LC; ++ } else { ++ if (box_desc && sg_is_last(sg)) ++ box_desc->cmd |= ADM_CMD_LC; ++ } ++ ++ return desc; ++} ++ ++/** ++ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers ++ * ++ * @achan: ADM channel ++ * @desc: Descriptor memory pointer ++ * @sg: Scatterlist entry ++ * @direction: DMA transfer direction ++ */ ++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, ++ enum dma_transfer_direction direction) ++{ ++ struct adm_desc_hw_single *single_desc; ++ u32 remainder = sg_dma_len(sg); ++ u32 mem_addr = sg_dma_address(sg); ++ u32 *incr_addr = &mem_addr; ++ u32 *src, *dst; ++ ++ if (direction == DMA_DEV_TO_MEM) { ++ src = &achan->slave.src_addr; ++ dst = &mem_addr; ++ } else { ++ src = &mem_addr; ++ dst = &achan->slave.dst_addr; ++ } ++ ++ do { ++ single_desc = desc; ++ single_desc->cmd = ADM_CMD_TYPE_SINGLE; ++ single_desc->src_addr = *src; ++ single_desc->dst_addr = *dst; ++ single_desc->len = (remainder > ADM_MAX_XFER) ? ++ ADM_MAX_XFER : remainder; ++ ++ remainder -= single_desc->len; ++ *incr_addr += single_desc->len; ++ desc += sizeof(*single_desc); ++ } while (remainder); ++ ++ /* set last command if this is the end of the whole transaction */ ++ if (sg_is_last(sg)) ++ single_desc->cmd |= ADM_CMD_LC; ++ ++ return desc; ++} ++ ++/** ++ * adm_prep_slave_sg - Prep slave sg transaction ++ * ++ * @chan: dma channel ++ * @sgl: scatter gather list ++ * @sg_len: length of sg ++ * @direction: DMA transfer direction ++ * @flags: DMA flags ++ * @context: transfer context (unused) ++ */ ++static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, ++ struct scatterlist *sgl, ++ unsigned int sg_len, ++ enum dma_transfer_direction direction, ++ unsigned long flags, ++ void *context) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct adm_device *adev = achan->adev; ++ struct adm_async_desc *async_desc; ++ struct scatterlist *sg; ++ dma_addr_t cple_addr; ++ u32 i, burst; ++ u32 single_count = 0, box_count = 0, crci = 0; ++ void *desc; ++ u32 *cple; ++ int blk_size = 0; ++ ++ if (!is_slave_direction(direction)) { ++ dev_err(adev->dev, "invalid dma direction\n"); ++ return NULL; ++ } ++ ++ /* ++ * get burst value from slave configuration ++ */ ++ burst = (direction == DMA_MEM_TO_DEV) ? ++ achan->slave.dst_maxburst : ++ achan->slave.src_maxburst; ++ ++ /* if using flow control, validate burst and crci values */ ++ if (achan->slave.device_fc) { ++ blk_size = adm_get_blksize(burst); ++ if (blk_size < 0) { ++ dev_err(adev->dev, "invalid burst value: %d\n", ++ burst); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ crci = achan->slave.slave_id & 0xf; ++ if (!crci || achan->slave.slave_id > 0x1f) { ++ dev_err(adev->dev, "invalid crci value\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ ++ /* iterate through sgs and compute allocation size of structures */ ++ for_each_sg(sgl, sg, sg_len, i) { ++ if (achan->slave.device_fc) { ++ box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst, ++ ADM_MAX_ROWS); ++ if (sg_dma_len(sg) % burst) ++ single_count++; ++ } else { ++ single_count += DIV_ROUND_UP(sg_dma_len(sg), ++ ADM_MAX_XFER); ++ } ++ } ++ ++ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); ++ if (!async_desc) ++ return ERR_PTR(-ENOMEM); ++ ++ if (crci) ++ async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ? ++ ADM_CRCI_CTL_MUX_SEL : 0; ++ async_desc->crci = crci; ++ async_desc->blk_size = blk_size; ++ async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) + ++ box_count * sizeof(struct adm_desc_hw_box) + ++ sizeof(*cple) + 2 * ADM_DESC_ALIGN; ++ ++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); ++ if (!async_desc->cpl) ++ goto free; ++ ++ async_desc->adev = adev; ++ ++ /* both command list entry and descriptors must be 8 byte aligned */ ++ cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN); ++ desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN); ++ ++ for_each_sg(sgl, sg, sg_len, i) { ++ async_desc->length += sg_dma_len(sg); ++ ++ if (achan->slave.device_fc) ++ desc = adm_process_fc_descriptors(achan, desc, sg, crci, ++ burst, direction); ++ else ++ desc = adm_process_non_fc_descriptors(achan, desc, sg, ++ direction); ++ } ++ ++ async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, ++ async_desc->dma_len, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(adev->dev, async_desc->dma_addr)) ++ goto free; ++ ++ cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl); ++ ++ /* init cmd list */ ++ dma_sync_single_for_cpu(adev->dev, cple_addr, sizeof(*cple), ++ DMA_TO_DEVICE); ++ *cple = ADM_CPLE_LP; ++ *cple |= (async_desc->dma_addr + ADM_DESC_ALIGN) >> 3; ++ dma_sync_single_for_device(adev->dev, cple_addr, sizeof(*cple), ++ DMA_TO_DEVICE); ++ ++ return vchan_tx_prep(&achan->vc, &async_desc->vd, flags); ++ ++free: ++ kfree(async_desc); ++ return ERR_PTR(-ENOMEM); ++} ++ ++/** ++ * adm_terminate_all - terminate all transactions on a channel ++ * @achan: adm dma channel ++ * ++ * Dequeues and frees all transactions, aborts current transaction ++ * No callbacks are done ++ * ++ */ ++static int adm_terminate_all(struct dma_chan *chan) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct adm_device *adev = achan->adev; ++ unsigned long flags; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ vchan_get_all_descriptors(&achan->vc, &head); ++ ++ /* send flush command to terminate current transaction */ ++ writel_relaxed(0x0, ++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ ++ vchan_dma_desc_free_list(&achan->vc, &head); ++ ++ return 0; ++} ++ ++static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ unsigned long flag; ++ ++ spin_lock_irqsave(&achan->vc.lock, flag); ++ memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); ++ spin_unlock_irqrestore(&achan->vc.lock, flag); ++ ++ return 0; ++} ++ ++/** ++ * adm_start_dma - start next transaction ++ * @achan - ADM dma channel ++ */ ++static void adm_start_dma(struct adm_chan *achan) ++{ ++ struct virt_dma_desc *vd = vchan_next_desc(&achan->vc); ++ struct adm_device *adev = achan->adev; ++ struct adm_async_desc *async_desc; ++ ++ lockdep_assert_held(&achan->vc.lock); ++ ++ if (!vd) ++ return; ++ ++ list_del(&vd->node); ++ ++ /* write next command list out to the CMD FIFO */ ++ async_desc = container_of(vd, struct adm_async_desc, vd); ++ achan->curr_txd = async_desc; ++ ++ /* reset channel error */ ++ achan->error = 0; ++ ++ if (!achan->initialized) { ++ /* enable interrupts */ ++ writel(ADM_CH_CONF_SHADOW_EN | ++ ADM_CH_CONF_PERM_MPU_CONF | ++ ADM_CH_CONF_MPU_DISABLE | ++ ADM_CH_CONF_SEC_DOMAIN(adev->ee), ++ adev->regs + ADM_CH_CONF(achan->id)); ++ ++ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, ++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ ++ achan->initialized = 1; ++ } ++ ++ /* set the crci block size if this transaction requires CRCI */ ++ if (async_desc->crci) { ++ writel(async_desc->mux | async_desc->blk_size, ++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); ++ } ++ ++ /* make sure IRQ enable doesn't get reordered */ ++ wmb(); ++ ++ /* write next command list out to the CMD FIFO */ ++ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, ++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); ++} ++ ++/** ++ * adm_dma_irq - irq handler for ADM controller ++ * @irq: IRQ of interrupt ++ * @data: callback data ++ * ++ * IRQ handler for the bam controller ++ */ ++static irqreturn_t adm_dma_irq(int irq, void *data) ++{ ++ struct adm_device *adev = data; ++ u32 srcs, i; ++ struct adm_async_desc *async_desc; ++ unsigned long flags; ++ ++ srcs = readl_relaxed(adev->regs + ++ ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee)); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) { ++ struct adm_chan *achan = &adev->channels[i]; ++ u32 status, result; ++ ++ if (srcs & BIT(i)) { ++ status = readl_relaxed(adev->regs + ++ ADM_CH_STATUS_SD(i, adev->ee)); ++ ++ /* if no result present, skip */ ++ if (!(status & ADM_CH_STATUS_VALID)) ++ continue; ++ ++ result = readl_relaxed(adev->regs + ++ ADM_CH_RSLT(i, adev->ee)); ++ ++ /* no valid results, skip */ ++ if (!(result & ADM_CH_RSLT_VALID)) ++ continue; ++ ++ /* flag error if transaction was flushed or failed */ ++ if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH)) ++ achan->error = 1; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ async_desc = achan->curr_txd; ++ ++ achan->curr_txd = NULL; ++ ++ if (async_desc) { ++ vchan_cookie_complete(&async_desc->vd); ++ ++ /* kick off next DMA */ ++ adm_start_dma(achan); ++ } ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * adm_tx_status - returns status of transaction ++ * @chan: dma channel ++ * @cookie: transaction cookie ++ * @txstate: DMA transaction state ++ * ++ * Return status of dma transaction ++ */ ++static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct virt_dma_desc *vd; ++ enum dma_status ret; ++ unsigned long flags; ++ size_t residue = 0; ++ ++ ret = dma_cookie_status(chan, cookie, txstate); ++ if (ret == DMA_COMPLETE || !txstate) ++ return ret; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ ++ vd = vchan_find_desc(&achan->vc, cookie); ++ if (vd) ++ residue = container_of(vd, struct adm_async_desc, vd)->length; ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ ++ /* ++ * residue is either the full length if it is in the issued list, or 0 ++ * if it is in progress. We have no reliable way of determining ++ * anything inbetween ++ */ ++ dma_set_residue(txstate, residue); ++ ++ if (achan->error) ++ return DMA_ERROR; ++ ++ return ret; ++} ++ ++/** ++ * adm_issue_pending - starts pending transactions ++ * @chan: dma channel ++ * ++ * Issues all pending transactions and starts DMA ++ */ ++static void adm_issue_pending(struct dma_chan *chan) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ ++ if (vchan_issue_pending(&achan->vc) && !achan->curr_txd) ++ adm_start_dma(achan); ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++} ++ ++/** ++ * adm_dma_free_desc - free descriptor memory ++ * @vd: virtual descriptor ++ * ++ */ ++static void adm_dma_free_desc(struct virt_dma_desc *vd) ++{ ++ struct adm_async_desc *async_desc = container_of(vd, ++ struct adm_async_desc, vd); ++ ++ dma_unmap_single(async_desc->adev->dev, async_desc->dma_addr, ++ async_desc->dma_len, DMA_TO_DEVICE); ++ kfree(async_desc->cpl); ++ kfree(async_desc); ++} ++ ++static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, ++ u32 index) ++{ ++ achan->id = index; ++ achan->adev = adev; ++ ++ vchan_init(&achan->vc, &adev->common); ++ achan->vc.desc_free = adm_dma_free_desc; ++} ++ ++static int adm_dma_probe(struct platform_device *pdev) ++{ ++ struct adm_device *adev; ++ int ret; ++ u32 i; ++ ++ adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL); ++ if (!adev) ++ return -ENOMEM; ++ ++ adev->dev = &pdev->dev; ++ ++ adev->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(adev->regs)) ++ return PTR_ERR(adev->regs); ++ ++ adev->irq = platform_get_irq(pdev, 0); ++ if (adev->irq < 0) ++ return adev->irq; ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee); ++ if (ret) { ++ dev_err(adev->dev, "Execution environment unspecified\n"); ++ return ret; ++ } ++ ++ adev->core_clk = devm_clk_get(adev->dev, "core"); ++ if (IS_ERR(adev->core_clk)) ++ return PTR_ERR(adev->core_clk); ++ ++ adev->iface_clk = devm_clk_get(adev->dev, "iface"); ++ if (IS_ERR(adev->iface_clk)) ++ return PTR_ERR(adev->iface_clk); ++ ++ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); ++ if (IS_ERR(adev->clk_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 reset\n"); ++ return PTR_ERR(adev->clk_reset); ++ } ++ ++ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); ++ if (IS_ERR(adev->c0_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); ++ return PTR_ERR(adev->c0_reset); ++ } ++ ++ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); ++ if (IS_ERR(adev->c1_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); ++ return PTR_ERR(adev->c1_reset); ++ } ++ ++ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); ++ if (IS_ERR(adev->c2_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); ++ return PTR_ERR(adev->c2_reset); ++ } ++ ++ ret = clk_prepare_enable(adev->core_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable core clock\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(adev->iface_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); ++ goto err_disable_core_clk; ++ } ++ ++ reset_control_assert(adev->clk_reset); ++ reset_control_assert(adev->c0_reset); ++ reset_control_assert(adev->c1_reset); ++ reset_control_assert(adev->c2_reset); ++ ++ udelay(2); ++ ++ reset_control_deassert(adev->clk_reset); ++ reset_control_deassert(adev->c0_reset); ++ reset_control_deassert(adev->c1_reset); ++ reset_control_deassert(adev->c2_reset); ++ ++ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, ++ sizeof(*adev->channels), GFP_KERNEL); ++ ++ if (!adev->channels) { ++ ret = -ENOMEM; ++ goto err_disable_clks; ++ } ++ ++ /* allocate and initialize channels */ ++ INIT_LIST_HEAD(&adev->common.channels); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) ++ adm_channel_init(adev, &adev->channels[i], i); ++ ++ /* reset CRCIs */ ++ for (i = 0; i < 16; i++) ++ writel(ADM_CRCI_CTL_RST, adev->regs + ++ ADM_CRCI_CTL(i, adev->ee)); ++ ++ /* configure client interfaces */ ++ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); ++ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); ++ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); ++ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), ++ adev->regs + ADM_GP_CTL); ++ ++ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, ++ 0, "adm_dma", adev); ++ if (ret) ++ goto err_disable_clks; ++ ++ platform_set_drvdata(pdev, adev); ++ ++ adev->common.dev = adev->dev; ++ adev->common.dev->dma_parms = &adev->dma_parms; ++ ++ /* set capabilities */ ++ dma_cap_zero(adev->common.cap_mask); ++ dma_cap_set(DMA_SLAVE, adev->common.cap_mask); ++ dma_cap_set(DMA_PRIVATE, adev->common.cap_mask); ++ ++ /* initialize dmaengine apis */ ++ adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV); ++ adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; ++ adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ adev->common.device_free_chan_resources = adm_free_chan; ++ adev->common.device_prep_slave_sg = adm_prep_slave_sg; ++ adev->common.device_issue_pending = adm_issue_pending; ++ adev->common.device_tx_status = adm_tx_status; ++ adev->common.device_terminate_all = adm_terminate_all; ++ adev->common.device_config = adm_slave_config; ++ ++ ret = dma_async_device_register(&adev->common); ++ if (ret) { ++ dev_err(adev->dev, "failed to register dma async device\n"); ++ goto err_disable_clks; ++ } ++ ++ ret = of_dma_controller_register(pdev->dev.of_node, ++ of_dma_xlate_by_chan_id, ++ &adev->common); ++ if (ret) ++ goto err_unregister_dma; ++ ++ return 0; ++ ++err_unregister_dma: ++ dma_async_device_unregister(&adev->common); ++err_disable_clks: ++ clk_disable_unprepare(adev->iface_clk); ++err_disable_core_clk: ++ clk_disable_unprepare(adev->core_clk); ++ ++ return ret; ++} ++ ++static int adm_dma_remove(struct platform_device *pdev) ++{ ++ struct adm_device *adev = platform_get_drvdata(pdev); ++ struct adm_chan *achan; ++ u32 i; ++ ++ of_dma_controller_free(pdev->dev.of_node); ++ dma_async_device_unregister(&adev->common); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) { ++ achan = &adev->channels[i]; ++ ++ /* mask IRQs for this channel/EE pair */ ++ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ ++ tasklet_kill(&adev->channels[i].vc.task); ++ adm_terminate_all(&adev->channels[i].vc.chan); ++ } ++ ++ devm_free_irq(adev->dev, adev->irq, adev); ++ ++ clk_disable_unprepare(adev->core_clk); ++ clk_disable_unprepare(adev->iface_clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id adm_of_match[] = { ++ { .compatible = "qcom,adm", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, adm_of_match); ++ ++static struct platform_driver adm_dma_driver = { ++ .probe = adm_dma_probe, ++ .remove = adm_dma_remove, ++ .driver = { ++ .name = "adm-dma-engine", ++ .of_match_table = adm_of_match, ++ }, ++}; ++ ++module_platform_driver(adm_dma_driver); ++ ++MODULE_AUTHOR("Andy Gross "); ++MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch new file mode 100644 index 0000000..a78dc82 --- /dev/null +++ b/ipq806x/patches-5.10/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -0,0 +1,217 @@ +From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam +Date: Mon, 4 Jan 2021 09:41:35 +0530 +Subject: mtd: parsers: Add Qcom SMEM parser + +NAND based Qualcomm platforms have the partition table populated in the +Shared Memory (SMEM). Hence, add a parser for parsing the partitions +from it. + +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org +--- + drivers/mtd/parsers/Kconfig | 8 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 179 insertions(+) + create mode 100644 drivers/mtd/parsers/qcomsmempart.c + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -196,6 +196,14 @@ config MTD_REDBOOT_PARTS_READONLY + + endif # MTD_REDBOOT_PARTS + ++config MTD_QCOMSMEM_PARTS ++ tristate "Qualcomm SMEM NAND flash partition parser" ++ depends on MTD_NAND_QCOM || COMPILE_TEST ++ depends on QCOM_SMEM ++ help ++ This provides support for parsing partitions from Shared Memory (SMEM) ++ for NAND flash on Qualcomm platforms. ++ + config MTD_ROUTERBOOT_PARTS + tristate "RouterBoot flash partition parser" + depends on MTD && OF +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -13,4 +13,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o ++obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +--- /dev/null ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Qualcomm SMEM NAND flash partition parser ++ * ++ * Copyright (C) 2020, Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SMEM_AARM_PARTITION_TABLE 9 ++#define SMEM_APPS 0 ++ ++#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa ++#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb ++#define SMEM_FLASH_PTABLE_V3 3 ++#define SMEM_FLASH_PTABLE_V4 4 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48 ++#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32)) ++#define SMEM_FLASH_PTABLE_NAME_SIZE 16 ++ ++/** ++ * struct smem_flash_pentry - SMEM Flash partition entry ++ * @name: Name of the partition ++ * @offset: Offset in blocks ++ * @length: Length of the partition in blocks ++ * @attr: Flags for this partition ++ */ ++struct smem_flash_pentry { ++ char name[SMEM_FLASH_PTABLE_NAME_SIZE]; ++ __le32 offset; ++ __le32 length; ++ u8 attr; ++} __packed __aligned(4); ++ ++/** ++ * struct smem_flash_ptable - SMEM Flash partition table ++ * @magic1: Partition table Magic 1 ++ * @magic2: Partition table Magic 2 ++ * @version: Partition table version ++ * @numparts: Number of partitions in this ptable ++ * @pentry: Flash partition entries belonging to this ptable ++ */ ++struct smem_flash_ptable { ++ __le32 magic1; ++ __le32 magic2; ++ __le32 version; ++ __le32 numparts; ++ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4]; ++} __packed __aligned(4); ++ ++static int parse_qcomsmem_part(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct smem_flash_pentry *pentry; ++ struct smem_flash_ptable *ptable; ++ size_t len = SMEM_FLASH_PTABLE_HDR_LEN; ++ struct mtd_partition *parts; ++ int ret, i, numparts; ++ char *name, *c; ++ ++ pr_debug("Parsing partition table info from SMEM\n"); ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR(ptable)) { ++ pr_err("Error reading partition table header\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ /* Verify ptable magic */ ++ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 || ++ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) { ++ pr_err("Partition table magic verification failed\n"); ++ return -EINVAL; ++ } ++ ++ /* Ensure that # of partitions is less than the max we have allocated */ ++ numparts = le32_to_cpu(ptable->numparts); ++ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { ++ pr_err("Partition numbers exceed the max limit\n"); ++ return -EINVAL; ++ } ++ ++ /* Find out length of partition data based on table version */ ++ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 * ++ sizeof(struct smem_flash_pentry); ++ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 * ++ sizeof(struct smem_flash_pentry); ++ } else { ++ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Now that the partition table header has been parsed, verified ++ * and the length of the partition table calculated, read the ++ * complete partition table ++ */ ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR_OR_NULL(ptable)) { ++ pr_err("Error reading partition table\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ for (i = 0; i < numparts; i++) { ++ pentry = &ptable->pentry[i]; ++ if (pentry->name[0] == '\0') ++ continue; ++ ++ name = kstrdup(pentry->name, GFP_KERNEL); ++ if (!name) { ++ ret = -ENOMEM; ++ goto out_free_parts; ++ } ++ ++ /* Convert name to lower case */ ++ for (c = name; *c != '\0'; c++) ++ *c = tolower(*c); ++ ++ parts[i].name = name; ++ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; ++ parts[i].mask_flags = pentry->attr; ++ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", ++ i, pentry->name, le32_to_cpu(pentry->offset), ++ le32_to_cpu(pentry->length), pentry->attr); ++ } ++ ++ pr_debug("SMEM partition table found: ver: %d len: %d\n", ++ le32_to_cpu(ptable->version), numparts); ++ *pparts = parts; ++ ++ return numparts; ++ ++out_free_parts: ++ while (--i >= 0) ++ kfree(parts[i].name); ++ kfree(parts); ++ *pparts = NULL; ++ ++ return ret; ++} ++ ++static const struct of_device_id qcomsmem_of_match_table[] = { ++ { .compatible = "qcom,smem-part" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); ++ ++static struct mtd_part_parser mtd_parser_qcomsmem = { ++ .parse_fn = parse_qcomsmem_part, ++ .name = "qcomsmem", ++ .of_match_table = qcomsmem_of_match_table, ++}; ++module_mtd_part_parser(mtd_parser_qcomsmem); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Manivannan Sadhasivam "); ++MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); diff --git a/ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch b/ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch new file mode 100644 index 0000000..8e9939a --- /dev/null +++ b/ipq806x/patches-5.10/101-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch @@ -0,0 +1,83 @@ +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -64,6 +64,17 @@ + #define NSS_COMMON_CLK_DIV_SGMII_100 4 + #define NSS_COMMON_CLK_DIV_SGMII_10 49 + ++#define QSGMII_PCS_ALL_CH_CTL 0x80 ++#define QSGMII_PCS_CH_SPEED_FORCE 0x2 ++#define QSGMII_PCS_CH_SPEED_10 0x0 ++#define QSGMII_PCS_CH_SPEED_100 0x4 ++#define QSGMII_PCS_CH_SPEED_1000 0x8 ++#define QSGMII_PCS_CH_SPEED_MASK (QSGMII_PCS_CH_SPEED_FORCE | \ ++ QSGMII_PCS_CH_SPEED_10 | \ ++ QSGMII_PCS_CH_SPEED_100 | \ ++ QSGMII_PCS_CH_SPEED_1000) ++#define QSGMII_PCS_CH_SPEED_SHIFT(x) (x * 4) ++ + #define QSGMII_PCS_CAL_LCKDT_CTL 0x120 + #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) + +@@ -242,6 +253,36 @@ static void ipq806x_gmac_fix_mac_speed(v + ipq806x_gmac_set_speed(gmac, speed); + } + ++static int ++ipq806x_gmac_get_qsgmii_pcs_speed_val(struct platform_device *pdev) { ++ struct device_node *fixed_link_node; ++ int rv; ++ int fixed_link_speed; ++ ++ if (!of_phy_is_fixed_link(pdev->dev.of_node)) ++ return 0; ++ ++ fixed_link_node = of_get_child_by_name(pdev->dev.of_node, "fixed-link"); ++ if (!fixed_link_node) ++ return -1; ++ ++ rv = of_property_read_u32(fixed_link_node, "speed", &fixed_link_speed); ++ of_node_put(fixed_link_node); ++ if (rv) ++ return -1; ++ ++ switch (fixed_link_speed) { ++ case SPEED_1000: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_1000; ++ case SPEED_100: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_100; ++ case SPEED_10: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_10; ++ } ++ ++ return -1; ++} ++ + static int ipq806x_gmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -250,6 +291,7 @@ static int ipq806x_gmac_probe(struct pla + struct ipq806x_gmac *gmac; + int val; + int err; ++ int qsgmii_pcs_speed; + + val = stmmac_get_platform_resources(pdev, &stmmac_res); + if (val) +@@ -346,6 +388,17 @@ static int ipq806x_gmac_probe(struct pla + 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | + 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | + 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); ++ ++ qsgmii_pcs_speed = ipq806x_gmac_get_qsgmii_pcs_speed_val(pdev); ++ if (qsgmii_pcs_speed != -1) { ++ regmap_update_bits( ++ gmac->qsgmii_csr, ++ QSGMII_PCS_ALL_CH_CTL, ++ QSGMII_PCS_CH_SPEED_MASK << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), ++ qsgmii_pcs_speed << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id)); ++ } + } + + plat_dat->has_gmac = true; diff --git a/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 0000000..e838729 --- /dev/null +++ b/ipq806x/patches-5.10/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,24 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin +--- + drivers/mtd/parsers/qcomsmempart.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/parsers/qcomsmempart.c ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -132,6 +132,11 @@ static int parse_qcomsmem_part(struct mt + parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[i].mask_flags = pentry->attr; + parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(mtd) && !strcmp(name, "rootfs")) ++ parts[i].name = "ubi"; ++ + pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", + i, pentry->name, le32_to_cpu(pentry->offset), + le32_to_cpu(pentry->length), pentry->attr); diff --git a/ipq806x/patches-5.10/103-ARM-dts-qcom-reduce-pci-IO-size-to-64K.patch b/ipq806x/patches-5.10/103-ARM-dts-qcom-reduce-pci-IO-size-to-64K.patch new file mode 100644 index 0000000..050360a --- /dev/null +++ b/ipq806x/patches-5.10/103-ARM-dts-qcom-reduce-pci-IO-size-to-64K.patch @@ -0,0 +1,46 @@ +From 84909e85881d67244240c9f40974ce12a51e3886 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 11 May 2021 23:09:45 +0200 +Subject: [PATCH] ARM: dts: qcom: reduce pci IO size to 64K + +The current value is probably a typo and is actually uncommon to find +1MB IO space even on a x86 arch. Also with recent changes to the pci +driver, pci1 and pci2 now fails to function as any connected device +fails any reg read/write. Reduce this to 64K as it should be more than +enough and 3 * 64K of total IO space doesn't exceed the IO_SPACE_LIMIT +hardcoded for the ARM arch. + +Signed-off-by: Ansuel Smith +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1085,7 +1085,7 @@ + #address-cells = <3>; + #size-cells = <2>; + +- ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00100000 /* downstream I/O */ ++ ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x08000000 0x08000000 0 0x07e00000>; /* non-prefetchable memory */ + + interrupts = ; +@@ -1136,7 +1136,7 @@ + #address-cells = <3>; + #size-cells = <2>; + +- ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00100000 /* downstream I/O */ ++ ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x2e000000 0x2e000000 0 0x03e00000>; /* non-prefetchable memory */ + + interrupts = ; +@@ -1187,7 +1187,7 @@ + #address-cells = <3>; + #size-cells = <2>; + +- ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00100000 /* downstream I/O */ ++ ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x32000000 0x32000000 0 0x03e00000>; /* non-prefetchable memory */ + + interrupts = ; diff --git a/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch b/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch new file mode 100644 index 0000000..8627244 --- /dev/null +++ b/ipq806x/patches-5.10/104-1-drivers-thermal-tsens-Add-VER_0-tsens-version.patch @@ -0,0 +1,285 @@ +From 5c7d1181056feef0b58fb2f556f55e170ba5b479 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 25 Jul 2020 19:14:59 +0200 +Subject: [PATCH 01/10] drivers: thermal: tsens: Add VER_0 tsens version + +VER_0 is used to describe device based on tsens version before v0.1. +These device are devices based on msm8960 for example apq8064 or +ipq806x. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +Reported-by: kernel test robot +Reported-by: Dan Carpenter +--- + drivers/thermal/qcom/tsens.c | 150 ++++++++++++++++++++++++++++------- + drivers/thermal/qcom/tsens.h | 4 +- + 2 files changed, 124 insertions(+), 30 deletions(-) + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int + dev_dbg(priv->dev, "[%u] %s: no violation: %d\n", + hw_id, __func__, temp); + } ++ ++ if (tsens_version(priv) < VER_0_1) { ++ /* Constraint: There is only 1 interrupt control register for all ++ * 11 temperature sensor. So monitoring more than 1 sensor based ++ * on interrupts will yield inconsistent result. To overcome this ++ * issue we will monitor only sensor 0 which is the master sensor. ++ */ ++ break; ++ } + } + + return IRQ_HANDLED; +@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor + int high_val, low_val, cl_high, cl_low; + u32 hw_id = s->hw_id; + ++ if (tsens_version(priv) < VER_0_1) { ++ /* Pre v0.1 IP had a single register for each type of interrupt ++ * and thresholds ++ */ ++ hw_id = 0; ++ } ++ + dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n", + hw_id, __func__, low, high); + +@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct ts + u32 valid; + int ret; + +- ret = regmap_field_read(priv->rf[valid_idx], &valid); +- if (ret) +- return ret; +- while (!valid) { +- /* Valid bit is 0 for 6 AHB clock cycles. +- * At 19.2MHz, 1 AHB clock is ~60ns. +- * We should enter this loop very, very rarely. +- */ +- ndelay(400); ++ /* VER_0 doesn't have VALID bit */ ++ if (tsens_version(priv) >= VER_0_1) { + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; ++ while (!valid) { ++ /* Valid bit is 0 for 6 AHB clock cycles. ++ * At 19.2MHz, 1 AHB clock is ~60ns. ++ * We should enter this loop very, very rarely. ++ */ ++ ndelay(400); ++ ret = regmap_field_read(priv->rf[valid_idx], &valid); ++ if (ret) ++ return ret; ++ } + } + + /* Valid bit is set, OK to read the temperature */ +@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_s + { + struct tsens_priv *priv = s->priv; + int hw_id = s->hw_id; +- int last_temp = 0, ret; ++ int last_temp = 0, ret, trdy; ++ unsigned long timeout; + +- ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); +- if (ret) +- return ret; ++ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); ++ do { ++ if (tsens_version(priv) == VER_0) { ++ ret = regmap_field_read(priv->rf[TRDY], &trdy); ++ if (ret) ++ return ret; ++ if (!trdy) ++ continue; ++ } + +- *temp = code_to_degc(last_temp, s) * 1000; ++ ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], &last_temp); ++ if (ret) ++ return ret; + +- return 0; ++ *temp = code_to_degc(last_temp, s) * 1000; ++ ++ return 0; ++ } while (time_before(jiffies, timeout)); ++ ++ return -ETIMEDOUT; + } + + #ifdef CONFIG_DEBUG_FS +@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv + priv->tm_offset = 0x1000; + } + +- res = platform_get_resource(op, IORESOURCE_MEM, 0); +- tm_base = devm_ioremap_resource(dev, res); +- if (IS_ERR(tm_base)) { +- ret = PTR_ERR(tm_base); +- goto err_put_device; ++ if (tsens_version(priv) >= VER_0_1) { ++ res = platform_get_resource(op, IORESOURCE_MEM, 0); ++ tm_base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(tm_base)) { ++ ret = PTR_ERR(tm_base); ++ goto err_put_device; ++ } ++ ++ priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); ++ } else { /* VER_0 share the same gcc regs using a syscon */ ++ struct device *parent = priv->dev->parent; ++ ++ if (parent) ++ priv->tm_map = syscon_node_to_regmap(parent->of_node); + } + +- priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); +- if (IS_ERR(priv->tm_map)) { +- ret = PTR_ERR(priv->tm_map); ++ if (IS_ERR_OR_NULL(priv->tm_map)) { ++ if (!priv->tm_map) ++ ret = -ENODEV; ++ else ++ ret = PTR_ERR(priv->tm_map); + goto err_put_device; + } + ++ /* VER_0 have only tm_map */ ++ if (!priv->srot_map) ++ priv->srot_map = priv->tm_map; ++ + if (tsens_version(priv) > VER_0_1) { + for (i = VER_MAJOR; i <= VER_STEP; i++) { + priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map, +@@ -771,6 +820,10 @@ int __init init_common(struct tsens_priv + ret = PTR_ERR(priv->rf[TSENS_EN]); + goto err_put_device; + } ++ /* in VER_0 TSENS need to be explicitly enabled */ ++ if (tsens_version(priv) == VER_0) ++ regmap_field_write(priv->rf[TSENS_EN], 1); ++ + ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); + if (ret) + goto err_put_device; +@@ -793,6 +846,19 @@ int __init init_common(struct tsens_priv + goto err_put_device; + } + ++ priv->rf[TSENS_SW_RST] = ++ devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]); ++ if (IS_ERR(priv->rf[TSENS_SW_RST])) { ++ ret = PTR_ERR(priv->rf[TSENS_SW_RST]); ++ goto err_put_device; ++ } ++ ++ priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]); ++ if (IS_ERR(priv->rf[TRDY])) { ++ ret = PTR_ERR(priv->rf[TRDY]); ++ goto err_put_device; ++ } ++ + /* This loop might need changes if enum regfield_ids is reordered */ + for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) { + for (i = 0; i < priv->feat->max_sensors; i++) { +@@ -808,7 +874,7 @@ int __init init_common(struct tsens_priv + } + } + +- if (priv->feat->crit_int) { ++ if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) { + /* Loop might need changes if enum regfield_ids is reordered */ + for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) { + for (i = 0; i < priv->feat->max_sensors; i++) { +@@ -846,7 +912,11 @@ int __init init_common(struct tsens_priv + } + + spin_lock_init(&priv->ul_lock); +- tsens_enable_irq(priv); ++ ++ /* VER_0 interrupt doesn't need to be enabled */ ++ if (tsens_version(priv) >= VER_0_1) ++ tsens_enable_irq(priv); ++ + tsens_debug_init(op); + + err_put_device: +@@ -945,10 +1015,19 @@ static int tsens_register_irq(struct tse + if (irq == -ENXIO) + ret = 0; + } else { +- ret = devm_request_threaded_irq(&pdev->dev, irq, +- NULL, thread_fn, +- IRQF_ONESHOT, +- dev_name(&pdev->dev), priv); ++ /* VER_0 interrupt is TRIGGER_RISING, VER_0_1 and up is ONESHOT */ ++ if (tsens_version(priv) == VER_0) ++ ret = devm_request_threaded_irq(&pdev->dev, irq, ++ thread_fn, NULL, ++ IRQF_TRIGGER_RISING, ++ dev_name(&pdev->dev), ++ priv); ++ else ++ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ++ thread_fn, IRQF_ONESHOT, ++ dev_name(&pdev->dev), ++ priv); ++ + if (ret) + dev_err(&pdev->dev, "%s: failed to get irq\n", + __func__); +@@ -977,6 +1056,19 @@ static int tsens_register(struct tsens_p + priv->ops->enable(priv, i); + } + ++ /* VER_0 require to set MIN and MAX THRESH ++ * These 2 regs are set using the: ++ * - CRIT_THRESH_0 for MAX THRESH hardcoded to 120°C ++ * - CRIT_THRESH_1 for MIN THRESH hardcoded to 0°C ++ */ ++ if (tsens_version(priv) < VER_0_1) { ++ regmap_field_write(priv->rf[CRIT_THRESH_0], ++ tsens_mC_to_hw(priv->sensor, 120000)); ++ ++ regmap_field_write(priv->rf[CRIT_THRESH_1], ++ tsens_mC_to_hw(priv->sensor, 0)); ++ } ++ + ret = tsens_register_irq(priv, "uplow", tsens_irq_thread); + if (ret < 0) + return ret; +--- a/drivers/thermal/qcom/tsens.h ++++ b/drivers/thermal/qcom/tsens.h +@@ -13,6 +13,7 @@ + #define CAL_DEGC_PT2 120 + #define SLOPE_FACTOR 1000 + #define SLOPE_DEFAULT 3200 ++#define TIMEOUT_US 100 + #define THRESHOLD_MAX_ADC_CODE 0x3ff + #define THRESHOLD_MIN_ADC_CODE 0x0 + +@@ -25,7 +26,8 @@ struct tsens_priv; + + /* IP version numbers in ascending order */ + enum tsens_ver { +- VER_0_1 = 0, ++ VER_0 = 0, ++ VER_0_1, + VER_1_X, + VER_2_X, + }; diff --git a/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch b/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch new file mode 100644 index 0000000..109f524 --- /dev/null +++ b/ipq806x/patches-5.10/104-2-drivers-thermal-tsens-Don-t-hardcode-sensor-slope.patch @@ -0,0 +1,28 @@ +From efa0d50a6c5ec7619371dfe4d3e6ca54b73787d5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 16:47:21 +0100 +Subject: [PATCH 02/10] drivers: thermal: tsens: Don't hardcode sensor slope + +Function compute_intercept_slope hardcode the sensor slope to +SLOPE_DEFAULT. Change this and use the default value only if a slope is +not defined. This is needed for tsens VER_0 that has a hardcoded slope +table. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsen + "%s: sensor%d - data_point1:%#x data_point2:%#x\n", + __func__, i, p1[i], p2[i]); + +- priv->sensor[i].slope = SLOPE_DEFAULT; ++ if (!priv->sensor[i].slope) ++ priv->sensor[i].slope = SLOPE_DEFAULT; + if (mode == TWO_PT_CALIB) { + /* + * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ diff --git a/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch b/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch new file mode 100644 index 0000000..bf37810 --- /dev/null +++ b/ipq806x/patches-5.10/104-3-drivers-thermal-tsens-Convert-msm8960-to-reg_field.patch @@ -0,0 +1,119 @@ +From 6bac2e2fa36c2d7c304768a689d8b73155b90aa2 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:15:51 +0100 +Subject: [PATCH 03/10] drivers: thermal: tsens: Convert msm8960 to reg_field + +Convert msm9860 driver to reg_field to use the init_common +function. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 80 ++++++++++++++++++++++++++++++- + 1 file changed, 79 insertions(+), 1 deletion(-) + +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -51,11 +51,22 @@ + #define MIN_LIMIT_TH 0x0 + #define MAX_LIMIT_TH 0xff + +-#define S0_STATUS_ADDR 0x3628 + #define INT_STATUS_ADDR 0x363c + #define TRDY_MASK BIT(7) + #define TIMEOUT_US 100 + ++#define S0_STATUS_OFF 0x3628 ++#define S1_STATUS_OFF 0x362c ++#define S2_STATUS_OFF 0x3630 ++#define S3_STATUS_OFF 0x3634 ++#define S4_STATUS_OFF 0x3638 ++#define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */ ++#define S6_STATUS_OFF 0x3668 ++#define S7_STATUS_OFF 0x366c ++#define S8_STATUS_OFF 0x3670 ++#define S9_STATUS_OFF 0x3674 ++#define S10_STATUS_OFF 0x3678 ++ + static int suspend_8960(struct tsens_priv *priv) + { + int ret; +@@ -269,6 +280,71 @@ static int get_temp_8960(const struct ts + return -ETIMEDOUT; + } + ++static struct tsens_features tsens_8960_feat = { ++ .ver_major = VER_0, ++ .crit_int = 0, ++ .adc = 1, ++ .srot_split = 0, ++ .max_sensors = 11, ++}; ++ ++static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { ++ /* ----- SROT ------ */ ++ /* No VERSION information */ ++ ++ /* CNTL */ ++ [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0), ++ [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1), ++ /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */ ++ [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7), ++ ++ /* ----- TM ------ */ ++ /* INTERRUPT ENABLE */ ++ /* NO INTERRUPT ENABLE */ ++ ++ /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */ ++ [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7), ++ [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15), ++ /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield ++ * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp ++ * MIN_THRESH_0 -> CRIT_THRESH_1 ++ * MAX_THRESH_0 -> CRIT_THRESH_0 ++ */ ++ [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23), ++ [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31), ++ ++ /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */ ++ /* 1 == clear, 0 == normal operation */ ++ [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9), ++ [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10), ++ ++ /* NO CRITICAL INTERRUPT SUPPORT on 8960 */ ++ ++ /* Sn_STATUS */ ++ [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7), ++ [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7), ++ [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7), ++ [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7), ++ [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7), ++ [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7), ++ [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7), ++ [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7), ++ [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7), ++ [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7), ++ [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7), ++ ++ /* No VALID field on 8960 */ ++ /* TSENS_INT_STATUS bits: 1 == threshold violated */ ++ [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0), ++ [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1), ++ [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2), ++ /* No CRITICAL field on 8960 */ ++ [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3), ++ ++ /* TRDY: 1=ready, 0=in progress */ ++ [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7), ++}; ++ + static const struct tsens_ops ops_8960 = { + .init = init_8960, + .calibrate = calibrate_8960, +@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = + struct tsens_plat_data data_8960 = { + .num_sensors = 11, + .ops = &ops_8960, ++ .feat = &tsens_8960_feat, ++ .fields = tsens_8960_regfields, + }; diff --git a/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch b/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch new file mode 100644 index 0000000..ae8a52c --- /dev/null +++ b/ipq806x/patches-5.10/104-4-drivers-thermal-tsens-Use-init_common-for-msm8960.patch @@ -0,0 +1,81 @@ +From c04f98a496929f75d75c65115d5717423c3d0634 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:16:36 +0100 +Subject: [PATCH 04/10] drivers: thermal: tsens: Use init_common for msm8960 + +Use init_common and drop custom init for msm8960. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 52 +------------------------------ + 1 file changed, 1 insertion(+), 51 deletions(-) + +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_pr + regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); + } + +-static int init_8960(struct tsens_priv *priv) +-{ +- int ret, i; +- u32 reg_cntl; +- +- priv->tm_map = dev_get_regmap(priv->dev, NULL); +- if (!priv->tm_map) +- return -ENODEV; +- +- /* +- * The status registers for each sensor are discontiguous +- * because some SoCs have 5 sensors while others have more +- * but the control registers stay in the same place, i.e +- * directly after the first 5 status registers. +- */ +- for (i = 0; i < priv->num_sensors; i++) { +- if (i >= 5) +- priv->sensor[i].status = S0_STATUS_ADDR + 40; +- priv->sensor[i].status += i * 4; +- } +- +- reg_cntl = SW_RST; +- ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); +- if (ret) +- return ret; +- +- if (priv->num_sensors > 1) { +- reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); +- reg_cntl &= ~SW_RST; +- ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, +- CONFIG_MASK, CONFIG); +- } else { +- reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); +- reg_cntl &= ~CONFIG_MASK_8660; +- reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; +- } +- +- reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; +- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); +- if (ret) +- return ret; +- +- reg_cntl |= EN; +- ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); +- if (ret) +- return ret; +- +- return 0; +-} +- + static int calibrate_8960(struct tsens_priv *priv) + { + int i; +@@ -346,7 +296,7 @@ static const struct reg_field tsens_8960 + }; + + static const struct tsens_ops ops_8960 = { +- .init = init_8960, ++ .init = init_common, + .calibrate = calibrate_8960, + .get_temp = get_temp_8960, + .enable = enable_8960, diff --git a/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch b/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch new file mode 100644 index 0000000..7b01a67 --- /dev/null +++ b/ipq806x/patches-5.10/104-5-drivers-thermal-tsens-Fix-bug-in-sensor-enable-for-m.patch @@ -0,0 +1,66 @@ +From b3e8bd33b84a6b6c863bd1733bd15b5f1483b8ab Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:06:55 +0100 +Subject: [PATCH 05/10] drivers: thermal: tsens: Fix bug in sensor enable for + msm8960 + +Device based on tsens VER_0 contains a hardware bug that results in some +problem with sensor enablement. Sensor id 6-11 can't be enabled +selectively and all of them must be enabled in one step. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -27,9 +27,9 @@ + #define EN BIT(0) + #define SW_RST BIT(1) + #define SENSOR0_EN BIT(3) ++#define MEASURE_PERIOD BIT(18) + #define SLP_CLK_ENA BIT(26) + #define SLP_CLK_ENA_8660 BIT(24) +-#define MEASURE_PERIOD 1 + #define SENSOR0_SHIFT 3 + + /* INT_STATUS_ADDR bitmasks */ +@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv + static int enable_8960(struct tsens_priv *priv, int id) + { + int ret; +- u32 reg, mask; ++ u32 reg, mask = BIT(id); + + ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); + if (ret) + return ret; + +- mask = BIT(id + SENSOR0_SHIFT); ++ /* HARDWARE BUG: ++ * On platforms with more than 6 sensors, all remaining sensors ++ * must be enabled together, otherwise undefined results are expected. ++ * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver, ++ * all the sensors are enabled in one step hence this bug is not ++ * triggered. ++ */ ++ if (id > 5) ++ mask = GENMASK(10, 6); ++ ++ mask <<= SENSOR0_SHIFT; ++ ++ /* Sensors already enabled. Skip. */ ++ if ((reg & mask) == mask) ++ return 0; ++ + ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); + if (ret) + return ret; + ++ reg |= MEASURE_PERIOD; ++ + if (priv->num_sensors > 1) + reg |= mask | SLP_CLK_ENA | EN; + else diff --git a/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch b/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch new file mode 100644 index 0000000..a82f596 --- /dev/null +++ b/ipq806x/patches-5.10/104-6-drivers-thermal-tsens-Replace-custom-8960-apis-with-.patch @@ -0,0 +1,109 @@ +From 1ff9f982051759e0387e8c7e793b49c48eae291d Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 25 Nov 2020 17:11:05 +0100 +Subject: [PATCH 06/10] drivers: thermal: tsens: Replace custom 8960 apis with + generic apis + +Rework calibrate function to use common function. Derive the offset from +a missing hardcoded slope table and the data from the nvmem calib +efuses. +Drop custom get_temp function and use generic api. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 56 +++++++++---------------------- + 1 file changed, 15 insertions(+), 41 deletions(-) + +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -67,6 +67,13 @@ + #define S9_STATUS_OFF 0x3674 + #define S10_STATUS_OFF 0x3678 + ++/* Original slope - 200 to compensate mC to C inaccuracy */ ++static u32 tsens_msm8960_slope[] = { ++ 976, 976, 954, 976, ++ 911, 932, 932, 999, ++ 932, 999, 932 ++ }; ++ + static int suspend_8960(struct tsens_priv *priv) + { + int ret; +@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_p + { + int i; + char *data; +- +- ssize_t num_read = priv->num_sensors; +- struct tsens_sensor *s = priv->sensor; ++ u32 p1[11]; + + data = qfprom_read(priv->dev, "calib"); + if (IS_ERR(data)) +@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_p + if (IS_ERR(data)) + return PTR_ERR(data); + +- for (i = 0; i < num_read; i++, s++) +- s->offset = data[i]; ++ for (i = 0; i < priv->num_sensors; i++) { ++ p1[i] = data[i]; ++ priv->sensor[i].slope = tsens_msm8960_slope[i]; ++ } ++ ++ compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB); + + kfree(data); + + return 0; + } + +-/* Temperature on y axis and ADC-code on x-axis */ +-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) +-{ +- int slope, offset; +- +- slope = thermal_zone_get_slope(s->tzd); +- offset = CAL_MDEGC - slope * s->offset; +- +- return adc_code * slope + offset; +-} +- +-static int get_temp_8960(const struct tsens_sensor *s, int *temp) +-{ +- int ret; +- u32 code, trdy; +- struct tsens_priv *priv = s->priv; +- unsigned long timeout; +- +- timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); +- do { +- ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); +- if (ret) +- return ret; +- if (!(trdy & TRDY_MASK)) +- continue; +- ret = regmap_read(priv->tm_map, s->status, &code); +- if (ret) +- return ret; +- *temp = code_to_mdegC(code, s); +- return 0; +- } while (time_before(jiffies, timeout)); +- +- return -ETIMEDOUT; +-} +- + static struct tsens_features tsens_8960_feat = { + .ver_major = VER_0, + .crit_int = 0, +@@ -315,7 +289,7 @@ static const struct reg_field tsens_8960 + static const struct tsens_ops ops_8960 = { + .init = init_common, + .calibrate = calibrate_8960, +- .get_temp = get_temp_8960, ++ .get_temp = get_temp_common, + .enable = enable_8960, + .disable = disable_8960, + .suspend = suspend_8960, diff --git a/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch b/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch new file mode 100644 index 0000000..77ca3cf --- /dev/null +++ b/ipq806x/patches-5.10/104-7-drivers-thermal-tsens-Drop-unused-define-for-msm8960.patch @@ -0,0 +1,65 @@ +From 5716a61239c6ac9ceb137e825e93c3aea06c4634 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 19 Mar 2021 00:48:23 +0100 +Subject: [PATCH 07/10] drivers: thermal: tsens: Drop unused define for msm8960 + +Drop unused define for msm8960 replaced by generic api and reg_field. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens-8960.c | 24 +----------------------- + 1 file changed, 1 insertion(+), 23 deletions(-) + +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -10,8 +10,6 @@ + #include + #include "tsens.h" + +-#define CAL_MDEGC 30000 +- + #define CONFIG_ADDR 0x3640 + #define CONFIG_ADDR_8660 0x3620 + /* CONFIG_ADDR bitmasks */ +@@ -21,39 +19,19 @@ + #define CONFIG_SHIFT_8660 28 + #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) + +-#define STATUS_CNTL_ADDR_8064 0x3660 + #define CNTL_ADDR 0x3620 + /* CNTL_ADDR bitmasks */ + #define EN BIT(0) + #define SW_RST BIT(1) +-#define SENSOR0_EN BIT(3) ++ + #define MEASURE_PERIOD BIT(18) + #define SLP_CLK_ENA BIT(26) + #define SLP_CLK_ENA_8660 BIT(24) + #define SENSOR0_SHIFT 3 + +-/* INT_STATUS_ADDR bitmasks */ +-#define MIN_STATUS_MASK BIT(0) +-#define LOWER_STATUS_CLR BIT(1) +-#define UPPER_STATUS_CLR BIT(2) +-#define MAX_STATUS_MASK BIT(3) +- + #define THRESHOLD_ADDR 0x3624 +-/* THRESHOLD_ADDR bitmasks */ +-#define THRESHOLD_MAX_LIMIT_SHIFT 24 +-#define THRESHOLD_MIN_LIMIT_SHIFT 16 +-#define THRESHOLD_UPPER_LIMIT_SHIFT 8 +-#define THRESHOLD_LOWER_LIMIT_SHIFT 0 +- +-/* Initial temperature threshold values */ +-#define LOWER_LIMIT_TH 0x50 +-#define UPPER_LIMIT_TH 0xdf +-#define MIN_LIMIT_TH 0x0 +-#define MAX_LIMIT_TH 0xff + + #define INT_STATUS_ADDR 0x363c +-#define TRDY_MASK BIT(7) +-#define TIMEOUT_US 100 + + #define S0_STATUS_OFF 0x3628 + #define S1_STATUS_OFF 0x362c diff --git a/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch b/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch new file mode 100644 index 0000000..127abae --- /dev/null +++ b/ipq806x/patches-5.10/104-8-drivers-thermal-tsens-Add-support-for-ipq8064-tsens.patch @@ -0,0 +1,26 @@ +From 0d0c22a59bf2672b57e23da9a9ea743e91b71f54 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 25 Jul 2020 19:55:57 +0200 +Subject: [PATCH 08/10] drivers: thermal: tsens: Add support for ipq8064-tsens + +Add support for tsens present in ipq806x SoCs based on generic msm8960 +tsens driver. + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -968,6 +968,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, t + + static const struct of_device_id tsens_table[] = { + { ++ .compatible = "qcom,ipq8064-tsens", ++ .data = &data_8960, ++ }, { + .compatible = "qcom,msm8916-tsens", + .data = &data_8916, + }, { diff --git a/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch b/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch new file mode 100644 index 0000000..3821068 --- /dev/null +++ b/ipq806x/patches-5.10/104-9-dt-bindings-thermal-tsens-Document-ipq8064-bindings.patch @@ -0,0 +1,112 @@ +From ac369071920d427dd484cf74cddba2774bba45f5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 9 Jul 2020 22:35:54 +0200 +Subject: [PATCH 09/10] dt-bindings: thermal: tsens: Document ipq8064 bindings + +Document the use of bindings used for msm8960 tsens based devices. +msm8960 use the same gcc regs and is set as a child of the qcom gcc. + +Signed-off-by: Ansuel Smith +Reviewed-by: Rob Herring +--- + .../bindings/thermal/qcom-tsens.yaml | 56 ++++++++++++++++--- + 1 file changed, 48 insertions(+), 8 deletions(-) + +--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml ++++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +@@ -19,6 +19,11 @@ description: | + properties: + compatible: + oneOf: ++ - description: msm9860 TSENS based ++ items: ++ - enum: ++ - qcom,ipq8064-tsens ++ + - description: v0.1 of TSENS + items: + - enum: +@@ -73,7 +78,9 @@ properties: + maxItems: 2 + items: + - const: calib +- - const: calib_sel ++ - enum: ++ - calib_backup ++ - calib_sel + + "#qcom,sensors": + description: +@@ -88,12 +95,20 @@ properties: + Number of cells required to uniquely identify the thermal sensors. Since + we have multiple sensors this is set to 1 + ++required: ++ - compatible ++ - interrupts ++ - interrupt-names ++ - "#thermal-sensor-cells" ++ - "#qcom,sensors" ++ + allOf: + - if: + properties: + compatible: + contains: + enum: ++ - qcom,ipq8064-tsens + - qcom,msm8916-tsens + - qcom,msm8974-tsens + - qcom,msm8976-tsens +@@ -114,19 +129,44 @@ allOf: + interrupt-names: + minItems: 2 + +-required: +- - compatible +- - reg +- - "#qcom,sensors" +- - interrupts +- - interrupt-names +- - "#thermal-sensor-cells" ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - qcom,tsens-v0_1 ++ - qcom,tsens-v1 ++ - qcom,tsens-v2 ++ ++ then: ++ required: ++ - reg + + additionalProperties: false + + examples: + - | + #include ++ // Example msm9860 based SoC (ipq8064): ++ gcc: clock-controller { ++ ++ /* ... */ ++ ++ tsens: thermal-sensor { ++ compatible = "qcom,ipq8064-tsens"; ++ ++ nvmem-cells = <&tsens_calib>, <&tsens_calib_backup>; ++ nvmem-cell-names = "calib", "calib_backup"; ++ interrupts = ; ++ interrupt-names = "uplow"; ++ ++ #qcom,sensors = <11>; ++ #thermal-sensor-cells = <1>; ++ }; ++ }; ++ ++ - | ++ #include + // Example 1 (legacy: for pre v1 IP): + tsens1: thermal-sensor@900000 { + compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1"; diff --git a/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch b/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch new file mode 100644 index 0000000..6cdc0b2 --- /dev/null +++ b/ipq806x/patches-5.10/105-10-drivers-thermal-tsens-Fix-wrong-slope-on-msm-8960.patch @@ -0,0 +1,32 @@ +From 68e720ed73c8f038c8c500e4c49c1e65a993a448 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 6 Apr 2021 04:45:31 +0200 +Subject: [PATCH 10/10] drivers: thermal: tsens: Fix wrong slope on msm-8960 + +Some user using some stats with the old legacy implementation and the +new implementation using the compute_intercept_slope reported an offset +of 3C. Fix the slope table to reflect the original temp. + +Signed-off-by: Ansuel Smith +--- + drivers/thermal/qcom/tsens-8960.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/thermal/qcom/tsens-8960.c ++++ b/drivers/thermal/qcom/tsens-8960.c +@@ -45,11 +45,11 @@ + #define S9_STATUS_OFF 0x3674 + #define S10_STATUS_OFF 0x3678 + +-/* Original slope - 200 to compensate mC to C inaccuracy */ ++/* Original slope - 350 to compensate mC to C inaccuracy */ + static u32 tsens_msm8960_slope[] = { +- 976, 976, 954, 976, +- 911, 932, 932, 999, +- 932, 999, 932 ++ 826, 826, 804, 826, ++ 761, 782, 782, 849, ++ 782, 849, 782 + }; + + static int suspend_8960(struct tsens_priv *priv) diff --git a/ipq806x/patches-5.10/107-1-thermal-qcom-tsens-init-debugfs-only-with-successful.patch b/ipq806x/patches-5.10/107-1-thermal-qcom-tsens-init-debugfs-only-with-successful.patch new file mode 100644 index 0000000..1dc2d2e --- /dev/null +++ b/ipq806x/patches-5.10/107-1-thermal-qcom-tsens-init-debugfs-only-with-successful.patch @@ -0,0 +1,41 @@ +From 8f32d48a309246a80bdca505968085a484d54408 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 19 Apr 2021 03:01:53 +0200 +Subject: [thermal-next PATCH v2 1/2] thermal: qcom: tsens: init debugfs only with + successful probe + +calibrate and tsens_register can fail or PROBE_DEFER. This will cause a +double or a wrong init of the debugfs information. Init debugfs only +with successful probe fixing warning about directory already present. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -918,8 +918,6 @@ int __init init_common(struct tsens_priv + if (tsens_version(priv) >= VER_0_1) + tsens_enable_irq(priv); + +- tsens_debug_init(op); +- + err_put_device: + put_device(&op->dev); + return ret; +@@ -1155,7 +1153,12 @@ static int tsens_probe(struct platform_d + } + } + +- return tsens_register(priv); ++ ret = tsens_register(priv); ++ ++ if (!ret) ++ tsens_debug_init(pdev); ++ ++ return ret; + } + + static int tsens_remove(struct platform_device *pdev) diff --git a/ipq806x/patches-5.10/107-2-thermal-qcom-tsens-simplify-debugfs-init-function.patch b/ipq806x/patches-5.10/107-2-thermal-qcom-tsens-simplify-debugfs-init-function.patch new file mode 100644 index 0000000..0fbc4bd --- /dev/null +++ b/ipq806x/patches-5.10/107-2-thermal-qcom-tsens-simplify-debugfs-init-function.patch @@ -0,0 +1,54 @@ +From 4204f22060f7a5d42c6ccb4d4c25a6a875571099 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 19 Apr 2021 03:08:37 +0200 +Subject: [thermal-next PATCH v2 2/2] thermal: qcom: tsens: simplify debugfs init + function + +Simplify debugfs init function. +- Add check for existing dev directory. +- Fix wrong version in dbg_version_show (with version 0.0.0, 0.1.0 was + incorrectly reported) + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -692,7 +692,7 @@ static int dbg_version_show(struct seq_f + return ret; + seq_printf(s, "%d.%d.%d\n", maj_ver, min_ver, step_ver); + } else { +- seq_puts(s, "0.1.0\n"); ++ seq_printf(s, "0.%d.0\n", priv->feat->ver_major); + } + + return 0; +@@ -704,21 +704,17 @@ DEFINE_SHOW_ATTRIBUTE(dbg_sensors); + static void tsens_debug_init(struct platform_device *pdev) + { + struct tsens_priv *priv = platform_get_drvdata(pdev); +- struct dentry *root, *file; + +- root = debugfs_lookup("tsens", NULL); +- if (!root) ++ priv->debug_root = debugfs_lookup("tsens", NULL); ++ if (!priv->debug_root) + priv->debug_root = debugfs_create_dir("tsens", NULL); +- else +- priv->debug_root = root; + +- file = debugfs_lookup("version", priv->debug_root); +- if (!file) ++ if (!debugfs_lookup("version", priv->debug_root)) + debugfs_create_file("version", 0444, priv->debug_root, + pdev, &dbg_version_fops); + + /* A directory for each instance of the TSENS IP */ +- priv->debug = debugfs_create_dir(dev_name(&pdev->dev), priv->debug_root); ++ priv->debug = debugfs_lookup(dev_name(&pdev->dev), priv->debug_root); + debugfs_create_file("sensors", 0444, priv->debug, pdev, &dbg_sensors_fops); + } + #else diff --git a/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch b/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch new file mode 100644 index 0000000..8325e10 --- /dev/null +++ b/ipq806x/patches-5.10/850-soc-add-qualcomm-syscon.patch @@ -0,0 +1,121 @@ +From: Christian Lamparter +Subject: SoC: add qualcomm syscon +--- a/drivers/soc/qcom/Makefile ++++ b/drivers/soc/qcom/Makefile +@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o + obj-$(CONFIG_QCOM_SMSM) += smsm.o + obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o + obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o ++obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o + obj-$(CONFIG_QCOM_APR) += apr.o + obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o + obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o +--- a/drivers/soc/qcom/Kconfig ++++ b/drivers/soc/qcom/Kconfig +@@ -189,6 +189,13 @@ config QCOM_SOCINFO + Say yes here to support the Qualcomm socinfo driver, providing + information about the SoC to user space. + ++config QCOM_TCSR ++ tristate "QCOM Top Control and Status Registers" ++ depends on ARCH_QCOM ++ help ++ Say y here to enable TCSR support. The TCSR provides control ++ functions for various peripherals. ++ + config QCOM_WCNSS_CTRL + tristate "Qualcomm WCNSS control driver" + depends on ARCH_QCOM || COMPILE_TEST +--- /dev/null ++++ b/drivers/soc/qcom/qcom_tcsr.c +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (c) 2014, The Linux foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License rev 2 and ++ * only rev 2 as published by the free Software foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TCSR_USB_PORT_SEL 0xb0 ++ ++static int tcsr_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ const struct device_node *node = pdev->dev.of_node; ++ void __iomem *base; ++ u32 val; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) { ++ dev_err(&pdev->dev, "setting usb port select = %d\n", val); ++ writel(val, base + TCSR_USB_PORT_SEL); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id tcsr_dt_match[] = { ++ { .compatible = "qcom,tcsr", }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, tcsr_dt_match); ++ ++static struct platform_driver tcsr_driver = { ++ .driver = { ++ .name = "tcsr", ++ .owner = THIS_MODULE, ++ .of_match_table = tcsr_dt_match, ++ }, ++ .probe = tcsr_probe, ++}; ++ ++module_platform_driver(tcsr_driver); ++ ++MODULE_AUTHOR("Andy Gross "); ++MODULE_DESCRIPTION("QCOM TCSR driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/include/dt-bindings/soc/qcom,tcsr.h +@@ -0,0 +1,23 @@ ++/* Copyright (c) 2014, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#ifndef __DT_BINDINGS_QCOM_TCSR_H ++#define __DT_BINDINGS_QCOM_TCSR_H ++ ++#define TCSR_USB_SELECT_USB3_P0 0x1 ++#define TCSR_USB_SELECT_USB3_P1 0x2 ++#define TCSR_USB_SELECT_USB3_DUAL 0x3 ++ ++/* TCSR A/B REG */ ++#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL 0 ++#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL 1 ++ ++#endif diff --git a/ipq806x/patches-5.10/851-add-gsbi1-dts.patch b/ipq806x/patches-5.10/851-add-gsbi1-dts.patch new file mode 100644 index 0000000..3a83b2d --- /dev/null +++ b/ipq806x/patches-5.10/851-add-gsbi1-dts.patch @@ -0,0 +1,44 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -747,6 +747,41 @@ + reg = <0x12100000 0x10000>; + }; + ++ gsbi1: gsbi@12440000 { ++ compatible = "qcom,gsbi-v1.0.0"; ++ cell-index = <1>; ++ reg = <0x12440000 0x100>; ++ clocks = <&gcc GSBI1_H_CLK>; ++ clock-names = "iface"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ status = "disabled"; ++ ++ syscon-tcsr = <&tcsr>; ++ ++ gsbi1_serial: serial@12450000 { ++ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; ++ reg = <0x12450000 0x100>, ++ <0x12400000 0x03>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ status = "disabled"; ++ }; ++ ++ gsbi1_i2c: i2c@12460000 { ++ compatible = "qcom,i2c-qup-v1.1.1"; ++ reg = <0x12460000 0x1000>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ }; ++ + gsbi2: gsbi@12480000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <2>; diff --git a/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch b/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch new file mode 100644 index 0000000..2459e6a --- /dev/null +++ b/ipq806x/patches-5.10/900-arm-add-cmdline-override.patch @@ -0,0 +1,37 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1793,6 +1793,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL + + endchoice + ++config CMDLINE_OVERRIDE ++ bool "Use alternative cmdline from device tree" ++ help ++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can ++ be used, this is not a good option for kernels that are shared across ++ devices. This setting enables using "chosen/cmdline-override" as the ++ cmdline if it exists in the device tree. ++ + config CMDLINE + string "Default kernel command string" + default "" +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1056,6 +1056,17 @@ int __init early_init_dt_scan_chosen(uns + if (p != NULL && l > 0) + strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); + ++ /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different ++ * device tree option of chosen/bootargs-override. This is ++ * helpful on boards where u-boot sets bootargs, and is unable ++ * to be modified. ++ */ ++#ifdef CONFIG_CMDLINE_OVERRIDE ++ p = of_get_flat_dt_prop(node, "bootargs-override", &l); ++ if (p != NULL && l > 0) ++ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++#endif ++ + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else + * managed to set the command line, unless CONFIG_CMDLINE_FORCE diff --git a/ipq806x/patches-5.10/997-device_tree_cmdline.patch b/ipq806x/patches-5.10/997-device_tree_cmdline.patch new file mode 100644 index 0000000..bdcba2a --- /dev/null +++ b/ipq806x/patches-5.10/997-device_tree_cmdline.patch @@ -0,0 +1,12 @@ +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1055,6 +1055,9 @@ int __init early_init_dt_scan_chosen(uns + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + + /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different + * device tree option of chosen/bootargs-override. This is diff --git a/ipq806x/patches-5.4/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch b/ipq806x/patches-5.4/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch new file mode 100644 index 0000000..83d7bbc --- /dev/null +++ b/ipq806x/patches-5.4/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch @@ -0,0 +1,71 @@ +From 28d0ed88f536dd639adf1b0c7c08e04be3c8f294 Mon Sep 17 00:00:00 2001 +From: Thomas Pedersen +Date: Mon, 16 May 2016 17:58:50 -0700 +Subject: [PATCH 01/69] dtbindings: qcom_adm: Fix channel specifiers + +Original patch from Andy Gross. + +This patch removes the crci information from the dma +channel property. At least one client device requires +using more than one CRCI value for a channel. This does +not match the current binding and the crci information +needs to be removed. + +Instead, the client device will provide this information +via other means. + +Signed-off-by: Andy Gross +Signed-off-by: Thomas Pedersen +--- + Documentation/devicetree/bindings/dma/qcom_adm.txt | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +--- a/Documentation/devicetree/bindings/dma/qcom_adm.txt ++++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt +@@ -4,8 +4,7 @@ Required properties: + - compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960 + - reg: Address range for DMA registers + - interrupts: Should contain one interrupt shared by all channels +-- #dma-cells: must be <2>. First cell denotes the channel number. Second cell +- denotes CRCI (client rate control interface) flow control assignment. ++- #dma-cells: must be <1>. First cell denotes the channel number. + - clocks: Should contain the core clock and interface clock. + - clock-names: Must contain "core" for the core clock and "iface" for the + interface clock. +@@ -22,7 +21,7 @@ Example: + compatible = "qcom,adm"; + reg = <0x18300000 0x100000>; + interrupts = <0 170 0>; +- #dma-cells = <2>; ++ #dma-cells = <1>; + + clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; + clock-names = "core", "iface"; +@@ -35,15 +34,12 @@ Example: + qcom,ee = <0>; + }; + +-DMA clients must use the format descripted in the dma.txt file, using a three ++DMA clients must use the format descripted in the dma.txt file, using a two + cell specifier for each channel. + +-Each dmas request consists of 3 cells: ++Each dmas request consists of two cells: + 1. phandle pointing to the DMA controller + 2. channel number +- 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0. +- The CRCI is used for flow control. It identifies the peripheral device that +- is the source/destination for the transferred data. + + Example: + +@@ -55,7 +51,7 @@ Example: + + cs-gpios = <&qcom_pinmux 20 0>; + +- dmas = <&adm_dma 6 9>, +- <&adm_dma 5 10>; ++ dmas = <&adm_dma 6>, ++ <&adm_dma 5>; + dma-names = "rx", "tx"; + }; diff --git a/ipq806x/patches-5.4/0030-clk-Disable-i2c-device-on-gsbi4.patch b/ipq806x/patches-5.4/0030-clk-Disable-i2c-device-on-gsbi4.patch new file mode 100644 index 0000000..a5fb714 --- /dev/null +++ b/ipq806x/patches-5.4/0030-clk-Disable-i2c-device-on-gsbi4.patch @@ -0,0 +1,40 @@ +From 0c974b87829e007dc4fae94e20d488204e20e662 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 08:16:10 +0100 +Subject: [PATCH 30/69] clk: Disable i2c device on gsbi4 + +This patch was not annotated and comes from the v4.4 tree. + +Signed-off-by: John Crispin +--- + drivers/clk/qcom/gcc-ipq806x.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -365,7 +365,7 @@ static struct clk_rcg gsbi1_uart_src = { + .parent_names = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -383,7 +383,7 @@ static struct clk_branch gsbi1_uart_clk + }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -961,6 +961,7 @@ static struct clk_branch gsbi1_h_clk = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_h_clk", + .ops = &clk_branch_ops, ++ .flags = CLK_IGNORE_UNUSED, + }, + }, + }; diff --git a/ipq806x/patches-5.4/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch b/ipq806x/patches-5.4/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch new file mode 100644 index 0000000..a12aa72 --- /dev/null +++ b/ipq806x/patches-5.4/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch @@ -0,0 +1,29 @@ +From 48051ece78136e4235a2415a52797db56f8a4478 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Tue, 21 Apr 2015 19:09:07 -0700 +Subject: [PATCH 33/69] ARM: qcom: automatically select PCI_DOMAINS if PCI is + enabled + +If multiple PCIe devices are present in the system, the kernel will +panic at boot time when trying to scan the PCI buses. This happens on +IPQ806x based platforms, which has 3 PCIe ports. + +Enabling this option allows the kernel to assign the pci-domains +according to the device-tree content. This allows multiple PCIe +controllers to coexist in the system. + +Signed-off-by: Mathieu Olivari +--- + arch/arm/mach-qcom/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/mach-qcom/Kconfig ++++ b/arch/arm/mach-qcom/Kconfig +@@ -7,6 +7,7 @@ menuconfig ARCH_QCOM + select ARM_AMBA + select PINCTRL + select QCOM_SCM if SMP ++ select PCI_DOMAINS if PCI + help + Support for Qualcomm's devicetree based systems. + diff --git a/ipq806x/patches-5.4/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch b/ipq806x/patches-5.4/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch new file mode 100644 index 0000000..7d6e3f1 --- /dev/null +++ b/ipq806x/patches-5.4/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch @@ -0,0 +1,29 @@ +From 04ca10340f1b4d92e849724d322a7ca225d11539 Mon Sep 17 00:00:00 2001 +From: Lina Iyer +Date: Wed, 25 Mar 2015 14:25:29 -0600 +Subject: [PATCH 59/69] ARM: cpuidle: Add cpuidle support for QCOM cpus + +Define ARM_QCOM_CPUIDLE config item to enable cpuidle support. + +Cc: Stephen Boyd +Cc: Arnd Bergmann +Cc: Kevin Hilman +Cc: Daniel Lezcano +Signed-off-by: Lina Iyer +--- + drivers/cpuidle/Kconfig.arm | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/cpuidle/Kconfig.arm ++++ b/drivers/cpuidle/Kconfig.arm +@@ -86,3 +86,10 @@ config ARM_MVEBU_V7_CPUIDLE + depends on ARCH_MVEBU && !ARM64 + help + Select this to enable cpuidle on Armada 370, 38x and XP processors. ++ ++config ARM_QCOM_CPUIDLE ++ bool "CPU Idle Driver for QCOM processors" ++ depends on ARCH_QCOM ++ select ARM_CPUIDLE ++ help ++ Select this to enable cpuidle on QCOM processors. diff --git a/ipq806x/patches-5.4/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/ipq806x/patches-5.4/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch new file mode 100644 index 0000000..6d3e7d9 --- /dev/null +++ b/ipq806x/patches-5.4/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch @@ -0,0 +1,62 @@ +From fa71139b55e114aa8c3c4823ff8ee7d49ee810d4 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Wed, 29 Apr 2015 15:21:46 -0700 +Subject: [PATCH 60/69] HACK: arch: arm: force ZRELADDR on arch-qcom + +ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended +on most ARM architectures. This automatically calculate ZRELADDR by +masking PHYS_OFFSET with 0xf8000000. + +However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware +network accelerators, and the bootloader removes this section from the +layout passed from the ATAGS (when used). + +For newer bootloader, when DT is used, this is not a problem, we just +reserve this memory in the device tree. But if the bootloader doesn't +have DT support, then ATAGS have to be used. In this case, the ARM +decompressor will position the kernel in this low mem, which will not be +in the RAM section mapped by the bootloader, which means the kernel will +freeze in the middle of the boot process trying to map the memory. + +As a work around, this patch allows disabling AUTO_ZRELADDR when +ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders +which don't support device-tree, which is the case on certain early +IPQ806x based designs. + +Signed-off-by: Mathieu Olivari +--- + arch/arm/Kconfig | 2 +- + arch/arm/Makefile | 2 ++ + arch/arm/mach-qcom/Makefile.boot | 1 + + 3 files changed, 4 insertions(+), 1 deletion(-) + create mode 100644 arch/arm/mach-qcom/Makefile.boot + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -319,7 +319,7 @@ config ARCH_MULTIPLATFORM + depends on MMU + select ARM_HAS_SG_CHAIN + select ARM_PATCH_PHYS_VIRT +- select AUTO_ZRELADDR ++ select AUTO_ZRELADDR if !ARCH_QCOM + select TIMER_OF + select COMMON_CLK + select GENERIC_CLOCKEVENTS +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -258,9 +258,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac + else + MACHINE := + endif ++ifeq ($(CONFIG_ARCH_QCOM),) + ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y) + MACHINE := + endif ++endif + + machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) + platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y))) +--- /dev/null ++++ b/arch/arm/mach-qcom/Makefile.boot +@@ -0,0 +1 @@ ++zreladdr-y+= 0x42208000 diff --git a/ipq806x/patches-5.4/0063-1-ipq806x-tsens-driver.patch b/ipq806x/patches-5.4/0063-1-ipq806x-tsens-driver.patch new file mode 100644 index 0000000..80954c1 --- /dev/null +++ b/ipq806x/patches-5.4/0063-1-ipq806x-tsens-driver.patch @@ -0,0 +1,616 @@ +From 3302e1e1a3cfa4e67fda2a61d6f0c42205d40932 Mon Sep 17 00:00:00 2001 +From: Rajith Cherian +Date: Tue, 14 Feb 2017 18:30:43 +0530 +Subject: [PATCH] ipq8064: tsens: Base tsens driver for IPQ8064 + +Add TSENS driver template to support IPQ8064. +This is a base file copied from tsens-8960.c + +Change-Id: I47c573fdfa2d898243c6a6ba952d1632f91391f7 +Signed-off-by: Rajith Cherian + +ipq8064: tsens: TSENS driver support for IPQ8064 + +Support for IPQ8064 tsens driver. The driver works +with the thermal framework. The driver overrides the +following fucntionalities: + +1. Get current temperature. +2. Get/Set trip temperatures. +3. Enabled/Disable trip points. +4. ISR for threshold generated interrupt. +5. Notify userspace when trip points are hit. + +Change-Id: I8bc7204fd627d10875ab13fc1de8cb6c2ed7a918 +Signed-off-by: Rajith Cherian +--- + +--- a/drivers/thermal/qcom/Makefile ++++ b/drivers/thermal/qcom/Makefile +@@ -2,5 +2,5 @@ + obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o + + qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o \ +- tsens-8960.o tsens-v2.o tsens-v1.o ++ tsens-8960.o tsens-v2.o tsens-v1.o tsens-ipq8064.o + obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o +--- /dev/null ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -0,0 +1,551 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "tsens.h" ++ ++#define CAL_MDEGC 30000 ++ ++#define CONFIG_ADDR 0x3640 ++/* CONFIG_ADDR bitmasks */ ++#define CONFIG 0x9b ++#define CONFIG_MASK 0xf ++#define CONFIG_SHIFT 0 ++ ++#define STATUS_CNTL_8064 0x3660 ++#define CNTL_ADDR 0x3620 ++/* CNTL_ADDR bitmasks */ ++#define EN BIT(0) ++#define SW_RST BIT(1) ++#define SENSOR0_EN BIT(3) ++#define SLP_CLK_ENA BIT(26) ++#define MEASURE_PERIOD 1 ++#define SENSOR0_SHIFT 3 ++ ++/* INT_STATUS_ADDR bitmasks */ ++#define MIN_STATUS_MASK BIT(0) ++#define LOWER_STATUS_CLR BIT(1) ++#define UPPER_STATUS_CLR BIT(2) ++#define MAX_STATUS_MASK BIT(3) ++ ++#define THRESHOLD_ADDR 0x3624 ++/* THRESHOLD_ADDR bitmasks */ ++#define THRESHOLD_MAX_CODE 0x20000 ++#define THRESHOLD_MIN_CODE 0 ++#define THRESHOLD_MAX_LIMIT_SHIFT 24 ++#define THRESHOLD_MIN_LIMIT_SHIFT 16 ++#define THRESHOLD_UPPER_LIMIT_SHIFT 8 ++#define THRESHOLD_LOWER_LIMIT_SHIFT 0 ++#define THRESHOLD_MAX_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_MAX_LIMIT_SHIFT) ++#define THRESHOLD_MIN_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_MIN_LIMIT_SHIFT) ++#define THRESHOLD_UPPER_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_UPPER_LIMIT_SHIFT) ++#define THRESHOLD_LOWER_LIMIT_MASK (THRESHOLD_MAX_CODE << \ ++ THRESHOLD_LOWER_LIMIT_SHIFT) ++ ++/* Initial temperature threshold values */ ++#define LOWER_LIMIT_TH 0x9d /* 95C */ ++#define UPPER_LIMIT_TH 0xa6 /* 105C */ ++#define MIN_LIMIT_TH 0x0 ++#define MAX_LIMIT_TH 0xff ++ ++#define S0_STATUS_ADDR 0x3628 ++#define STATUS_ADDR_OFFSET 2 ++#define SENSOR_STATUS_SIZE 4 ++#define INT_STATUS_ADDR 0x363c ++#define TRDY_MASK BIT(7) ++#define TIMEOUT_US 100 ++ ++#define TSENS_EN BIT(0) ++#define TSENS_SW_RST BIT(1) ++#define TSENS_ADC_CLK_SEL BIT(2) ++#define SENSOR0_EN BIT(3) ++#define SENSOR1_EN BIT(4) ++#define SENSOR2_EN BIT(5) ++#define SENSOR3_EN BIT(6) ++#define SENSOR4_EN BIT(7) ++#define SENSORS_EN (SENSOR0_EN | SENSOR1_EN | \ ++ SENSOR2_EN | SENSOR3_EN | SENSOR4_EN) ++#define TSENS_8064_SENSOR5_EN BIT(8) ++#define TSENS_8064_SENSOR6_EN BIT(9) ++#define TSENS_8064_SENSOR7_EN BIT(10) ++#define TSENS_8064_SENSOR8_EN BIT(11) ++#define TSENS_8064_SENSOR9_EN BIT(12) ++#define TSENS_8064_SENSOR10_EN BIT(13) ++#define TSENS_8064_SENSORS_EN (SENSORS_EN | \ ++ TSENS_8064_SENSOR5_EN | \ ++ TSENS_8064_SENSOR6_EN | \ ++ TSENS_8064_SENSOR7_EN | \ ++ TSENS_8064_SENSOR8_EN | \ ++ TSENS_8064_SENSOR9_EN | \ ++ TSENS_8064_SENSOR10_EN) ++ ++#define TSENS_8064_SEQ_SENSORS 5 ++#define TSENS_8064_S4_S5_OFFSET 40 ++#define TSENS_FACTOR 1 ++ ++/* Trips: from very hot to very cold */ ++enum tsens_trip_type { ++ TSENS_TRIP_STAGE3 = 0, ++ TSENS_TRIP_STAGE2, ++ TSENS_TRIP_STAGE1, ++ TSENS_TRIP_STAGE0, ++ TSENS_TRIP_NUM, ++}; ++ ++u32 tsens_8064_slope[] = { ++ 1176, 1176, 1154, 1176, ++ 1111, 1132, 1132, 1199, ++ 1132, 1199, 1132 ++ }; ++ ++/* Temperature on y axis and ADC-code on x-axis */ ++static inline int code_to_degC(u32 adc_code, const struct tsens_sensor *s) ++{ ++ int degcbeforefactor, degc; ++ ++ degcbeforefactor = (adc_code * s->slope) + s->offset; ++ ++ if (degcbeforefactor == 0) ++ degc = degcbeforefactor; ++ else if (degcbeforefactor > 0) ++ degc = (degcbeforefactor + TSENS_FACTOR/2) ++ / TSENS_FACTOR; ++ else ++ degc = (degcbeforefactor - TSENS_FACTOR/2) ++ / TSENS_FACTOR; ++ ++ return degc; ++} ++ ++static int degC_to_code(int degC, const struct tsens_sensor *s) ++{ ++ int code = ((degC * TSENS_FACTOR - s->offset) + (s->slope/2)) ++ / s->slope; ++ ++ if (code > THRESHOLD_MAX_CODE) ++ code = THRESHOLD_MAX_CODE; ++ else if (code < THRESHOLD_MIN_CODE) ++ code = THRESHOLD_MIN_CODE; ++ return code; ++} ++ ++static int suspend_ipq8064(struct tsens_priv *priv) ++{ ++ int ret; ++ unsigned int mask; ++ struct regmap *map = priv->tm_map; ++ ++ ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); ++ if (ret) ++ return ret; ++ ++ mask = SLP_CLK_ENA | EN; ++ ++ ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int resume_ipq8064(struct tsens_priv *priv) ++{ ++ int ret; ++ struct regmap *map = priv->tm_map; ++ ++ ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static void notify_uspace_tsens_fn(struct work_struct *work) ++{ ++ struct tsens_sensor *s = container_of(work, struct tsens_sensor, ++ notify_work); ++ ++ sysfs_notify(&s->tzd->device.kobj, NULL, "type"); ++} ++ ++static void tsens_scheduler_fn(struct work_struct *work) ++{ ++ struct tsens_priv *priv = container_of(work, struct tsens_priv, ++ tsens_work); ++ unsigned int threshold, threshold_low, code, reg, sensor, mask; ++ unsigned int sensor_addr; ++ bool upper_th_x, lower_th_x; ++ int adc_code, ret; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); ++ if (ret) ++ return; ++ reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR; ++ ret = regmap_write(priv->tm_map, STATUS_CNTL_8064, reg); ++ if (ret) ++ return; ++ ++ mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR); ++ ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, &threshold); ++ if (ret) ++ return; ++ threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK) ++ >> THRESHOLD_LOWER_LIMIT_SHIFT; ++ threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK) ++ >> THRESHOLD_UPPER_LIMIT_SHIFT; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); ++ if (ret) ++ return; ++ ++ ret = regmap_read(priv->tm_map, CNTL_ADDR, &sensor); ++ if (ret) ++ return; ++ sensor &= (uint32_t) TSENS_8064_SENSORS_EN; ++ sensor >>= SENSOR0_SHIFT; ++ ++ /* Constraint: There is only 1 interrupt control register for all ++ * 11 temperature sensor. So monitoring more than 1 sensor based ++ * on interrupts will yield inconsistent result. To overcome this ++ * issue we will monitor only sensor 0 which is the master sensor. ++ */ ++ ++ /* Skip if the sensor is disabled */ ++ if (sensor & 1) { ++ ret = regmap_read(priv->tm_map, priv->sensor[0].status, &code); ++ if (ret) ++ return; ++ upper_th_x = code >= threshold; ++ lower_th_x = code <= threshold_low; ++ if (upper_th_x) ++ mask |= UPPER_STATUS_CLR; ++ if (lower_th_x) ++ mask |= LOWER_STATUS_CLR; ++ if (upper_th_x || lower_th_x) { ++ /* Notify user space */ ++ schedule_work(&priv->sensor[0].notify_work); ++ regmap_read(priv->tm_map, sensor_addr, &adc_code); ++ pr_debug("Trigger (%d degrees) for sensor %d\n", ++ code_to_degC(adc_code, &priv->sensor[0]), 0); ++ } ++ } ++ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask); ++ ++ /* force memory to sync */ ++ mb(); ++} ++ ++static irqreturn_t tsens_isr(int irq, void *data) ++{ ++ struct tsens_priv *priv = data; ++ ++ schedule_work(&priv->tsens_work); ++ return IRQ_HANDLED; ++} ++ ++static void hw_init(struct tsens_priv *priv) ++{ ++ int ret; ++ unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0; ++ unsigned int reg_status_cntl = 0; ++ ++ regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); ++ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl | TSENS_SW_RST); ++ ++ reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18) ++ | (((1 << priv->num_sensors) - 1) << SENSOR0_SHIFT); ++ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_status_cntl); ++ reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR ++ | MIN_STATUS_MASK | MAX_STATUS_MASK; ++ regmap_write(priv->tm_map, STATUS_CNTL_8064, reg_status_cntl); ++ reg_cntl |= TSENS_EN; ++ regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ ++ regmap_read(priv->tm_map, CONFIG_ADDR, ®_cfg); ++ reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT); ++ regmap_write(priv->tm_map, CONFIG_ADDR, reg_cfg); ++ ++ reg_thr |= (LOWER_LIMIT_TH << THRESHOLD_LOWER_LIMIT_SHIFT) ++ | (UPPER_LIMIT_TH << THRESHOLD_UPPER_LIMIT_SHIFT) ++ | (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT) ++ | (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT); ++ ++ regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_thr); ++ ++ ret = devm_request_irq(priv->dev, priv->tsens_irq, tsens_isr, ++ IRQF_TRIGGER_RISING, "tsens_interrupt", priv); ++ if (ret < 0) { ++ pr_err("%s: request_irq FAIL: %d\n", __func__, ret); ++ return; ++ } ++ ++ INIT_WORK(&priv->tsens_work, tsens_scheduler_fn); ++} ++ ++static int init_ipq8064(struct tsens_priv *priv) ++{ ++ int ret, i; ++ u32 reg_cntl, offset = 0; ++ ++ init_common(priv); ++ if (!priv->tm_map) ++ return -ENODEV; ++ ++ /* ++ * The status registers for each sensor are discontiguous ++ * because some SoCs have 5 sensors while others have more ++ * but the control registers stay in the same place, i.e ++ * directly after the first 5 status registers. ++ */ ++ for (i = 0; i < priv->num_sensors; i++) { ++ if (i >= TSENS_8064_SEQ_SENSORS) ++ offset = TSENS_8064_S4_S5_OFFSET; ++ ++ priv->sensor[i].status = S0_STATUS_ADDR + offset ++ + (i << STATUS_ADDR_OFFSET); ++ priv->sensor[i].slope = tsens_8064_slope[i]; ++ INIT_WORK(&priv->sensor[i].notify_work, ++ notify_uspace_tsens_fn); ++ } ++ ++ reg_cntl = SW_RST; ++ ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); ++ if (ret) ++ return ret; ++ ++ reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); ++ reg_cntl &= ~SW_RST; ++ ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, ++ CONFIG_MASK, CONFIG); ++ ++ reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; ++ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ if (ret) ++ return ret; ++ ++ reg_cntl |= EN; ++ ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int calibrate_ipq8064(struct tsens_priv *priv) ++{ ++ int i; ++ char *data, *data_backup; ++ ++ ssize_t num_read = priv->num_sensors; ++ struct tsens_sensor *s = priv->sensor; ++ ++ data = qfprom_read(priv->dev, "calib"); ++ if (IS_ERR(data)) { ++ pr_err("Calibration not found.\n"); ++ return PTR_ERR(data); ++ } ++ ++ data_backup = qfprom_read(priv->dev, "calib_backup"); ++ if (IS_ERR(data_backup)) { ++ pr_err("Backup calibration not found.\n"); ++ return PTR_ERR(data_backup); ++ } ++ ++ for (i = 0; i < num_read; i++) { ++ s[i].calib_data = readb_relaxed(data + i); ++ s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (s[i].calib_data_backup) ++ s[i].calib_data = s[i].calib_data_backup; ++ if (!s[i].calib_data) { ++ pr_err("QFPROM TSENS calibration data not present\n"); ++ return -ENODEV; ++ } ++ s[i].slope = tsens_8064_slope[i]; ++ s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); ++ } ++ ++ hw_init(priv); ++ ++ return 0; ++} ++ ++static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp) ++{ ++ int ret; ++ u32 code, trdy; ++ const struct tsens_sensor *s = &priv->sensor[id]; ++ unsigned long timeout; ++ ++ timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); ++ do { ++ ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); ++ if (ret) ++ return ret; ++ if (!(trdy & TRDY_MASK)) ++ continue; ++ ret = regmap_read(priv->tm_map, s->status, &code); ++ if (ret) ++ return ret; ++ *temp = code_to_degC(code, s); ++ return 0; ++ } while (time_before(jiffies, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++static int set_trip_temp_ipq8064(void *data, int trip, int temp) ++{ ++ unsigned int reg_th, reg_cntl; ++ int ret, code, code_chk, hi_code, lo_code; ++ const struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ ++ code_chk = code = degC_to_code(temp, s); ++ ++ if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE) ++ return -EINVAL; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_cntl); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, ®_th); ++ if (ret) ++ return ret; ++ ++ hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK) ++ >> THRESHOLD_UPPER_LIMIT_SHIFT; ++ lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK) ++ >> THRESHOLD_LOWER_LIMIT_SHIFT; ++ ++ switch (trip) { ++ case TSENS_TRIP_STAGE3: ++ code <<= THRESHOLD_MAX_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_MAX_LIMIT_MASK; ++ break; ++ case TSENS_TRIP_STAGE2: ++ if (code_chk <= lo_code) ++ return -EINVAL; ++ code <<= THRESHOLD_UPPER_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK; ++ break; ++ case TSENS_TRIP_STAGE1: ++ if (code_chk >= hi_code) ++ return -EINVAL; ++ code <<= THRESHOLD_LOWER_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK; ++ break; ++ case TSENS_TRIP_STAGE0: ++ code <<= THRESHOLD_MIN_LIMIT_SHIFT; ++ reg_th &= ~THRESHOLD_MIN_LIMIT_MASK; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ ret = regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_th | code); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int set_trip_activate_ipq8064(void *data, int trip, ++ enum thermal_trip_activation_mode mode) ++{ ++ unsigned int reg_cntl, mask, val; ++ const struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ int ret; ++ ++ if (!priv || trip < 0) ++ return -EINVAL; ++ ++ ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®_cntl); ++ if (ret) ++ return ret; ++ ++ switch (trip) { ++ case TSENS_TRIP_STAGE3: ++ mask = MAX_STATUS_MASK; ++ break; ++ case TSENS_TRIP_STAGE2: ++ mask = UPPER_STATUS_CLR; ++ break; ++ case TSENS_TRIP_STAGE1: ++ mask = LOWER_STATUS_CLR; ++ break; ++ case TSENS_TRIP_STAGE0: ++ mask = MIN_STATUS_MASK; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (mode == THERMAL_TRIP_ACTIVATION_DISABLED) ++ val = reg_cntl | mask; ++ else ++ val = reg_cntl & ~mask; ++ ++ ret = regmap_write(priv->tm_map, STATUS_CNTL_8064, val); ++ if (ret) ++ return ret; ++ ++ /* force memory to sync */ ++ mb(); ++ return 0; ++} ++ ++const struct tsens_ops ops_ipq8064 = { ++ .init = init_ipq8064, ++ .calibrate = calibrate_ipq8064, ++ .get_temp = get_temp_ipq8064, ++ .suspend = suspend_ipq8064, ++ .resume = resume_ipq8064, ++ .set_trip_temp = set_trip_temp_ipq8064, ++ .set_trip_activate = set_trip_activate_ipq8064, ++}; ++ ++const struct tsens_plat_data data_ipq8064 = { ++ .num_sensors = 11, ++ .ops = &ops_ipq8064, ++}; +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -69,8 +69,11 @@ static const struct of_device_id tsens_t + }, { + .compatible = "qcom,tsens-v2", + .data = &data_tsens_v2, ++ }, { ++ .compatible = "qcom,ipq8064-tsens", ++ .data = &data_ipq8064, + }, +- {} ++ {} + }; + MODULE_DEVICE_TABLE(of, tsens_table); + +--- a/drivers/thermal/qcom/tsens.h ++++ b/drivers/thermal/qcom/tsens.h +@@ -324,7 +324,7 @@ extern const struct tsens_plat_data data + extern const struct tsens_plat_data data_8916, data_8974; + + /* TSENS v1 targets */ +-extern const struct tsens_plat_data data_tsens_v1; ++extern const struct tsens_plat_data data_tsens_v1, data_ipq8064; + + /* TSENS v2 targets */ + extern const struct tsens_plat_data data_8996, data_tsens_v2; diff --git a/ipq806x/patches-5.4/0063-2-tsens-support-configurable-interrupts.patch b/ipq806x/patches-5.4/0063-2-tsens-support-configurable-interrupts.patch new file mode 100644 index 0000000..54488f2 --- /dev/null +++ b/ipq806x/patches-5.4/0063-2-tsens-support-configurable-interrupts.patch @@ -0,0 +1,437 @@ +From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001 +From: Rajith Cherian +Date: Wed, 1 Feb 2017 19:00:26 +0530 +Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts + +Provide support for adding configurable high and +configurable low trip temperatures. An interrupts is +also triggerred when these trip points are hit. The +interrupts can be activated or deactivated from sysfs. +This functionality is made available only if +CONFIG_THERMAL_WRITABLE_TRIPS is defined. + +Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934 +Signed-off-by: Rajith Cherian +--- + .../devicetree/bindings/thermal/qcom-tsens.txt | 4 ++ + drivers/thermal/of-thermal.c | 63 ++++++++++++++++++---- + drivers/thermal/qcom/tsens.c | 43 ++++++++++++--- + drivers/thermal/qcom/tsens.h | 11 ++++ + drivers/thermal/thermal_core.c | 44 ++++++++++++++- + include/linux/thermal.h | 14 +++++ + 6 files changed, 162 insertions(+), 17 deletions(-) + +--- a/drivers/thermal/of-thermal.c ++++ b/drivers/thermal/of-thermal.c +@@ -91,7 +91,7 @@ static int of_thermal_get_temp(struct th + { + struct __thermal_zone *data = tz->devdata; + +- if (!data->ops->get_temp) ++ if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EINVAL; + + return data->ops->get_temp(data->sensor_data, temp); +@@ -102,7 +102,8 @@ static int of_thermal_set_trips(struct t + { + struct __thermal_zone *data = tz->devdata; + +- if (!data->ops || !data->ops->set_trips) ++ if (!data->ops || !data->ops->set_trips ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EINVAL; + + return data->ops->set_trips(data->sensor_data, low, high); +@@ -188,6 +189,9 @@ static int of_thermal_set_emul_temp(stru + { + struct __thermal_zone *data = tz->devdata; + ++ if (data->mode == THERMAL_DEVICE_DISABLED) ++ return -EINVAL; ++ + return data->ops->set_emul_temp(data->sensor_data, temp); + } + +@@ -196,7 +200,7 @@ static int of_thermal_get_trend(struct t + { + struct __thermal_zone *data = tz->devdata; + +- if (!data->ops->get_trend) ++ if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EINVAL; + + return data->ops->get_trend(data->sensor_data, trip, trend); +@@ -297,7 +301,9 @@ static int of_thermal_set_mode(struct th + mutex_unlock(&tz->lock); + + data->mode = mode; +- thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); ++ ++ if (mode == THERMAL_DEVICE_ENABLED) ++ thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + return 0; + } +@@ -307,7 +313,8 @@ static int of_thermal_get_trip_type(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + *type = data->trips[trip].type; +@@ -315,12 +322,39 @@ static int of_thermal_get_trip_type(stru + return 0; + } + ++static int of_thermal_activate_trip_type(struct thermal_zone_device *tz, ++ int trip, enum thermal_trip_activation_mode mode) ++{ ++ struct __thermal_zone *data = tz->devdata; ++ ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) ++ return -EDOM; ++ ++ /* ++ * The configurable_hi and configurable_lo trip points can be ++ * activated and deactivated. ++ */ ++ ++ if (data->ops->set_trip_activate) { ++ int ret; ++ ++ ret = data->ops->set_trip_activate(data->sensor_data, ++ trip, mode); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, + int *temp) + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + *temp = data->trips[trip].temperature; +@@ -333,7 +367,8 @@ static int of_thermal_set_trip_temp(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + if (data->ops->set_trip_temp) { +@@ -355,7 +390,8 @@ static int of_thermal_get_trip_hyst(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + *hyst = data->trips[trip].hysteresis; +@@ -368,7 +404,8 @@ static int of_thermal_set_trip_hyst(stru + { + struct __thermal_zone *data = tz->devdata; + +- if (trip >= data->ntrips || trip < 0) ++ if (trip >= data->ntrips || trip < 0 ++ || (data->mode == THERMAL_DEVICE_DISABLED)) + return -EDOM; + + /* thermal framework should take care of data->mask & (1 << trip) */ +@@ -443,6 +480,9 @@ thermal_zone_of_add_sensor(struct device + if (ops->set_emul_temp) + tzd->ops->set_emul_temp = of_thermal_set_emul_temp; + ++ if (ops->set_trip_activate) ++ tzd->ops->set_trip_activate = of_thermal_activate_trip_type; ++ + mutex_unlock(&tzd->lock); + + return tzd; +@@ -765,7 +805,10 @@ static const char * const trip_types[] = + [THERMAL_TRIP_ACTIVE] = "active", + [THERMAL_TRIP_PASSIVE] = "passive", + [THERMAL_TRIP_HOT] = "hot", +- [THERMAL_TRIP_CRITICAL] = "critical", ++ [THERMAL_TRIP_CRITICAL] = "critical_high", ++ [THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi", ++ [THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo", ++ [THERMAL_TRIP_CRITICAL_LOW] = "critical_low", + }; + + /** +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -22,7 +22,7 @@ static int tsens_get_temp(void *data, in + + static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend) + { +- const struct tsens_sensor *s = data; ++ struct tsens_sensor *s = data; + struct tsens_priv *priv = s->priv; + + if (priv->ops->get_trend) +@@ -31,9 +31,10 @@ static int tsens_get_trend(void *data, i + return -ENOTSUPP; + } + +-static int __maybe_unused tsens_suspend(struct device *dev) ++static int __maybe_unused tsens_suspend(void *data) + { +- struct tsens_priv *priv = dev_get_drvdata(dev); ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; + + if (priv->ops && priv->ops->suspend) + return priv->ops->suspend(priv); +@@ -41,9 +42,10 @@ static int __maybe_unused tsens_suspend + return 0; + } + +-static int __maybe_unused tsens_resume(struct device *dev) ++static int __maybe_unused tsens_resume(void *data) + { +- struct tsens_priv *priv = dev_get_drvdata(dev); ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; + + if (priv->ops && priv->ops->resume) + return priv->ops->resume(priv); +@@ -51,6 +53,30 @@ static int __maybe_unused tsens_resume(s + return 0; + } + ++static int __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp) ++{ ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ ++ if (priv->ops && priv->ops->set_trip_temp) ++ return priv->ops->set_trip_temp(s, trip, temp); ++ ++ return 0; ++} ++ ++static int __maybe_unused tsens_activate_trip_type(void *data, int trip, ++ enum thermal_trip_activation_mode mode) ++{ ++ struct tsens_sensor *s = data; ++ struct tsens_priv *priv = s->priv; ++ ++ if (priv->ops && priv->ops->set_trip_activate) ++ return priv->ops->set_trip_activate(s, trip, mode); ++ ++ return 0; ++} ++ ++ + static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume); + + static const struct of_device_id tsens_table[] = { +@@ -80,6 +106,8 @@ MODULE_DEVICE_TABLE(of, tsens_table); + static const struct thermal_zone_of_device_ops tsens_of_ops = { + .get_temp = tsens_get_temp, + .get_trend = tsens_get_trend, ++ .set_trip_temp = tsens_set_trip_temp, ++ .set_trip_activate = tsens_activate_trip_type, + }; + + static int tsens_register(struct tsens_priv *priv) +@@ -123,7 +151,7 @@ static int tsens_probe(struct platform_d + if (id) + data = id->data; + else +- data = &data_8960; ++ return -EINVAL; + + num_sensors = data->num_sensors; + +@@ -144,6 +172,9 @@ static int tsens_probe(struct platform_d + priv->dev = dev; + priv->num_sensors = num_sensors; + priv->ops = data->ops; ++ ++ priv->tsens_irq = platform_get_irq(pdev, 0); ++ + for (i = 0; i < priv->num_sensors; i++) { + if (data->hw_ids) + priv->sensor[i].hw_id = data->hw_ids[i]; +--- a/drivers/thermal/qcom/tsens.h ++++ b/drivers/thermal/qcom/tsens.h +@@ -40,9 +40,12 @@ enum tsens_ver { + struct tsens_sensor { + struct tsens_priv *priv; + struct thermal_zone_device *tzd; ++ struct work_struct notify_work; + int offset; + unsigned int id; + unsigned int hw_id; ++ int calib_data; ++ int calib_data_backup; + int slope; + u32 status; + }; +@@ -57,6 +60,9 @@ struct tsens_sensor { + * @suspend: Function to suspend the tsens device + * @resume: Function to resume the tsens device + * @get_trend: Function to get the thermal/temp trend ++ * @set_trip_temp: Function to set trip temp ++ * @get_trip_temp: Function to get trip temp ++ * @set_trip_activate: Function to activate trip points + */ + struct tsens_ops { + /* mandatory callbacks */ +@@ -69,6 +75,9 @@ struct tsens_ops { + int (*suspend)(struct tsens_priv *priv); + int (*resume)(struct tsens_priv *priv); + int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend); ++ int (*set_trip_temp)(void *data, int trip, int temp); ++ int (*set_trip_activate)(void *data, int trip, ++ enum thermal_trip_activation_mode mode); + }; + + #define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \ +@@ -300,6 +309,7 @@ struct tsens_context { + struct tsens_priv { + struct device *dev; + u32 num_sensors; ++ u32 tsens_irq; + struct regmap *tm_map; + struct regmap *srot_map; + u32 tm_offset; +@@ -308,6 +318,7 @@ struct tsens_priv { + const struct tsens_features *feat; + const struct reg_field *fields; + const struct tsens_ops *ops; ++ struct work_struct tsens_work; + struct tsens_sensor sensor[0]; + }; + +--- a/drivers/thermal/thermal_sysfs.c ++++ b/drivers/thermal/thermal_sysfs.c +@@ -113,12 +113,48 @@ trip_point_type_show(struct device *dev, + return sprintf(buf, "passive\n"); + case THERMAL_TRIP_ACTIVE: + return sprintf(buf, "active\n"); ++ case THERMAL_TRIP_CONFIGURABLE_HI: ++ return sprintf(buf, "configurable_hi\n"); ++ case THERMAL_TRIP_CONFIGURABLE_LOW: ++ return sprintf(buf, "configurable_low\n"); ++ case THERMAL_TRIP_CRITICAL_LOW: ++ return sprintf(buf, "critical_low\n"); + default: + return sprintf(buf, "unknown\n"); + } + } + + static ssize_t ++trip_point_type_activate(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct thermal_zone_device *tz = to_thermal_zone(dev); ++ int trip, ret; ++ char *enabled = "enabled"; ++ char *disabled = "disabled"; ++ ++ if (!tz->ops->set_trip_activate) ++ return -EPERM; ++ ++ if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) ++ return -EINVAL; ++ ++ if (!strncmp(buf, enabled, strlen(enabled))) ++ ret = tz->ops->set_trip_activate(tz, trip, ++ THERMAL_TRIP_ACTIVATION_ENABLED); ++ else if (!strncmp(buf, disabled, strlen(disabled))) ++ ret = tz->ops->set_trip_activate(tz, trip, ++ THERMAL_TRIP_ACTIVATION_DISABLED); ++ else ++ ret = -EINVAL; ++ ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static ssize_t + trip_point_temp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) + { +@@ -559,6 +595,12 @@ static int create_trip_attrs(struct ther + tz->trip_type_attrs[indx].attr.show = trip_point_type_show; + attrs[indx] = &tz->trip_type_attrs[indx].attr.attr; + ++ if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) { ++ tz->trip_type_attrs[indx].attr.store ++ = trip_point_type_activate; ++ tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR; ++ } ++ + /* create trip temp attribute */ + snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH, + "trip_point_%d_temp", indx); +--- a/include/linux/thermal.h ++++ b/include/linux/thermal.h +@@ -63,11 +63,19 @@ enum thermal_device_mode { + THERMAL_DEVICE_ENABLED, + }; + ++enum thermal_trip_activation_mode { ++ THERMAL_TRIP_ACTIVATION_DISABLED = 0, ++ THERMAL_TRIP_ACTIVATION_ENABLED, ++}; ++ + enum thermal_trip_type { + THERMAL_TRIP_ACTIVE = 0, + THERMAL_TRIP_PASSIVE, + THERMAL_TRIP_HOT, + THERMAL_TRIP_CRITICAL, ++ THERMAL_TRIP_CONFIGURABLE_HI, ++ THERMAL_TRIP_CONFIGURABLE_LOW, ++ THERMAL_TRIP_CRITICAL_LOW, + }; + + enum thermal_trend { +@@ -105,6 +113,8 @@ struct thermal_zone_device_ops { + enum thermal_trip_type *); + int (*get_trip_temp) (struct thermal_zone_device *, int, int *); + int (*set_trip_temp) (struct thermal_zone_device *, int, int); ++ int (*set_trip_activate) (struct thermal_zone_device *, int, ++ enum thermal_trip_activation_mode); + int (*get_trip_hyst) (struct thermal_zone_device *, int, int *); + int (*set_trip_hyst) (struct thermal_zone_device *, int, int); + int (*get_crit_temp) (struct thermal_zone_device *, int *); +@@ -349,6 +359,8 @@ struct thermal_genl_event { + * temperature. + * @set_trip_temp: a pointer to a function that sets the trip temperature on + * hardware. ++ * @activate_trip_type: a pointer to a function to enable/disable trip ++ * temperature interrupts + */ + struct thermal_zone_of_device_ops { + int (*get_temp)(void *, int *); +@@ -356,6 +368,8 @@ struct thermal_zone_of_device_ops { + int (*set_trips)(void *, int, int); + int (*set_emul_temp)(void *, int); + int (*set_trip_temp)(void *, int, int); ++ int (*set_trip_activate)(void *, int, ++ enum thermal_trip_activation_mode); + }; + + /** diff --git a/ipq806x/patches-5.4/0063-3-tsens-fix-kernel-5_4.patch b/ipq806x/patches-5.4/0063-3-tsens-fix-kernel-5_4.patch new file mode 100644 index 0000000..6c056db --- /dev/null +++ b/ipq806x/patches-5.4/0063-3-tsens-fix-kernel-5_4.patch @@ -0,0 +1,68 @@ +--- a/drivers/thermal/qcom/tsens-ipq8064.c ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include "tsens.h" +@@ -320,15 +321,42 @@ static void hw_init(struct tsens_priv *p + INIT_WORK(&priv->tsens_work, tsens_scheduler_fn); + } + ++static const struct regmap_config tsens_config = { ++ .name = "tm", ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++}; ++ + static int init_ipq8064(struct tsens_priv *priv) + { +- int ret, i; ++ struct device *dev = priv->dev; + u32 reg_cntl, offset = 0; ++ struct resource *res; ++ resource_size_t size; ++ void __iomem *base; ++ int ret, i; ++ struct platform_device *op = of_find_device_by_node(priv->dev->of_node); ++ ++ if (!op) ++ return -EINVAL; + +- init_common(priv); +- if (!priv->tm_map) +- return -ENODEV; ++ /* old DTs where SROT and TM were in a contiguous 2K block */ ++ priv->tm_offset = 0x1000; + ++ res = platform_get_resource(op, IORESOURCE_MEM, 0); ++ size = resource_size(res); ++ base = devm_ioremap(&op->dev, res->start, size); ++ if (IS_ERR(base)) { ++ ret = PTR_ERR(base); ++ goto err_put_device; ++ } ++ ++ priv->tm_map = devm_regmap_init_mmio(dev, base, &tsens_config); ++ if (IS_ERR(priv->tm_map)) { ++ ret = PTR_ERR(priv->tm_map); ++ goto err_put_device; ++ } + /* + * The status registers for each sensor are discontiguous + * because some SoCs have 5 sensors while others have more +@@ -367,6 +395,10 @@ static int init_ipq8064(struct tsens_pri + return ret; + + return 0; ++ ++err_put_device: ++ put_device(&op->dev); ++ return ret; + } + + static int calibrate_ipq8064(struct tsens_priv *priv) diff --git a/ipq806x/patches-5.4/0063-4-ip806x-tsense-rework-driver.patch b/ipq806x/patches-5.4/0063-4-ip806x-tsense-rework-driver.patch new file mode 100644 index 0000000..67fc8db --- /dev/null +++ b/ipq806x/patches-5.4/0063-4-ip806x-tsense-rework-driver.patch @@ -0,0 +1,107 @@ +--- a/drivers/thermal/qcom/tsens-ipq8064.c ++++ b/drivers/thermal/qcom/tsens-ipq8064.c +@@ -13,10 +13,12 @@ + */ + + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -211,9 +213,8 @@ static void tsens_scheduler_fn(struct wo + struct tsens_priv *priv = container_of(work, struct tsens_priv, + tsens_work); + unsigned int threshold, threshold_low, code, reg, sensor, mask; +- unsigned int sensor_addr; + bool upper_th_x, lower_th_x; +- int adc_code, ret; ++ int ret; + + ret = regmap_read(priv->tm_map, STATUS_CNTL_8064, ®); + if (ret) +@@ -262,9 +263,8 @@ static void tsens_scheduler_fn(struct wo + if (upper_th_x || lower_th_x) { + /* Notify user space */ + schedule_work(&priv->sensor[0].notify_work); +- regmap_read(priv->tm_map, sensor_addr, &adc_code); + pr_debug("Trigger (%d degrees) for sensor %d\n", +- code_to_degC(adc_code, &priv->sensor[0]), 0); ++ code_to_degC(code, &priv->sensor[0]), 0); + } + } + regmap_write(priv->tm_map, STATUS_CNTL_8064, reg & mask); +@@ -404,40 +404,55 @@ err_put_device: + static int calibrate_ipq8064(struct tsens_priv *priv) + { + int i; +- char *data, *data_backup; +- ++ int ret = 0; ++ u8 *data, *data_backup; ++ struct device *dev = priv->dev; + ssize_t num_read = priv->num_sensors; + struct tsens_sensor *s = priv->sensor; + +- data = qfprom_read(priv->dev, "calib"); ++ data = qfprom_read(dev, "calib"); + if (IS_ERR(data)) { +- pr_err("Calibration not found.\n"); +- return PTR_ERR(data); ++ ret = PTR_ERR(data); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Calibration not found."); ++ goto exit; + } + +- data_backup = qfprom_read(priv->dev, "calib_backup"); ++ data_backup = qfprom_read(dev, "calib_backup"); + if (IS_ERR(data_backup)) { +- pr_err("Backup calibration not found.\n"); +- return PTR_ERR(data_backup); ++ ret = PTR_ERR(data_backup); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "Backup Calibration not found."); ++ goto free_data; + } + + for (i = 0; i < num_read; i++) { + s[i].calib_data = readb_relaxed(data + i); +- s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data) { ++ s[i].calib_data_backup = readb_relaxed(data_backup + i); ++ ++ if (!s[i].calib_data_backup) { ++ dev_err(dev, "QFPROM TSENS calibration data not present"); ++ ret = -ENODEV; ++ goto free_backup; ++ } + +- if (s[i].calib_data_backup) + s[i].calib_data = s[i].calib_data_backup; +- if (!s[i].calib_data) { +- pr_err("QFPROM TSENS calibration data not present\n"); +- return -ENODEV; + } ++ + s[i].slope = tsens_8064_slope[i]; + s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope); + } + + hw_init(priv); + +- return 0; ++free_backup: ++ kfree(data_backup); ++free_data: ++ kfree(data); ++exit: ++ return ret; + } + + static int get_temp_ipq8064(struct tsens_priv *priv, int id, int *temp) diff --git a/ipq806x/patches-5.4/0065-arm-override-compiler-flags.patch b/ipq806x/patches-5.4/0065-arm-override-compiler-flags.patch new file mode 100644 index 0000000..0d2a427 --- /dev/null +++ b/ipq806x/patches-5.4/0065-arm-override-compiler-flags.patch @@ -0,0 +1,21 @@ +From 4d8e29642661397a339ac3485f212c6360445421 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:33:32 +0100 +Subject: [PATCH 65/69] arm: override compiler flags + +Signed-off-by: John Crispin +--- + arch/arm/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -67,7 +67,7 @@ KBUILD_CFLAGS += $(call cc-option,-fno-i + # macro, but instead defines a whole series of macros which makes + # testing for a specific architecture or later rather impossible. + arch-$(CONFIG_CPU_32v7M) =-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m +-arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a) ++arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-a15 + arch-$(CONFIG_CPU_32v6) =-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6) + # Only override the compiler option if ARMv6. The ARMv6K extensions are + # always available in ARMv7 diff --git a/ipq806x/patches-5.4/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/ipq806x/patches-5.4/0067-generic-Mangle-bootloader-s-kernel-arguments.patch new file mode 100644 index 0000000..33c77fb --- /dev/null +++ b/ipq806x/patches-5.4/0067-generic-Mangle-bootloader-s-kernel-arguments.patch @@ -0,0 +1,210 @@ +From 71270226b14733a4b1f2cde58ea9265caa50b38d Mon Sep 17 00:00:00 2001 +From: Adrian Panella +Date: Thu, 9 Mar 2017 09:37:17 +0100 +Subject: [PATCH 67/69] generic: Mangle bootloader's kernel arguments + +The command-line arguments provided by the boot loader will be +appended to a new device tree property: bootloader-args. +If there is a property "append-rootblock" in DT under /chosen +and a root= option in bootloaders command line it will be parsed +and added to DT bootargs with the form: XX. +Only command line ATAG will be processed, the rest of the ATAGs +sent by bootloader will be ignored. +This is usefull in dual boot systems, to get the current root partition +without afecting the rest of the system. + +Signed-off-by: Adrian Panella +--- + arch/arm/Kconfig | 11 +++++ + arch/arm/boot/compressed/atags_to_fdt.c | 72 ++++++++++++++++++++++++++++++++- + init/main.c | 16 ++++++++ + 3 files changed, 98 insertions(+), 1 deletion(-) + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1828,6 +1828,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN + The command-line arguments provided by the boot loader will be + appended to the the device tree bootargs property. + ++config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ bool "Append rootblock parsing bootloader's kernel arguments" ++ help ++ The command-line arguments provided by the boot loader will be ++ appended to a new device tree property: bootloader-args. ++ If there is a property "append-rootblock" in DT under /chosen ++ and a root= option in bootloaders command line it will be parsed ++ and added to DT bootargs with the form: XX. ++ Only command line ATAG will be processed, the rest of the ATAGs ++ sent by bootloader will be ignored. ++ + endchoice + + config CMDLINE +--- a/arch/arm/boot/compressed/atags_to_fdt.c ++++ b/arch/arm/boot/compressed/atags_to_fdt.c +@@ -4,6 +4,8 @@ + + #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND) + #define do_extend_cmdline 1 ++#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#define do_extend_cmdline 1 + #else + #define do_extend_cmdline 0 + #endif +@@ -67,6 +69,80 @@ static uint32_t get_cell_size(const void + return cell_size; + } + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++/** ++ * taken from arch/x86/boot/string.c ++ * local_strstr - Find the first substring in a %NUL terminated string ++ * @s1: The string to be searched ++ * @s2: The string to search for ++ */ ++static char *local_strstr(const char *s1, const char *s2) ++{ ++ size_t l1, l2; ++ ++ l2 = strlen(s2); ++ if (!l2) ++ return (char *)s1; ++ l1 = strlen(s1); ++ while (l1 >= l2) { ++ l1--; ++ if (!memcmp(s1, s2, l2)) ++ return (char *)s1; ++ s1++; ++ } ++ return NULL; ++} ++ ++static char *append_rootblock(char *dest, const char *str, int len, void *fdt) ++{ ++ char *ptr, *end, *tmp; ++ char *root="root="; ++ char *find_rootblock; ++ int i, l; ++ const char *rootblock; ++ ++ find_rootblock = getprop(fdt, "/chosen", "find-rootblock", &l); ++ if(!find_rootblock) ++ find_rootblock = root; ++ ++ //ARM doesn't have __HAVE_ARCH_STRSTR, so it was copied from x86 ++ ptr = local_strstr(str, find_rootblock); ++ ++ if(!ptr) ++ return dest; ++ ++ end = strchr(ptr, ' '); ++ end = end ? (end - 1) : (strchr(ptr, 0) - 1); ++ ++ // Some boards ubi.mtd=XX,ZZZZ, so let's check for '," too. ++ tmp = strchr(ptr, ','); ++ ++ if(tmp) ++ end = end < tmp ? end : tmp - 1; ++ ++ //find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX | ubi.mtd=XX,ZZZZ ) ++ for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++); ++ ptr = end + 1; ++ ++ /* if append-rootblock property is set use it to append to command line */ ++ rootblock = getprop(fdt, "/chosen", "append-rootblock", &l); ++ if(rootblock != NULL) { ++ if(*dest != ' ') { ++ *dest = ' '; ++ dest++; ++ len++; ++ } ++ if (len + l + i <= COMMAND_LINE_SIZE) { ++ memcpy(dest, rootblock, l); ++ dest += l - 1; ++ memcpy(dest, ptr, i); ++ dest += i; ++ } ++ } ++ return dest; ++} ++#endif ++ + static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) + { + char cmdline[COMMAND_LINE_SIZE]; +@@ -86,12 +162,21 @@ static void merge_fdt_bootargs(void *fdt + + /* and append the ATAG_CMDLINE */ + if (fdt_cmdline) { ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //save original bootloader args ++ //and append ubi.mtd with root partition number to current cmdline ++ setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline); ++ ptr = append_rootblock(ptr, fdt_cmdline, len, fdt); ++ ++#else + len = strlen(fdt_cmdline); + if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) { + *ptr++ = ' '; + memcpy(ptr, fdt_cmdline, len); + ptr += len; + } ++#endif + } + *ptr = '\0'; + +@@ -166,7 +251,9 @@ int atags_to_fdt(void *atag_list, void * + else + setprop_string(fdt, "/chosen", "bootargs", + atag->u.cmdline.cmdline); +- } else if (atag->hdr.tag == ATAG_MEM) { ++ } ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ else if (atag->hdr.tag == ATAG_MEM) { + if (memcount >= sizeof(mem_reg_property)/4) + continue; + if (!atag->u.mem.size) +@@ -210,6 +297,10 @@ int atags_to_fdt(void *atag_list, void * + setprop(fdt, "/memory", "reg", mem_reg_property, + 4 * memcount * memsize); + } ++#else ++ ++ } ++#endif + + return fdt_pack(fdt); + } +--- a/init/main.c ++++ b/init/main.c +@@ -104,6 +104,10 @@ + #define CREATE_TRACE_POINTS + #include + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#include ++#endif ++ + static int kernel_init(void *); + + extern void init_IRQ(void); +@@ -633,6 +637,18 @@ asmlinkage __visible void __init start_k + pr_notice("Kernel command line: %s\n", boot_command_line); + /* parameters may set static keys */ + jump_label_init(); ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //Show bootloader's original command line for reference ++ if(of_chosen) { ++ const char *prop = of_get_property(of_chosen, "bootloader-args", NULL); ++ if(prop) ++ pr_notice("Bootloader command line (ignored): %s\n", prop); ++ else ++ pr_notice("Bootloader command line not present\n"); ++ } ++#endif ++ + parse_early_param(); + after_dashes = parse_args("Booting kernel", + static_command_line, __start___param, diff --git a/ipq806x/patches-5.4/0069-arm-boot-add-dts-files.patch b/ipq806x/patches-5.4/0069-arm-boot-add-dts-files.patch new file mode 100644 index 0000000..7cb1d9c --- /dev/null +++ b/ipq806x/patches-5.4/0069-arm-boot-add-dts-files.patch @@ -0,0 +1,39 @@ +From 8f68331e14dff9a101f2d0e1d6bec84a031f27ee Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 11:03:18 +0100 +Subject: [PATCH 69/69] arm: boot: add dts files + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/Makefile | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -842,7 +842,26 @@ dtb-$(CONFIG_ARCH_QCOM) += \ + qcom-ipq4019-ap.dk04.1-c3.dtb \ + qcom-ipq4019-ap.dk07.1-c1.dtb \ + qcom-ipq4019-ap.dk07.1-c2.dtb \ ++ qcom-ipq8062-wg2600hp3.dtb \ + qcom-ipq8064-ap148.dtb \ ++ qcom-ipq8064-c2600.dtb \ ++ qcom-ipq8064-d7800.dtb \ ++ qcom-ipq8064-db149.dtb \ ++ qcom-ipq8064-ap161.dtb \ ++ qcom-ipq8064-ea7500-v1.dtb \ ++ qcom-ipq8064-ea8500.dtb \ ++ qcom-ipq8064-g10.dtb \ ++ qcom-ipq8064-r7500.dtb \ ++ qcom-ipq8064-r7500v2.dtb \ ++ qcom-ipq8064-unifi-ac-hd.dtb \ ++ qcom-ipq8064-wg2600hp.dtb \ ++ qcom-ipq8064-wpq864.dtb \ ++ qcom-ipq8064-wxr-2533dhp.dtb \ ++ qcom-ipq8065-nbg6817.dtb \ ++ qcom-ipq8065-r7800.dtb \ ++ qcom-ipq8065-rt4230w-rev6.dtb \ ++ qcom-ipq8068-ecw5410.dtb \ ++ qcom-ipq8068-ssw2ac2600.dtb \ + qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ + qcom-msm8974-fairphone-fp2.dtb \ diff --git a/ipq806x/patches-5.4/0072-add-ipq806x-with-no-clocks.patch b/ipq806x/patches-5.4/0072-add-ipq806x-with-no-clocks.patch new file mode 100644 index 0000000..b7cebd9 --- /dev/null +++ b/ipq806x/patches-5.4/0072-add-ipq806x-with-no-clocks.patch @@ -0,0 +1,10 @@ +--- a/drivers/firmware/qcom_scm.c ++++ b/drivers/firmware/qcom_scm.c +@@ -598,6 +598,7 @@ static const struct of_device_id qcom_sc + SCM_HAS_BUS_CLK) + }, + { .compatible = "qcom,scm-ipq4019" }, ++ { .compatible = "qcom,scm-ipq806x" }, + { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK }, + { .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK }, + { .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK | diff --git a/ipq806x/patches-5.4/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch b/ipq806x/patches-5.4/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch new file mode 100644 index 0000000..0dc9deb --- /dev/null +++ b/ipq806x/patches-5.4/080-v5.7-ARM-dts-qcom-add-gpio-ranges-property.patch @@ -0,0 +1,70 @@ +From patchwork Mon May 21 20:57:38 2018 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v5,3/4] ARM: dts: qcom: add gpio-ranges property +X-Patchwork-Submitter: Christian Lamparter +X-Patchwork-Id: 917856 +Message-Id: <0ae3376606a89bcdf3fe753a5c967f7103699e09.1526935804.git.chunkeey@gmail.com> +To: linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org +Cc: Bjorn Andersson , + Linus Walleij , + Stephen Boyd , David Brown , + Rob Herring , Mark Rutland , + Andy Gross , + Sven Eckelmann +Date: Mon, 21 May 2018 22:57:38 +0200 +From: Christian Lamparter +List-Id: + +This patch adds the gpio-ranges property to almost all of +the Qualcomm ARM platforms that utilize the pinctrl-msm +framework. + +The gpio-ranges property is part of the gpiolib subsystem. +As a result, the binding text is available in section +"2.1 gpio- and pin-controller interaction" of +Documentation/devicetree/bindings/gpio/gpio.txt + +For more information please see the patch titled: +"pinctrl: msm: fix gpio-hog related boot issues" from +this series. + +Reported-by: Sven Eckelmann +Tested-by: Sven Eckelmann [ipq4019] +Reviewed-by: Bjorn Andersson +Signed-off-by: Christian Lamparter +Reviewed-by: Linus Walleij +--- +To help with git bisect, the DT update patch has been intentionally +placed after the "pinctrl: msm: fix gpio-hog related boot issues". +Otherwise - if the order was reveresed - and bisect decides to split +between these two patches, the gpiochip_add_pin_ranges() function +will be executed twice with the same parameters for the same pinctrl. +--- + arch/arm/boot/dts/qcom-apq8064.dtsi | 1 + + arch/arm/boot/dts/qcom-apq8084.dtsi | 1 + + arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 + + arch/arm/boot/dts/qcom-ipq8064.dtsi | 1 + + arch/arm/boot/dts/qcom-mdm9615.dtsi | 1 + + arch/arm/boot/dts/qcom-msm8660.dtsi | 1 + + arch/arm/boot/dts/qcom-msm8960.dtsi | 1 + + arch/arm/boot/dts/qcom-msm8974.dtsi | 1 + + arch/arm64/boot/dts/qcom/ipq8074.dtsi | 3 ++- + arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8992.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8994.dtsi | 1 + + arch/arm64/boot/dts/qcom/msm8996.dtsi | 1 + + 13 files changed, 14 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -119,6 +119,7 @@ + reg = <0x800000 0x4000>; + + gpio-controller; ++ gpio-ranges = <&qcom_pinmux 0 0 69>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; diff --git a/ipq806x/patches-5.4/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch b/ipq806x/patches-5.4/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch new file mode 100644 index 0000000..f5483ac --- /dev/null +++ b/ipq806x/patches-5.4/081-v5.8-ARM-dts-qcom-add-scm-definition-to-ipq806x.patch @@ -0,0 +1,29 @@ +From 51befb888f62b1a62434fb4b82328d698a30f9de Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 19 Mar 2020 23:44:24 +0100 +Subject: ARM: dts: qcom: add scm definition to ipq806x + +Add missing scm definition for ipq806x soc + +Signed-off-by: Ansuel Smith +Link: https://lore.kernel.org/r/20200319224424.18473-1-ansuelsmth@gmail.com +Signed-off-by: Bjorn Andersson +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -93,6 +93,12 @@ + }; + }; + ++ firmware { ++ scm { ++ compatible = "qcom,scm-ipq806x", "qcom,scm"; ++ }; ++ }; ++ + soc: soc { + #address-cells = <1>; + #size-cells = <1>; diff --git a/ipq806x/patches-5.4/082-ipq8064-dtsi-tweaks.patch b/ipq806x/patches-5.4/082-ipq8064-dtsi-tweaks.patch new file mode 100644 index 0000000..568ca5b --- /dev/null +++ b/ipq806x/patches-5.4/082-ipq8064-dtsi-tweaks.patch @@ -0,0 +1,130 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -20,7 +20,7 @@ + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "qcom,krait"; + enable-method = "qcom,kpss-acc-v1"; + device_type = "cpu"; +@@ -30,7 +30,7 @@ + qcom,saw = <&saw0>; + }; + +- cpu@1 { ++ cpu1: cpu@1 { + compatible = "qcom,krait"; + enable-method = "qcom,kpss-acc-v1"; + device_type = "cpu"; +@@ -67,7 +67,7 @@ + no-map; + }; + +- smem@41000000 { ++ smem: smem@41000000 { + reg = <0x41000000 0x200000>; + no-map; + }; +@@ -155,6 +155,7 @@ + function = "pcie3_rst"; + drive-strength = <12>; + bias-disable; ++ output-low; + }; + }; + +@@ -219,21 +220,23 @@ + acc0: clock-controller@2088000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02088000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu0_aux"; + }; + + acc1: clock-controller@2098000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02098000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu1_aux"; + }; + + saw0: regulator@2089000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + + saw1: regulator@2099000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02099000 0x1000>, <0x02009000 0x1000>; + regulator; + }; +@@ -251,7 +254,7 @@ + + syscon-tcsr = <&tcsr>; + +- serial@12490000 { ++ gsbi2_serial: serial@12490000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x12490000 0x1000>, + <0x12480000 0x1000>; +@@ -326,7 +329,7 @@ + + syscon-tcsr = <&tcsr>; + +- serial@1a240000 { ++ gsbi5_serial: serial@1a240000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x1a240000 0x1000>, + <0x1a200000 0x1000>; +@@ -397,7 +400,7 @@ + status = "disabled"; + }; + +- sata@29000000 { ++ sata: sata@29000000 { + compatible = "qcom,ipq806x-ahci", "generic-ahci"; + reg = <0x29000000 0x180>; + +@@ -430,6 +433,7 @@ + reg = <0x00900000 0x4000>; + #clock-cells = <1>; + #reset-cells = <1>; ++ #power-domain-cells = <1>; + }; + + tcsr: syscon@1a400000 { +@@ -625,13 +629,13 @@ + qcom,ee = <0>; + }; + +- amba { +- compatible = "simple-bus"; ++ amba: amba { ++ compatible = "arm,amba-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + +- sdcc@12400000 { ++ sdcc1: sdcc@12400000 { + status = "disabled"; + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; +@@ -645,13 +649,12 @@ + non-removable; + cap-sd-highspeed; + cap-mmc-highspeed; +- mmc-ddr-1_8v; + vmmc-supply = <&vsdcc_fixed>; + dmas = <&sdcc1bam 2>, <&sdcc1bam 1>; + dma-names = "tx", "rx"; + }; + +- sdcc@12180000 { ++ sdcc3: sdcc@12180000 { + compatible = "arm,pl18x", "arm,primecell"; + arm,primecell-periphid = <0x00051180>; + status = "disabled"; diff --git a/ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch b/ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch new file mode 100644 index 0000000..ccfae25 --- /dev/null +++ b/ipq806x/patches-5.4/083-ipq8064-dtsi-additions.patch @@ -0,0 +1,1024 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -8,6 +8,8 @@ + #include + #include + #include ++#include ++#include + + / { + #address-cells = <1>; +@@ -28,6 +30,16 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc0>; + qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2a>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; + }; + + cpu1: cpu@1 { +@@ -38,11 +50,476 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc1>; + qcom,saw = <&saw1>; ++ clocks = <&kraitcc 1>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2b>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; + }; + +- L2: l2-cache { +- compatible = "cache"; +- cache-level = <2>; ++ idle-states { ++ CPU_SPC: spc { ++ compatible = "qcom,idle-state-spc", "arm,idle-state"; ++ status = "disabled"; ++ entry-latency-us = <400>; ++ exit-latency-us = <900>; ++ min-residency-us = <3000>; ++ }; ++ }; ++ }; ++ ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1000000>; ++ opp-microvolt-speed0-pvs1-v0 = <925000>; ++ opp-microvolt-speed0-pvs2-v0 = <875000>; ++ opp-microvolt-speed0-pvs3-v0 = <800000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <975000>; ++ opp-microvolt-speed0-pvs2-v0 = <925000>; ++ opp-microvolt-speed0-pvs3-v0 = <850000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1100000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000>; ++ opp-microvolt-speed0-pvs2-v0 = <995000>; ++ opp-microvolt-speed0-pvs3-v0 = <900000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1150000>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000>; ++ opp-microvolt-speed0-pvs3-v0 = <950000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1200000>; ++ opp-microvolt-speed0-pvs1-v0 = <1125000>; ++ opp-microvolt-speed0-pvs2-v0 = <1075000>; ++ opp-microvolt-speed0-pvs3-v0 = <1000000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1250000>; ++ opp-microvolt-speed0-pvs1-v0 = <1175000>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000>; ++ opp-microvolt-speed0-pvs3-v0 = <1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ thermal-zones { ++ tsens_tz_sensor0 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 0>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor1 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 1>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor2 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 2>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor3 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 3>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor4 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 4>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor5 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 5>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor6 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 6>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor7 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 7>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor8 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 8>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor9 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 9>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; ++ }; ++ ++ tsens_tz_sensor10 { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&tsens 10>; ++ ++ trips { ++ cpu-critical-hi { ++ temperature = <125000>; ++ hysteresis = <2000>; ++ type = "critical_high"; ++ }; ++ ++ cpu-config-hi { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "configurable_hi"; ++ }; ++ ++ cpu-config-lo { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "configurable_lo"; ++ }; ++ ++ cpu-critical-low { ++ temperature = <0>; ++ hysteresis = <2000>; ++ type = "critical_low"; ++ }; ++ }; + }; + }; + +@@ -93,6 +570,15 @@ + }; + }; + ++ fab-scaling { ++ compatible = "qcom,fab-scaling"; ++ clocks = <&rpmcc RPM_APPS_FABRIC_A_CLK>, <&rpmcc RPM_EBI1_A_CLK>; ++ clock-names = "apps-fab-clk", "ddr-fab-clk"; ++ fab_freq_high = <533000000>; ++ fab_freq_nominal = <400000000>; ++ cpu_freq_threshold = <1000000000>; ++ }; ++ + firmware { + scm { + compatible = "qcom,scm-ipq806x", "qcom,scm"; +@@ -120,6 +606,95 @@ + reg-names = "lpass-lpaif"; + }; + ++ L2: l2-cache { ++ compatible = "qcom,krait-cache", "cache"; ++ cache-level = <2>; ++ qcom,saw = <&saw_l2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ l2-supply = <&smb208_s1a>; ++ operating-points-v2 = <&opp_table_l2>; ++ }; ++ ++ qfprom: qfprom@700000 { ++ compatible = "qcom,qfprom", "syscon"; ++ reg = <0x700000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ status = "okay"; ++ tsens_calib: calib@400 { ++ reg = <0x400 0xb>; ++ }; ++ tsens_backup: backup@410 { ++ reg = <0x410 0xb>; ++ }; ++ speedbin_efuse: speedbin@0c0 { ++ reg = <0x0c0 0x4>; ++ }; ++ }; ++ ++ rpm: rpm@108000 { ++ compatible = "qcom,rpm-ipq8064"; ++ reg = <0x108000 0x1000>; ++ qcom,ipc = <&l2cc 0x8 2>; ++ ++ interrupts = , ++ , ++ ; ++ interrupt-names = "ack", "err", "wakeup"; ++ ++ clocks = <&gcc RPM_MSG_RAM_H_CLK>; ++ clock-names = "ram"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rpmcc: clock-controller { ++ compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc"; ++ #clock-cells = <1>; ++ }; ++ ++ regulators { ++ compatible = "qcom,rpm-smb208-regulators"; ++ ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2a: s2a { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2b: s2b { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ }; ++ }; ++ ++ rng@1a500000 { ++ compatible = "qcom,prng"; ++ reg = <0x1a500000 0x200>; ++ clocks = <&gcc PRNG_CLK>; ++ clock-names = "core"; ++ }; ++ + qcom_pinmux: pinmux@800000 { + compatible = "qcom,ipq8064-pinctrl"; + reg = <0x800000 0x4000>; +@@ -159,6 +734,15 @@ + }; + }; + ++ i2c4_pins: i2c4_pinmux { ++ mux { ++ pins = "gpio12", "gpio13"; ++ function = "gsbi4"; ++ drive-strength = <12>; ++ bias-disable; ++ }; ++ }; ++ + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; +@@ -168,6 +752,53 @@ + }; + }; + ++ nand_pins: nand_pins { ++ disable { ++ pins = "gpio34", "gpio35", "gpio36", ++ "gpio37", "gpio38"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-disable; ++ }; ++ ++ pullups { ++ pins = "gpio39"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-pull-up; ++ }; ++ ++ hold { ++ pins = "gpio40", "gpio41", "gpio42", ++ "gpio43", "gpio44", "gpio45", ++ "gpio46", "gpio47"; ++ function = "nand"; ++ drive-strength = <10>; ++ bias-bus-hold; ++ }; ++ }; ++ ++ mdio0_pins: mdio0_pins { ++ mux { ++ pins = "gpio0", "gpio1"; ++ function = "mdio"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; ++ ++ rgmii2_pins: rgmii2_pins { ++ mux { ++ pins = "gpio27", "gpio28", "gpio29", ++ "gpio30", "gpio31", "gpio32", ++ "gpio51", "gpio52", "gpio59", ++ "gpio60", "gpio61", "gpio62"; ++ function = "rgmii2"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; ++ + leds_pins: leds_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", +@@ -229,6 +860,17 @@ + clock-output-names = "acpu1_aux"; + }; + ++ l2cc: clock-controller@2011000 { ++ compatible = "qcom,kpss-gcc", "syscon"; ++ reg = <0x2011000 0x1000>; ++ clock-output-names = "acpu_l2_aux"; ++ }; ++ ++ kraitcc: clock-controller { ++ compatible = "qcom,krait-cc-v1"; ++ #clock-cells = <1>; ++ }; ++ + saw0: regulator@2089000 { + compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; +@@ -241,6 +883,17 @@ + regulator; + }; + ++ saw_l2: regulator@02012000 { ++ compatible = "qcom,saw2", "syscon"; ++ reg = <0x02012000 0x1000>; ++ regulator; ++ }; ++ ++ sic_non_secure: sic-non-secure@12100000 { ++ compatible = "syscon"; ++ reg = <0x12100000 0x10000>; ++ }; ++ + gsbi2: gsbi@12480000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <2>; +@@ -436,6 +1089,15 @@ + #power-domain-cells = <1>; + }; + ++ tsens: thermal-sensor@900000 { ++ compatible = "qcom,ipq8064-tsens"; ++ reg = <0x900000 0x3680>; ++ nvmem-cells = <&tsens_calib>, <&tsens_backup>; ++ nvmem-cell-names = "calib", "calib_backup"; ++ interrupts = ; ++ #thermal-sensor-cells = <1>; ++ }; ++ + tcsr: syscon@1a400000 { + compatible = "qcom,tcsr-ipq8064", "syscon"; + reg = <0x1a400000 0x100>; +@@ -448,6 +1110,95 @@ + #reset-cells = <1>; + }; + ++ sfpb_mutex_block: syscon@1200600 { ++ compatible = "syscon"; ++ reg = <0x01200600 0x100>; ++ }; ++ ++ hs_phy_0: hs_phy_0 { ++ compatible = "qcom,ipq806x-usb-phy-hs"; ++ reg = <0x110f8800 0x30>; ++ clocks = <&gcc USB30_0_UTMI_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ ss_phy_0: ss_phy_0 { ++ compatible = "qcom,ipq806x-usb-phy-ss"; ++ reg = <0x110f8830 0x30>; ++ clocks = <&gcc USB30_0_MASTER_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ usb3_0: usb3@110f8800 { ++ compatible = "qcom,dwc3", "syscon"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x110f8800 0x8000>; ++ clocks = <&gcc USB30_0_MASTER_CLK>; ++ clock-names = "core"; ++ ++ ranges; ++ ++ resets = <&gcc USB30_0_MASTER_RESET>; ++ reset-names = "master"; ++ ++ status = "disabled"; ++ ++ dwc3_0: dwc3@11000000 { ++ compatible = "snps,dwc3"; ++ reg = <0x11000000 0xcd00>; ++ interrupts = ; ++ phys = <&hs_phy_0>, <&ss_phy_0>; ++ phy-names = "usb2-phy", "usb3-phy"; ++ dr_mode = "host"; ++ snps,dis_u3_susphy_quirk; ++ }; ++ }; ++ ++ hs_phy_1: hs_phy_1 { ++ compatible = "qcom,ipq806x-usb-phy-hs"; ++ reg = <0x100f8800 0x30>; ++ clocks = <&gcc USB30_1_UTMI_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ ss_phy_1: ss_phy_1 { ++ compatible = "qcom,ipq806x-usb-phy-ss"; ++ reg = <0x100f8830 0x30>; ++ clocks = <&gcc USB30_1_MASTER_CLK>; ++ clock-names = "ref"; ++ #phy-cells = <0>; ++ }; ++ ++ usb3_1: usb3@100f8800 { ++ compatible = "qcom,dwc3", "syscon"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x100f8800 0x8000>; ++ clocks = <&gcc USB30_1_MASTER_CLK>; ++ clock-names = "core"; ++ ++ ranges; ++ ++ resets = <&gcc USB30_1_MASTER_RESET>; ++ reset-names = "master"; ++ ++ status = "disabled"; ++ ++ dwc3_1: dwc3@10000000 { ++ compatible = "snps,dwc3"; ++ reg = <0x10000000 0xcd00>; ++ interrupts = ; ++ phys = <&hs_phy_1>, <&ss_phy_1>; ++ phy-names = "usb2-phy", "usb3-phy"; ++ dr_mode = "host"; ++ snps,dis_u3_susphy_quirk; ++ }; ++ }; ++ + pcie0: pci@1b500000 { + compatible = "qcom,pcie-ipq8064"; + reg = <0x1b500000 0x1000 +@@ -601,6 +1352,167 @@ + perst-gpio = <&qcom_pinmux 63 GPIO_ACTIVE_LOW>; + }; + ++ adm_dma: dma@18300000 { ++ compatible = "qcom,adm"; ++ reg = <0x18300000 0x100000>; ++ interrupts = ; ++ #dma-cells = <1>; ++ ++ clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; ++ clock-names = "core", "iface"; ++ ++ resets = <&gcc ADM0_RESET>, ++ <&gcc ADM0_PBUS_RESET>, ++ <&gcc ADM0_C0_RESET>, ++ <&gcc ADM0_C1_RESET>, ++ <&gcc ADM0_C2_RESET>; ++ reset-names = "clk", "pbus", "c0", "c1", "c2"; ++ qcom,ee = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ nand_controller: nand-controller@1ac00000 { ++ compatible = "qcom,ipq806x-nand"; ++ reg = <0x1ac00000 0x800>; ++ ++ clocks = <&gcc EBI2_CLK>, ++ <&gcc EBI2_AON_CLK>; ++ clock-names = "core", "aon"; ++ ++ dmas = <&adm_dma 3>; ++ dma-names = "rxtx"; ++ qcom,cmd-crci = <15>; ++ qcom,data-crci = <3>; ++ ++ status = "disabled"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ nss_common: syscon@03000000 { ++ compatible = "syscon"; ++ reg = <0x03000000 0x0000FFFF>; ++ }; ++ ++ qsgmii_csr: syscon@1bb00000 { ++ compatible = "syscon"; ++ reg = <0x1bb00000 0x000001FF>; ++ }; ++ ++ stmmac_axi_setup: stmmac-axi-config { ++ snps,wr_osr_lmt = <7>; ++ snps,rd_osr_lmt = <7>; ++ snps,blen = <16 0 0 0 0 0 0>; ++ }; ++ ++ mdio0: mdio@37000000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ compatible = "qcom,ipq8064-mdio", "syscon"; ++ reg = <0x37000000 0x200000>; ++ resets = <&gcc GMAC_CORE1_RESET>; ++ reset-names = "stmmaceth"; ++ clocks = <&gcc GMAC_CORE1_CLK>; ++ clock-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac0: ethernet@37000000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; ++ reg = <0x37000000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE1_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE1_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac1: ethernet@37200000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; ++ reg = <0x37200000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE2_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE2_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac2: ethernet@37400000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; ++ reg = <0x37400000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE3_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE3_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ ++ gmac3: ethernet@37600000 { ++ device_type = "network"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; ++ reg = <0x37600000 0x200000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,pbl = <32>; ++ snps,aal = <1>; ++ ++ qcom,nss-common = <&nss_common>; ++ qcom,qsgmii-csr = <&qsgmii_csr>; ++ ++ clocks = <&gcc GMAC_CORE4_CLK>; ++ clock-names = "stmmaceth"; ++ ++ resets = <&gcc GMAC_CORE4_RESET>; ++ reset-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ + vsdcc_fixed: vsdcc-regulator { + compatible = "regulator-fixed"; + regulator-name = "SDCC Power"; +@@ -676,4 +1588,17 @@ + }; + }; + }; ++ ++ sfpb_mutex: sfpb-mutex { ++ compatible = "qcom,sfpb-mutex"; ++ syscon = <&sfpb_mutex_block 4 4>; ++ ++ #hwlock-cells = <1>; ++ }; ++ ++ smem { ++ compatible = "qcom,smem"; ++ memory-region = <&smem>; ++ hwlocks = <&sfpb_mutex 3>; ++ }; + }; diff --git a/ipq806x/patches-5.4/084-ipq8064-v1.0-dtsi-cleanup.patch b/ipq806x/patches-5.4/084-ipq8064-v1.0-dtsi-cleanup.patch new file mode 100644 index 0000000..e5ea8e6 --- /dev/null +++ b/ipq806x/patches-5.4/084-ipq8064-v1.0-dtsi-cleanup.patch @@ -0,0 +1,89 @@ +This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches +instead of keeping a local version. +We drop partitions, LEDs and keys from the file as we will implement +them differently anyway. + +--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi +@@ -42,16 +42,6 @@ + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; +- +- partition@0 { +- label = "rootfs"; +- reg = <0x0 0x1000000>; +- }; +- +- partition@1 { +- label = "scratch"; +- reg = <0x1000000 0x1000000>; +- }; + }; + }; + }; +@@ -64,64 +54,5 @@ + ports-implemented = <0x1>; + status = "ok"; + }; +- +- gpio_keys { +- compatible = "gpio-keys"; +- pinctrl-0 = <&buttons_pins>; +- pinctrl-names = "default"; +- +- button@1 { +- label = "reset"; +- linux,code = ; +- gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; +- linux,input-type = <1>; +- debounce-interval = <60>; +- }; +- button@2 { +- label = "wps"; +- linux,code = ; +- gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; +- linux,input-type = <1>; +- debounce-interval = <60>; +- }; +- }; +- +- leds { +- compatible = "gpio-leds"; +- pinctrl-0 = <&leds_pins>; +- pinctrl-names = "default"; +- +- led@7 { +- label = "led_usb1"; +- gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "usbdev"; +- default-state = "off"; +- }; +- +- led@8 { +- label = "led_usb3"; +- gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; +- linux,default-trigger = "usbdev"; +- default-state = "off"; +- }; +- +- led@9 { +- label = "status_led_fail"; +- gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- +- led@26 { +- label = "sata_led"; +- gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- +- led@53 { +- label = "status_led_pass"; +- gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; +- default-state = "off"; +- }; +- }; + }; + }; diff --git a/ipq806x/patches-5.4/085-ipq8064-v1.0-dtsi-additions.patch b/ipq806x/patches-5.4/085-ipq8064-v1.0-dtsi-additions.patch new file mode 100644 index 0000000..58f6a46 --- /dev/null +++ b/ipq806x/patches-5.4/085-ipq8064-v1.0-dtsi-additions.patch @@ -0,0 +1,14 @@ +This uses upstream qcom-ipq8064-v1.0.dtsi and modifies it by patches +instead of keeping a local version. This patch adds our local adjustments +for the (local) additional contents of qcom-ipq8064.dtsi + +--- a/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-v1.0.dtsi +@@ -56,3 +56,7 @@ + }; + }; + }; ++ ++&CPU_SPC { ++ status = "okay"; ++}; diff --git a/ipq806x/patches-5.4/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch b/ipq806x/patches-5.4/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch new file mode 100644 index 0000000..2b5171f --- /dev/null +++ b/ipq806x/patches-5.4/086-v5.8-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch @@ -0,0 +1,104 @@ +From 13bec8d49bdf10aab4e1570ef42417f6bfbb6126 Mon Sep 17 00:00:00 2001 +From: Ajay Kishore +Date: Fri, 27 Mar 2020 23:32:08 +0100 +Subject: pinctrl: qcom: use scm_call to route GPIO irq to Apps + +For IPQ806x targets, TZ protects the registers that are used to +configure the routing of interrupts to a target processor. +To resolve this, this patch uses scm call to route GPIO interrupts +to application processor. Also the scm call interface is changed. + +Signed-off-by: Ajay Kishore +Signed-off-by: Ansuel Smith +Link: https://lore.kernel.org/r/20200327223209.20409-1-ansuelsmth@gmail.com +Reviewed-by: Bjorn Andersson +Signed-off-by: Linus Walleij +--- + drivers/pinctrl/qcom/pinctrl-msm.c | 43 ++++++++++++++++++++++++++++++++------ + 1 file changed, 37 insertions(+), 6 deletions(-) + +(limited to 'drivers/pinctrl/qcom/pinctrl-msm.c') + +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -22,6 +22,8 @@ + #include + #include + #include ++#include ++#include + + #include "../core.h" + #include "../pinconf.h" +@@ -57,6 +59,8 @@ struct msm_pinctrl { + struct irq_chip irq_chip; + int irq; + ++ bool intr_target_use_scm; ++ + raw_spinlock_t lock; + + DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); +@@ -64,6 +68,7 @@ struct msm_pinctrl { + + const struct msm_pinctrl_soc_data *soc; + void __iomem *regs[MAX_NR_TILES]; ++ u32 phys_base[MAX_NR_TILES]; + }; + + #define MSM_ACCESSOR(name) \ +@@ -832,11 +837,30 @@ static int msm_gpio_irq_set_type(struct + else + clear_bit(d->hwirq, pctrl->dual_edge_irqs); + +- /* Route interrupts to application cpu */ +- val = msm_readl_intr_target(pctrl, g); +- val &= ~(7 << g->intr_target_bit); +- val |= g->intr_target_kpss_val << g->intr_target_bit; +- msm_writel_intr_target(val, pctrl, g); ++ /* Route interrupts to application cpu. ++ * With intr_target_use_scm interrupts are routed to ++ * application cpu using scm calls. ++ */ ++ if (pctrl->intr_target_use_scm) { ++ u32 addr = pctrl->phys_base[0] + g->intr_target_reg; ++ int ret; ++ ++ qcom_scm_io_readl(addr, &val); ++ ++ val &= ~(7 << g->intr_target_bit); ++ val |= g->intr_target_kpss_val << g->intr_target_bit; ++ ++ ret = qcom_scm_io_writel(addr, val); ++ if (ret) ++ dev_err(pctrl->dev, ++ "Failed routing %lu interrupt to Apps proc", ++ d->hwirq); ++ } else { ++ val = msm_readl_intr_target(pctrl, g); ++ val &= ~(7 << g->intr_target_bit); ++ val |= g->intr_target_kpss_val << g->intr_target_bit; ++ msm_writel_intr_target(val, pctrl, g); ++ } + + /* Update configuration for gpio. + * RAW_STATUS_EN is left on for all gpio irqs. Due to the +@@ -1138,6 +1162,9 @@ int msm_pinctrl_probe(struct platform_de + pctrl->dev = &pdev->dev; + pctrl->soc = soc_data; + pctrl->chip = msm_gpio_template; ++ pctrl->intr_target_use_scm = of_device_is_compatible( ++ pctrl->dev->of_node, ++ "qcom,ipq8064-pinctrl"); + + raw_spin_lock_init(&pctrl->lock); + +@@ -1154,6 +1181,8 @@ int msm_pinctrl_probe(struct platform_de + pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pctrl->regs[0])) + return PTR_ERR(pctrl->regs[0]); ++ ++ pctrl->phys_base[0] = res->start; + } + + msm_pinctrl_setup_pm_reset(pctrl); diff --git a/ipq806x/patches-5.4/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch b/ipq806x/patches-5.4/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch new file mode 100644 index 0000000..612c33c --- /dev/null +++ b/ipq806x/patches-5.4/087-v5.8-ipq8064-pinctrl-Fixed-missing-RGMII-pincontrol-defin.patch @@ -0,0 +1,56 @@ +From 8d8cec9bf6e9260397872785f249dfb59a417d08 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 19 Feb 2020 18:59:39 +0100 +Subject: ipq8064: pinctrl: Fixed missing RGMII pincontrol definitions + +Add missing gpio definition for mdio and rgmii2. + +Signed-off-by: Ram Chandra Jangir +Signed-off-by: Ansuel Smith +Link: https://lore.kernel.org/r/20200219175940.744-1-ansuelsmth@gmail.com +Acked-by: Bjorn Andersson +Signed-off-by: Linus Walleij +--- + drivers/pinctrl/qcom/pinctrl-ipq8064.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c ++++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c +@@ -299,7 +299,7 @@ static const char * const gpio_groups[] + }; + + static const char * const mdio_groups[] = { +- "gpio0", "gpio1", "gpio10", "gpio11", ++ "gpio0", "gpio1", "gpio2", "gpio10", "gpio11", "gpio66", + }; + + static const char * const mi2s_groups[] = { +@@ -403,8 +403,8 @@ static const char * const usb2_hsic_grou + }; + + static const char * const rgmii2_groups[] = { +- "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", +- "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62", ++ "gpio2", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", ++ "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62", "gpio66", + }; + + static const char * const sata_groups[] = { +@@ -539,7 +539,7 @@ static const struct msm_function ipq8064 + static const struct msm_pingroup ipq8064_groups[] = { + PINGROUP(0, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(1, mdio, NA, NA, NA, NA, NA, NA, NA, NA, NA), +- PINGROUP(2, gsbi5_spi_cs3, NA, NA, NA, NA, NA, NA, NA, NA, NA), ++ PINGROUP(2, gsbi5_spi_cs3, rgmii2, mdio, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(3, pcie1_rst, pcie1_prsnt, pdm, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(4, pcie1_pwren_n, pcie1_pwren, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(5, pcie1_clk_req, pcie1_pwrflt, NA, NA, NA, NA, NA, NA, NA, NA), +@@ -603,7 +603,7 @@ static const struct msm_pingroup ipq8064 + PINGROUP(63, pcie3_rst, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(65, pcie3_clk_req, NA, NA, NA, NA, NA, NA, NA, NA, NA), +- PINGROUP(66, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), ++ PINGROUP(66, rgmii2, mdio, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(67, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(68, usb2_hsic, NA, NA, NA, NA, NA, NA, NA, NA, NA), + SDC_PINGROUP(sdc3_clk, 0x204a, 14, 6), diff --git a/ipq806x/patches-5.4/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch b/ipq806x/patches-5.4/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch new file mode 100644 index 0000000..1bd44fd --- /dev/null +++ b/ipq806x/patches-5.4/088-v5.8-watchdog-qcom-wdt-disable-pretimeout-on-timer-platfo.patch @@ -0,0 +1,98 @@ +From 000de5417107623925a4cf0310579f744ff43c28 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 4 Feb 2020 20:56:48 +0100 +Subject: watchdog: qcom-wdt: disable pretimeout on timer platform + +Some platform like ipq806x doesn't support pretimeout and define +some interrupts used by qcom,msm-timer. Change the driver to check +and use pretimeout only on qcom,kpss-wdt as it's the only platform +that actually supports it. + +Signed-off-by: Ansuel Smith +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20200204195648.23350-1-ansuelsmth@gmail.com +[groeck: Conflict resolution] +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +--- + drivers/watchdog/qcom-wdt.c | 31 +++++++++++++++++++++++-------- + 1 file changed, 23 insertions(+), 8 deletions(-) + +--- a/drivers/watchdog/qcom-wdt.c ++++ b/drivers/watchdog/qcom-wdt.c +@@ -39,6 +39,11 @@ static const u32 reg_offset_data_kpss[] + [WDT_BITE_TIME] = 0x14, + }; + ++struct qcom_wdt_match_data { ++ const u32 *offset; ++ bool pretimeout; ++}; ++ + struct qcom_wdt { + struct watchdog_device wdd; + unsigned long rate; +@@ -168,19 +173,29 @@ static void qcom_clk_disable_unprepare(v + clk_disable_unprepare(data); + } + ++static const struct qcom_wdt_match_data match_data_apcs_tmr = { ++ .offset = reg_offset_data_apcs_tmr, ++ .pretimeout = false, ++}; ++ ++static const struct qcom_wdt_match_data match_data_kpss = { ++ .offset = reg_offset_data_kpss, ++ .pretimeout = true, ++}; ++ + static int qcom_wdt_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct qcom_wdt *wdt; + struct resource *res; + struct device_node *np = dev->of_node; +- const u32 *regs; ++ const struct qcom_wdt_match_data *data; + u32 percpu_offset; + int irq, ret; + struct clk *clk; + +- regs = of_device_get_match_data(dev); +- if (!regs) { ++ data = of_device_get_match_data(dev); ++ if (!data) { + dev_err(dev, "Unsupported QCOM WDT module\n"); + return -ENODEV; + } +@@ -236,7 +251,7 @@ static int qcom_wdt_probe(struct platfor + + /* check if there is pretimeout support */ + irq = platform_get_irq_optional(pdev, 0); +- if (irq > 0) { ++ if (data->pretimeout && irq > 0) { + ret = devm_request_irq(dev, irq, qcom_wdt_isr, + IRQF_TRIGGER_RISING, + "wdt_bark", &wdt->wdd); +@@ -256,7 +271,7 @@ static int qcom_wdt_probe(struct platfor + wdt->wdd.min_timeout = 1; + wdt->wdd.max_timeout = 0x10000000U / wdt->rate; + wdt->wdd.parent = dev; +- wdt->layout = regs; ++ wdt->layout = data->offset; + + if (readl(wdt_addr(wdt, WDT_STS)) & 1) + wdt->wdd.bootstatus = WDIOF_CARDRESET; +@@ -300,9 +315,9 @@ static int __maybe_unused qcom_wdt_resum + static SIMPLE_DEV_PM_OPS(qcom_wdt_pm_ops, qcom_wdt_suspend, qcom_wdt_resume); + + static const struct of_device_id qcom_wdt_of_table[] = { +- { .compatible = "qcom,kpss-timer", .data = reg_offset_data_apcs_tmr }, +- { .compatible = "qcom,scss-timer", .data = reg_offset_data_apcs_tmr }, +- { .compatible = "qcom,kpss-wdt", .data = reg_offset_data_kpss }, ++ { .compatible = "qcom,kpss-timer", .data = &match_data_apcs_tmr }, ++ { .compatible = "qcom,scss-timer", .data = &match_data_apcs_tmr }, ++ { .compatible = "qcom,kpss-wdt", .data = &match_data_kpss }, + { }, + }; + MODULE_DEVICE_TABLE(of, qcom_wdt_of_table); diff --git a/ipq806x/patches-5.4/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch b/ipq806x/patches-5.4/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch new file mode 100644 index 0000000..015a917 --- /dev/null +++ b/ipq806x/patches-5.4/089-v5.8-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch @@ -0,0 +1,28 @@ +From 1aec193ea41d672d11592714cdda8167eb3b38fc Mon Sep 17 00:00:00 2001 +From: Abhishek Sahu +Date: Wed, 18 Mar 2020 14:16:56 +0100 +Subject: ipq806x: gcc: Added the enable regs and mask for PRNG + +Kernel got hanged while reading from /dev/hwrng at the +time of PRNG clock enable + +Fixes: 24d8fba44af3 "clk: qcom: Add support for IPQ8064's global clock controller (GCC)" +Signed-off-by: Abhishek Sahu +Signed-off-by: Ansuel Smith +Link: https://lkml.kernel.org/r/20200318131657.345-1-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + drivers/clk/qcom/gcc-ipq806x.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -1225,6 +1225,8 @@ static struct clk_rcg prng_src = { + .parent_map = gcc_pxo_pll8_map, + }, + .clkr = { ++ .enable_reg = 0x2e80, ++ .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "prng_src", + .parent_names = gcc_pxo_pll8, diff --git a/ipq806x/patches-5.4/090-v5.8-clk-clk-rpm-fixes.patch b/ipq806x/patches-5.4/090-v5.8-clk-clk-rpm-fixes.patch new file mode 100644 index 0000000..a285709 --- /dev/null +++ b/ipq806x/patches-5.4/090-v5.8-clk-clk-rpm-fixes.patch @@ -0,0 +1,90 @@ +From eec152734be10c72d2d413a27ca9d282c28cdb61 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 10 Mar 2020 15:37:56 +0100 +Subject: clk: qcom: clk-rpm: add missing rpm clk for ipq806x + +Add missing definition of rpm clk for ipq806x soc + +Signed-off-by: John Crispin +Signed-off-by: Ansuel Smith +Acked-by: John Crispin +Reviewed-by: Rob Herring +Link: https://lkml.kernel.org/r/20200310143756.244-1-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + .../devicetree/bindings/clock/qcom,rpmcc.txt | 1 + + drivers/clk/qcom/clk-rpm.c | 35 ++++++++++++++++++++++ + include/dt-bindings/clock/qcom,rpmcc.h | 4 +++ + 3 files changed, 40 insertions(+) + +--- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt ++++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt +@@ -15,6 +15,7 @@ Required properties : + "qcom,rpmcc-msm8916", "qcom,rpmcc" + "qcom,rpmcc-msm8974", "qcom,rpmcc" + "qcom,rpmcc-apq8064", "qcom,rpmcc" ++ "qcom,rpmcc-ipq806x", "qcom,rpmcc" + "qcom,rpmcc-msm8996", "qcom,rpmcc" + "qcom,rpmcc-msm8998", "qcom,rpmcc" + "qcom,rpmcc-qcs404", "qcom,rpmcc" +--- a/drivers/clk/qcom/clk-rpm.c ++++ b/drivers/clk/qcom/clk-rpm.c +@@ -543,10 +543,45 @@ static const struct rpm_clk_desc rpm_clk + .num_clks = ARRAY_SIZE(apq8064_clks), + }; + ++/* ipq806x */ ++DEFINE_CLK_RPM(ipq806x, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); ++DEFINE_CLK_RPM(ipq806x, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); ++DEFINE_CLK_RPM(ipq806x, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK); ++DEFINE_CLK_RPM(ipq806x, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK); ++DEFINE_CLK_RPM(ipq806x, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); ++DEFINE_CLK_RPM(ipq806x, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); ++DEFINE_CLK_RPM(ipq806x, nss_fabric_0_clk, nss_fabric_0_a_clk, QCOM_RPM_NSS_FABRIC_0_CLK); ++DEFINE_CLK_RPM(ipq806x, nss_fabric_1_clk, nss_fabric_1_a_clk, QCOM_RPM_NSS_FABRIC_1_CLK); ++ ++static struct clk_rpm *ipq806x_clks[] = { ++ [RPM_APPS_FABRIC_CLK] = &ipq806x_afab_clk, ++ [RPM_APPS_FABRIC_A_CLK] = &ipq806x_afab_a_clk, ++ [RPM_CFPB_CLK] = &ipq806x_cfpb_clk, ++ [RPM_CFPB_A_CLK] = &ipq806x_cfpb_a_clk, ++ [RPM_DAYTONA_FABRIC_CLK] = &ipq806x_daytona_clk, ++ [RPM_DAYTONA_FABRIC_A_CLK] = &ipq806x_daytona_a_clk, ++ [RPM_EBI1_CLK] = &ipq806x_ebi1_clk, ++ [RPM_EBI1_A_CLK] = &ipq806x_ebi1_a_clk, ++ [RPM_SYS_FABRIC_CLK] = &ipq806x_sfab_clk, ++ [RPM_SYS_FABRIC_A_CLK] = &ipq806x_sfab_a_clk, ++ [RPM_SFPB_CLK] = &ipq806x_sfpb_clk, ++ [RPM_SFPB_A_CLK] = &ipq806x_sfpb_a_clk, ++ [RPM_NSS_FABRIC_0_CLK] = &ipq806x_nss_fabric_0_clk, ++ [RPM_NSS_FABRIC_0_A_CLK] = &ipq806x_nss_fabric_0_a_clk, ++ [RPM_NSS_FABRIC_1_CLK] = &ipq806x_nss_fabric_1_clk, ++ [RPM_NSS_FABRIC_1_A_CLK] = &ipq806x_nss_fabric_1_a_clk, ++}; ++ ++static const struct rpm_clk_desc rpm_clk_ipq806x = { ++ .clks = ipq806x_clks, ++ .num_clks = ARRAY_SIZE(ipq806x_clks), ++}; ++ + static const struct of_device_id rpm_clk_match_table[] = { + { .compatible = "qcom,rpmcc-msm8660", .data = &rpm_clk_msm8660 }, + { .compatible = "qcom,rpmcc-apq8060", .data = &rpm_clk_msm8660 }, + { .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 }, ++ { .compatible = "qcom,rpmcc-ipq806x", .data = &rpm_clk_ipq806x }, + { } + }; + MODULE_DEVICE_TABLE(of, rpm_clk_match_table); +--- a/include/dt-bindings/clock/qcom,rpmcc.h ++++ b/include/dt-bindings/clock/qcom,rpmcc.h +@@ -37,6 +37,10 @@ + #define RPM_XO_A0 27 + #define RPM_XO_A1 28 + #define RPM_XO_A2 29 ++#define RPM_NSS_FABRIC_0_CLK 30 ++#define RPM_NSS_FABRIC_0_A_CLK 31 ++#define RPM_NSS_FABRIC_1_CLK 32 ++#define RPM_NSS_FABRIC_1_A_CLK 33 + + /* SMD RPM clocks */ + #define RPM_SMD_XO_CLK_SRC 0 diff --git a/ipq806x/patches-5.4/091-v5.8-regulator-add-smb208-support.patch b/ipq806x/patches-5.4/091-v5.8-regulator-add-smb208-support.patch new file mode 100644 index 0000000..42a0286 --- /dev/null +++ b/ipq806x/patches-5.4/091-v5.8-regulator-add-smb208-support.patch @@ -0,0 +1,63 @@ +From b5f25304aece9f2e7eaab275bbb5461c666bf38c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 19 Feb 2020 17:37:11 +0100 +Subject: regulator: add smb208 support + +Smb208 regulators are used on some ipq806x soc. +Add support for it to make it avaiable on some routers +that use it. + +Signed-off-by: Ansuel Smith +Signed-off-by: Adrian Panella +Acked-by: Lee Jones +Link: https://lore.kernel.org/r/20200219163711.479-1-ansuelsmth@gmail.com +Signed-off-by: Mark Brown +--- + Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 4 ++++ + drivers/regulator/qcom_rpm-regulator.c | 9 +++++++++ + 2 files changed, 13 insertions(+) + +--- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt ++++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt +@@ -61,6 +61,7 @@ Regulator nodes are identified by their + "qcom,rpm-pm8901-regulators" + "qcom,rpm-pm8921-regulators" + "qcom,rpm-pm8018-regulators" ++ "qcom,rpm-smb208-regulators" + + - vdd_l0_l1_lvs-supply: + - vdd_l2_l11_l12-supply: +@@ -171,6 +172,9 @@ pm8018: + s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, + l12, l14, lvs1 + ++smb208: ++ s1a, s1b, s2a, s2b ++ + The content of each sub-node is defined by the standard binding for regulators - + see regulator.txt - with additional custom properties described below: + +--- a/drivers/regulator/qcom_rpm-regulator.c ++++ b/drivers/regulator/qcom_rpm-regulator.c +@@ -925,12 +925,21 @@ static const struct rpm_regulator_data r + { } + }; + ++static const struct rpm_regulator_data rpm_smb208_regulators[] = { ++ { "s1a", QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" }, ++ { "s1b", QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" }, ++ { "s2a", QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" }, ++ { "s2b", QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" }, ++ { } ++}; ++ + static const struct of_device_id rpm_of_match[] = { + { .compatible = "qcom,rpm-pm8018-regulators", + .data = &rpm_pm8018_regulators }, + { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, + { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, + { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, ++ { .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators }, + { } + }; + MODULE_DEVICE_TABLE(of, rpm_of_match); diff --git a/ipq806x/patches-5.4/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch b/ipq806x/patches-5.4/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch new file mode 100644 index 0000000..bdf0f8f --- /dev/null +++ b/ipq806x/patches-5.4/092-1-v5.7-qcom-cpufreq-nvmem-Add-support-for-krait-based-socs.patch @@ -0,0 +1,361 @@ +From a8811ec764f95a04ba82f6f457e28c5e9e36e36b Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 13 Mar 2020 18:52:13 +0100 +Subject: cpufreq: qcom: Add support for krait based socs + +In Certain QCOM SoCs like ipq8064, apq8064, msm8960, msm8974 +that has KRAIT processors the voltage/current value of each OPP +varies based on the silicon variant in use. + +The required OPP related data is determined based on +the efuse value. This is similar to the existing code for +kryo cores. So adding support for krait cores here. + +Signed-off-by: Sricharan R +Signed-off-by: Ansuel Smith +Signed-off-by: Viresh Kumar +--- + .../devicetree/bindings/opp/qcom-nvmem-cpufreq.txt | 3 +- + drivers/cpufreq/Kconfig.arm | 2 +- + drivers/cpufreq/cpufreq-dt-platdev.c | 5 + + drivers/cpufreq/qcom-cpufreq-nvmem.c | 191 +++++++++++++++++++-- + 4 files changed, 183 insertions(+), 18 deletions(-) + +--- a/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt ++++ b/Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt +@@ -19,7 +19,8 @@ In 'cpu' nodes: + + In 'operating-points-v2' table: + - compatible: Should be +- - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996. ++ - 'operating-points-v2-kryo-cpu' for apq8096, msm8996, msm8974, ++ apq8064, ipq8064, msm8960 and ipq8074. + + Optional properties: + -------------------- +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -135,7 +135,7 @@ config ARM_OMAP2PLUS_CPUFREQ + + config ARM_QCOM_CPUFREQ_NVMEM + tristate "Qualcomm nvmem based CPUFreq" +- depends on ARM64 ++ depends on ARCH_QCOM + depends on QCOM_QFPROM + depends on QCOM_SMEM + select PM_OPP +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -140,6 +140,11 @@ static const struct of_device_id blackli + { .compatible = "ti,am43", }, + { .compatible = "ti,dra7", }, + ++ { .compatible = "qcom,ipq8064", }, ++ { .compatible = "qcom,apq8064", }, ++ { .compatible = "qcom,msm8974", }, ++ { .compatible = "qcom,msm8960", }, ++ + { } + }; + +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -49,12 +49,14 @@ struct qcom_cpufreq_drv; + struct qcom_cpufreq_match_data { + int (*get_version)(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, ++ char **pvs_name, + struct qcom_cpufreq_drv *drv); + const char **genpd_names; + }; + + struct qcom_cpufreq_drv { +- struct opp_table **opp_tables; ++ struct opp_table **names_opp_tables; ++ struct opp_table **hw_opp_tables; + struct opp_table **genpd_opp_tables; + u32 versions; + const struct qcom_cpufreq_match_data *data; +@@ -62,6 +64,84 @@ struct qcom_cpufreq_drv { + + static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; + ++static void get_krait_bin_format_a(struct device *cpu_dev, ++ int *speed, int *pvs, int *pvs_ver, ++ struct nvmem_cell *pvs_nvmem, u8 *buf) ++{ ++ u32 pte_efuse; ++ ++ pte_efuse = *((u32 *)buf); ++ ++ *speed = pte_efuse & 0xf; ++ if (*speed == 0xf) ++ *speed = (pte_efuse >> 4) & 0xf; ++ ++ if (*speed == 0xf) { ++ *speed = 0; ++ dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed); ++ } else { ++ dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); ++ } ++ ++ *pvs = (pte_efuse >> 10) & 0x7; ++ if (*pvs == 0x7) ++ *pvs = (pte_efuse >> 13) & 0x7; ++ ++ if (*pvs == 0x7) { ++ *pvs = 0; ++ dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs); ++ } else { ++ dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); ++ } ++} ++ ++static void get_krait_bin_format_b(struct device *cpu_dev, ++ int *speed, int *pvs, int *pvs_ver, ++ struct nvmem_cell *pvs_nvmem, u8 *buf) ++{ ++ u32 pte_efuse, redundant_sel; ++ ++ pte_efuse = *((u32 *)buf); ++ redundant_sel = (pte_efuse >> 24) & 0x7; ++ ++ *pvs_ver = (pte_efuse >> 4) & 0x3; ++ ++ switch (redundant_sel) { ++ case 1: ++ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); ++ *speed = (pte_efuse >> 27) & 0xf; ++ break; ++ case 2: ++ *pvs = (pte_efuse >> 27) & 0xf; ++ *speed = pte_efuse & 0x7; ++ break; ++ default: ++ /* 4 bits of PVS are in efuse register bits 31, 8-6. */ ++ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); ++ *speed = pte_efuse & 0x7; ++ } ++ ++ /* Check SPEED_BIN_BLOW_STATUS */ ++ if (pte_efuse & BIT(3)) { ++ dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); ++ } else { ++ dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n"); ++ *speed = 0; ++ } ++ ++ /* Check PVS_BLOW_STATUS */ ++ pte_efuse = *(((u32 *)buf) + 4); ++ pte_efuse &= BIT(21); ++ if (pte_efuse) { ++ dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); ++ } else { ++ dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n"); ++ *pvs = 0; ++ } ++ ++ dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver); ++} ++ + static enum _msm8996_version qcom_cpufreq_get_msm_id(void) + { + size_t len; +@@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufre + + static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, ++ char **pvs_name, + struct qcom_cpufreq_drv *drv) + { + size_t len; + u8 *speedbin; + enum _msm8996_version msm8996_version; ++ *pvs_name = NULL; + + msm8996_version = qcom_cpufreq_get_msm_id(); + if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { +@@ -125,10 +207,51 @@ static int qcom_cpufreq_kryo_name_versio + return 0; + } + ++static int qcom_cpufreq_krait_name_version(struct device *cpu_dev, ++ struct nvmem_cell *speedbin_nvmem, ++ char **pvs_name, ++ struct qcom_cpufreq_drv *drv) ++{ ++ int speed = 0, pvs = 0, pvs_ver = 0; ++ u8 *speedbin; ++ size_t len; ++ ++ speedbin = nvmem_cell_read(speedbin_nvmem, &len); ++ ++ if (IS_ERR(speedbin)) ++ return PTR_ERR(speedbin); ++ ++ switch (len) { ++ case 4: ++ get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver, ++ speedbin_nvmem, speedbin); ++ break; ++ case 8: ++ get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver, ++ speedbin_nvmem, speedbin); ++ break; ++ default: ++ dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n"); ++ return -ENODEV; ++ } ++ ++ snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d", ++ speed, pvs, pvs_ver); ++ ++ drv->versions = (1 << speed); ++ ++ kfree(speedbin); ++ return 0; ++} ++ + static const struct qcom_cpufreq_match_data match_data_kryo = { + .get_version = qcom_cpufreq_kryo_name_version, + }; + ++static const struct qcom_cpufreq_match_data match_data_krait = { ++ .get_version = qcom_cpufreq_krait_name_version, ++}; ++ + static const char *qcs404_genpd_names[] = { "cpr", NULL }; + + static const struct qcom_cpufreq_match_data match_data_qcs404 = { +@@ -141,6 +264,7 @@ static int qcom_cpufreq_probe(struct pla + struct nvmem_cell *speedbin_nvmem; + struct device_node *np; + struct device *cpu_dev; ++ char *pvs_name = "speedXX-pvsXX-vXX"; + unsigned cpu; + const struct of_device_id *match; + int ret; +@@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla + if (!np) + return -ENOENT; + +- ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); ++ ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); + if (!ret) { + of_node_put(np); + return -ENOENT; +@@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct pla + goto free_drv; + } + +- ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv); ++ ret = drv->data->get_version(cpu_dev, ++ speedbin_nvmem, &pvs_name, drv); + if (ret) { + nvmem_cell_put(speedbin_nvmem); + goto free_drv; +@@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct pla + } + of_node_put(np); + +- drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables), ++ drv->names_opp_tables = kcalloc(num_possible_cpus(), ++ sizeof(*drv->names_opp_tables), + GFP_KERNEL); +- if (!drv->opp_tables) { ++ if (!drv->names_opp_tables) { + ret = -ENOMEM; + goto free_drv; + } ++ drv->hw_opp_tables = kcalloc(num_possible_cpus(), ++ sizeof(*drv->hw_opp_tables), ++ GFP_KERNEL); ++ if (!drv->hw_opp_tables) { ++ ret = -ENOMEM; ++ goto free_opp_names; ++ } + + drv->genpd_opp_tables = kcalloc(num_possible_cpus(), + sizeof(*drv->genpd_opp_tables), +@@ -213,11 +346,23 @@ static int qcom_cpufreq_probe(struct pla + } + + if (drv->data->get_version) { +- drv->opp_tables[cpu] = +- dev_pm_opp_set_supported_hw(cpu_dev, +- &drv->versions, 1); +- if (IS_ERR(drv->opp_tables[cpu])) { +- ret = PTR_ERR(drv->opp_tables[cpu]); ++ ++ if (pvs_name) { ++ drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name( ++ cpu_dev, ++ pvs_name); ++ if (IS_ERR(drv->names_opp_tables[cpu])) { ++ ret = PTR_ERR(drv->names_opp_tables[cpu]); ++ dev_err(cpu_dev, "Failed to add OPP name %s\n", ++ pvs_name); ++ goto free_opp; ++ } ++ } ++ ++ drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw( ++ cpu_dev, &drv->versions, 1); ++ if (IS_ERR(drv->hw_opp_tables[cpu])) { ++ ret = PTR_ERR(drv->hw_opp_tables[cpu]); + dev_err(cpu_dev, + "Failed to set supported hardware\n"); + goto free_genpd_opp; +@@ -259,11 +404,18 @@ free_genpd_opp: + kfree(drv->genpd_opp_tables); + free_opp: + for_each_possible_cpu(cpu) { +- if (IS_ERR_OR_NULL(drv->opp_tables[cpu])) ++ if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu])) ++ break; ++ dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]); ++ } ++ for_each_possible_cpu(cpu) { ++ if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu])) + break; +- dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); ++ dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); + } +- kfree(drv->opp_tables); ++ kfree(drv->hw_opp_tables); ++free_opp_names: ++ kfree(drv->names_opp_tables); + free_drv: + kfree(drv); + +@@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct pl + platform_device_unregister(cpufreq_dt_pdev); + + for_each_possible_cpu(cpu) { +- if (drv->opp_tables[cpu]) +- dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); ++ if (drv->names_opp_tables[cpu]) ++ dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]); ++ if (drv->hw_opp_tables[cpu]) ++ dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); + if (drv->genpd_opp_tables[cpu]) + dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); + } + +- kfree(drv->opp_tables); ++ kfree(drv->names_opp_tables); ++ kfree(drv->hw_opp_tables); + kfree(drv->genpd_opp_tables); + kfree(drv); + +@@ -303,6 +458,10 @@ static const struct of_device_id qcom_cp + { .compatible = "qcom,apq8096", .data = &match_data_kryo }, + { .compatible = "qcom,msm8996", .data = &match_data_kryo }, + { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, ++ { .compatible = "qcom,ipq8064", .data = &match_data_krait }, ++ { .compatible = "qcom,apq8064", .data = &match_data_krait }, ++ { .compatible = "qcom,msm8974", .data = &match_data_krait }, ++ { .compatible = "qcom,msm8960", .data = &match_data_krait }, + {}, + }; + MODULE_DEVICE_TABLE(of, qcom_cpufreq_match_list); diff --git a/ipq806x/patches-5.4/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch b/ipq806x/patches-5.4/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch new file mode 100644 index 0000000..764a917 --- /dev/null +++ b/ipq806x/patches-5.4/092-2-v5.7-cpufreq-qcom-fix-wrong-compatible-binding.patch @@ -0,0 +1,26 @@ +From 2dea651680cea1f3a29925de51002f33d1f55711 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 1 May 2020 00:22:25 +0200 +Subject: cpufreq: qcom: fix wrong compatible binding + +Binding in Documentation is still "operating-points-v2-kryo-cpu". +Restore the old binding to fix the compatibility problem. + +Fixes: a8811ec764f9 ("cpufreq: qcom: Add support for krait based socs") +Signed-off-by: Ansuel Smith +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -277,7 +277,7 @@ static int qcom_cpufreq_probe(struct pla + if (!np) + return -ENOENT; + +- ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); ++ ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); + if (!ret) { + of_node_put(np); + return -ENOENT; diff --git a/ipq806x/patches-5.4/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch b/ipq806x/patches-5.4/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch new file mode 100644 index 0000000..ecfcd74 --- /dev/null +++ b/ipq806x/patches-5.4/093-4-v5.8-ipq806x-PCI-qcom-Use-bulk-clk-api-and-assert-on-error.patch @@ -0,0 +1,228 @@ +From 6a114526af4689938863bf34976c83bfd279f517 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 15 Jun 2020 23:06:02 +0200 +Subject: PCI: qcom: Use bulk clk api and assert on error + +Rework 2.1.0 revision to use bulk clk api and fix missing assert on +reset_control_deassert error. + +Link: https://lore.kernel.org/r/20200615210608.21469-7-ansuelsmth@gmail.com +Signed-off-by: Ansuel Smith +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Rob Herring +Acked-by: Stanimir Varbanov +--- + drivers/pci/controller/dwc/pcie-qcom.c | 131 ++++++++++++--------------------- + 1 file changed, 46 insertions(+), 85 deletions(-) + +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -99,12 +99,9 @@ + #define SLV_ADDR_SPACE_SZ 0x10000000 + + #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 ++#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 + struct qcom_pcie_resources_2_1_0 { +- struct clk *iface_clk; +- struct clk *core_clk; +- struct clk *phy_clk; +- struct clk *aux_clk; +- struct clk *ref_clk; ++ struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS]; + struct reset_control *pci_reset; + struct reset_control *axi_reset; + struct reset_control *ahb_reset; +@@ -244,25 +241,21 @@ static int qcom_pcie_get_resources_2_1_0 + if (ret) + return ret; + +- res->iface_clk = devm_clk_get(dev, "iface"); +- if (IS_ERR(res->iface_clk)) +- return PTR_ERR(res->iface_clk); +- +- res->core_clk = devm_clk_get(dev, "core"); +- if (IS_ERR(res->core_clk)) +- return PTR_ERR(res->core_clk); +- +- res->phy_clk = devm_clk_get(dev, "phy"); +- if (IS_ERR(res->phy_clk)) +- return PTR_ERR(res->phy_clk); +- +- res->aux_clk = devm_clk_get_optional(dev, "aux"); +- if (IS_ERR(res->aux_clk)) +- return PTR_ERR(res->aux_clk); +- +- res->ref_clk = devm_clk_get_optional(dev, "ref"); +- if (IS_ERR(res->ref_clk)) +- return PTR_ERR(res->ref_clk); ++ res->clks[0].id = "iface"; ++ res->clks[1].id = "core"; ++ res->clks[2].id = "phy"; ++ res->clks[3].id = "aux"; ++ res->clks[4].id = "ref"; ++ ++ /* iface, core, phy are required */ ++ ret = devm_clk_bulk_get(dev, 3, res->clks); ++ if (ret < 0) ++ return ret; ++ ++ /* aux, ref are optional */ ++ ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3); ++ if (ret < 0) ++ return ret; + + res->pci_reset = devm_reset_control_get_exclusive(dev, "pci"); + if (IS_ERR(res->pci_reset)) +@@ -292,17 +285,13 @@ static void qcom_pcie_deinit_2_1_0(struc + { + struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0; + +- clk_disable_unprepare(res->phy_clk); ++ clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); + reset_control_assert(res->pci_reset); + reset_control_assert(res->axi_reset); + reset_control_assert(res->ahb_reset); + reset_control_assert(res->por_reset); + reset_control_assert(res->ext_reset); + reset_control_assert(res->phy_reset); +- clk_disable_unprepare(res->iface_clk); +- clk_disable_unprepare(res->core_clk); +- clk_disable_unprepare(res->aux_clk); +- clk_disable_unprepare(res->ref_clk); + + writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL); + +@@ -334,47 +323,45 @@ static int qcom_pcie_init_2_1_0(struct q + return ret; + } + +- ret = reset_control_assert(res->ahb_reset); ++ ret = reset_control_deassert(res->ahb_reset); + if (ret) { +- dev_err(dev, "cannot assert ahb reset\n"); +- goto err_assert_ahb; ++ dev_err(dev, "cannot deassert ahb reset\n"); ++ goto err_deassert_ahb; + } + +- ret = clk_prepare_enable(res->iface_clk); ++ ret = reset_control_deassert(res->ext_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable iface clock\n"); +- goto err_assert_ahb; ++ dev_err(dev, "cannot deassert ext reset\n"); ++ goto err_deassert_ext; + } + +- ret = clk_prepare_enable(res->core_clk); ++ ret = reset_control_deassert(res->phy_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable core clock\n"); +- goto err_clk_core; ++ dev_err(dev, "cannot deassert phy reset\n"); ++ goto err_deassert_phy; + } + +- ret = clk_prepare_enable(res->aux_clk); ++ ret = reset_control_deassert(res->pci_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable aux clock\n"); +- goto err_clk_aux; ++ dev_err(dev, "cannot deassert pci reset\n"); ++ goto err_deassert_pci; + } + +- ret = clk_prepare_enable(res->ref_clk); ++ ret = reset_control_deassert(res->por_reset); + if (ret) { +- dev_err(dev, "cannot prepare/enable ref clock\n"); +- goto err_clk_ref; ++ dev_err(dev, "cannot deassert por reset\n"); ++ goto err_deassert_por; + } + +- ret = reset_control_deassert(res->ahb_reset); ++ ret = reset_control_deassert(res->axi_reset); + if (ret) { +- dev_err(dev, "cannot deassert ahb reset\n"); +- goto err_deassert_ahb; ++ dev_err(dev, "cannot deassert axi reset\n"); ++ goto err_deassert_axi; + } + +- ret = reset_control_deassert(res->ext_reset); +- if (ret) { +- dev_err(dev, "cannot deassert ext reset\n"); +- goto err_deassert_ahb; +- } ++ ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); ++ if (ret) ++ goto err_clks; + + /* enable PCIe clocks and resets */ + val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL); +@@ -408,36 +395,6 @@ static int qcom_pcie_init_2_1_0(struct q + val |= PHY_REFCLK_SSP_EN; + writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK); + +- ret = reset_control_deassert(res->phy_reset); +- if (ret) { +- dev_err(dev, "cannot deassert phy reset\n"); +- return ret; +- } +- +- ret = reset_control_deassert(res->pci_reset); +- if (ret) { +- dev_err(dev, "cannot deassert pci reset\n"); +- return ret; +- } +- +- ret = reset_control_deassert(res->por_reset); +- if (ret) { +- dev_err(dev, "cannot deassert por reset\n"); +- return ret; +- } +- +- ret = reset_control_deassert(res->axi_reset); +- if (ret) { +- dev_err(dev, "cannot deassert axi reset\n"); +- return ret; +- } +- +- ret = clk_prepare_enable(res->phy_clk); +- if (ret) { +- dev_err(dev, "cannot prepare/enable phy clock\n"); +- goto err_deassert_ahb; +- } +- + /* wait for clock acquisition */ + usleep_range(1000, 1500); + +@@ -450,15 +407,19 @@ static int qcom_pcie_init_2_1_0(struct q + + return 0; + ++err_clks: ++ reset_control_assert(res->axi_reset); ++err_deassert_axi: ++ reset_control_assert(res->por_reset); ++err_deassert_por: ++ reset_control_assert(res->pci_reset); ++err_deassert_pci: ++ reset_control_assert(res->phy_reset); ++err_deassert_phy: ++ reset_control_assert(res->ext_reset); ++err_deassert_ext: ++ reset_control_assert(res->ahb_reset); + err_deassert_ahb: +- clk_disable_unprepare(res->ref_clk); +-err_clk_ref: +- clk_disable_unprepare(res->aux_clk); +-err_clk_aux: +- clk_disable_unprepare(res->core_clk); +-err_clk_core: +- clk_disable_unprepare(res->iface_clk); +-err_assert_ahb: + regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies); + + return ret; diff --git a/ipq806x/patches-5.4/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch b/ipq806x/patches-5.4/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch new file mode 100644 index 0000000..be334d7 --- /dev/null +++ b/ipq806x/patches-5.4/093-7-v5.8-ipq806x-PCI-qcom-Add-ipq8064-rev2-variant.patch @@ -0,0 +1,36 @@ +From 8df093fe2ae1717389df0dcdc620c02cc35abb21 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 15 Jun 2020 23:06:05 +0200 +Subject: PCI: qcom: Add ipq8064 rev2 variant + +Ipq8064-v2 have tx term offset set to 0. Introduce this variant to permit +different offset based on the revision. + +Link: https://lore.kernel.org/r/20200615210608.21469-10-ansuelsmth@gmail.com +Signed-off-by: Ansuel Smith +Signed-off-by: Lorenzo Pieralisi +Acked-by: Stanimir Varbanov +--- + drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -368,7 +368,8 @@ static int qcom_pcie_init_2_1_0(struct q + val &= ~BIT(0); + writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL); + +- if (of_device_is_compatible(node, "qcom,pcie-ipq8064")) { ++ if (of_device_is_compatible(node, "qcom,pcie-ipq8064") || ++ of_device_is_compatible(node, "qcom,pcie-ipq8064-v2")) { + writel(PCS_DEEMPH_TX_DEEMPH_GEN1(24) | + PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(24) | + PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(34), +@@ -1330,6 +1331,7 @@ err_pm_runtime_put: + static const struct of_device_id qcom_pcie_match[] = { + { .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 }, + { .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 }, ++ { .compatible = "qcom,pcie-ipq8064-v2", .data = &ops_2_1_0 }, + { .compatible = "qcom,pcie-apq8064", .data = &ops_2_1_0 }, + { .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 }, + { .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 }, diff --git a/ipq806x/patches-5.4/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch b/ipq806x/patches-5.4/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch new file mode 100644 index 0000000..5440b2f --- /dev/null +++ b/ipq806x/patches-5.4/093-8-v5.8-ipq806x-PCI-qcom-Support-pci-speed-set-for-ipq806x.patch @@ -0,0 +1,74 @@ +From 51ed2c2b60265006bde7531d10993cf24def0aee Mon Sep 17 00:00:00 2001 +From: Sham Muthayyan +Date: Mon, 15 Jun 2020 23:06:07 +0200 +Subject: PCI: qcom: Support pci speed set for ipq806x + +Some SoC based on ipq8064/5 needs to be limited to pci GEN1 speed due to +some hardware limitations. Add support for speed setting defined by the +max-link-speed binding. If not defined the max speed is set to GEN2 by +default. + +Link: https://lore.kernel.org/r/20200615210608.21469-12-ansuelsmth@gmail.com +Signed-off-by: Sham Muthayyan +Signed-off-by: Ansuel Smith +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Rob Herring +Acked-by: Stanimir Varbanov +--- + +Backported with light changes: +* One include is missing in kernel 5.4 + + drivers/pci/controller/dwc/pcie-qcom.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/pci/controller/dwc/pcie-qcom.c ++++ b/drivers/pci/controller/dwc/pcie-qcom.c +@@ -27,6 +27,7 @@ + #include + #include + ++#include "../../pci.h" + #include "pcie-designware.h" + + #define PCIE20_PARF_SYS_CTRL 0x00 +@@ -98,6 +99,8 @@ + #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358 + #define SLV_ADDR_SPACE_SZ 0x10000000 + ++#define PCIE20_LNK_CONTROL2_LINK_STATUS2 0xa0 ++ + #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 + #define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 + struct qcom_pcie_resources_2_1_0 { +@@ -184,6 +187,7 @@ struct qcom_pcie { + struct phy *phy; + struct gpio_desc *reset; + const struct qcom_pcie_ops *ops; ++ int gen; + }; + + #define to_qcom_pcie(x) dev_get_drvdata((x)->dev) +@@ -399,6 +403,11 @@ static int qcom_pcie_init_2_1_0(struct q + /* wait for clock acquisition */ + usleep_range(1000, 1500); + ++ if (pcie->gen == 1) { ++ val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); ++ val |= PCI_EXP_LNKSTA_CLS_2_5GB; ++ writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2); ++ } + + /* Set the Max TLP size to 2K, instead of using default of 4K */ + writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K, +@@ -1263,6 +1272,10 @@ static int qcom_pcie_probe(struct platfo + goto err_pm_runtime_put; + } + ++ pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node); ++ if (pcie->gen < 0) ++ pcie->gen = 2; ++ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf"); + pcie->parf = devm_ioremap_resource(dev, res); + if (IS_ERR(pcie->parf)) { diff --git a/ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch b/ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch new file mode 100644 index 0000000..19c3d09 --- /dev/null +++ b/ipq806x/patches-5.4/093-drivers-cpufreq-qcom-cpufreq-nvmem-support-specific-.patch @@ -0,0 +1,51 @@ +From a206d4061f1cc2c5cd17ee45c53a0ba711e48e6d Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 7 Feb 2021 16:42:52 +0100 +Subject: [PATCH 3/3] drivers: cpufreq: qcom-cpufreq-nvmem: support specific + cpufreq driver + +Add support for specific cpufreq driver for qcom-cpufreq-nvmem driver. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/qcom-cpufreq-nvmem.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c ++++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c +@@ -52,6 +52,7 @@ struct qcom_cpufreq_match_data { + char **pvs_name, + struct qcom_cpufreq_drv *drv); + const char **genpd_names; ++ const char *cpufreq_driver; + }; + + struct qcom_cpufreq_drv { +@@ -250,6 +251,7 @@ static const struct qcom_cpufreq_match_d + + static const struct qcom_cpufreq_match_data match_data_krait = { + .get_version = qcom_cpufreq_krait_name_version, ++ .cpufreq_driver = "krait-cpufreq", + }; + + static const char *qcs404_genpd_names[] = { "cpr", NULL }; +@@ -385,6 +387,19 @@ static int qcom_cpufreq_probe(struct pla + } + } + ++ if (drv->data->cpufreq_driver) { ++ cpufreq_dt_pdev = platform_device_register_simple( ++ drv->data->cpufreq_driver, -1, NULL, 0); ++ if (!IS_ERR(cpufreq_dt_pdev)) { ++ platform_set_drvdata(pdev, drv); ++ return 0; ++ } else { ++ dev_err(cpu_dev, ++ "Failed to register dedicated %s cpufreq\n", ++ drv->data->cpufreq_driver); ++ } ++ } ++ + cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, + NULL, 0); + if (!IS_ERR(cpufreq_dt_pdev)) { diff --git a/ipq806x/patches-5.4/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch b/ipq806x/patches-5.4/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch new file mode 100644 index 0000000..328942d --- /dev/null +++ b/ipq806x/patches-5.4/094-v5.7-ipq806x-net-mdio-add-ipq8064-mdio-driver.patch @@ -0,0 +1,216 @@ +From caaa71fac36ec8c19145dbf8262a9b77ab09f1a1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 4 Mar 2020 22:38:32 +0100 +Subject: net: mdio: add ipq8064 mdio driver + +Currently ipq806x soc use generic bitbang driver to +comunicate with the gmac ethernet interface. +Add a dedicated driver created by chunkeey to fix this. + +Co-developed-by: Christian Lamparter +Signed-off-by: Christian Lamparter +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/phy/Kconfig | 8 ++ + drivers/net/phy/Makefile | 1 + + drivers/net/phy/mdio-ipq8064.c | 166 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 175 insertions(+) + create mode 100644 drivers/net/phy/mdio-ipq8064.c + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -156,6 +156,14 @@ config MDIO_I2C + + This is library mode. + ++config MDIO_IPQ8064 ++ tristate "Qualcomm IPQ8064 MDIO interface support" ++ depends on HAS_IOMEM && OF_MDIO ++ depends on MFD_SYSCON ++ help ++ This driver supports the MDIO interface found in the network ++ interface units of the IPQ8064 SoC ++ + config MDIO_MOXART + tristate "MOXA ART MDIO interface support" + depends on ARCH_MOXART || COMPILE_TEST +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -50,6 +50,7 @@ obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o + obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o + obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o ++obj-$(CONFIG_MDIO_IPQ8064) += mdio-ipq8064.o + obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o + obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o + obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o +--- /dev/null ++++ b/drivers/net/phy/mdio-ipq8064.c +@@ -0,0 +1,166 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Qualcomm IPQ8064 MDIO interface driver ++ * ++ * Copyright (C) 2019 Christian Lamparter ++ * Copyright (C) 2020 Ansuel Smith ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* MII address register definitions */ ++#define MII_ADDR_REG_ADDR 0x10 ++#define MII_BUSY BIT(0) ++#define MII_WRITE BIT(1) ++#define MII_CLKRANGE_60_100M (0 << 2) ++#define MII_CLKRANGE_100_150M (1 << 2) ++#define MII_CLKRANGE_20_35M (2 << 2) ++#define MII_CLKRANGE_35_60M (3 << 2) ++#define MII_CLKRANGE_150_250M (4 << 2) ++#define MII_CLKRANGE_250_300M (5 << 2) ++#define MII_CLKRANGE_MASK GENMASK(4, 2) ++#define MII_REG_SHIFT 6 ++#define MII_REG_MASK GENMASK(10, 6) ++#define MII_ADDR_SHIFT 11 ++#define MII_ADDR_MASK GENMASK(15, 11) ++ ++#define MII_DATA_REG_ADDR 0x14 ++ ++#define MII_MDIO_DELAY_USEC (1000) ++#define MII_MDIO_RETRY_MSEC (10) ++ ++struct ipq8064_mdio { ++ struct regmap *base; /* NSS_GMAC0_BASE */ ++}; ++ ++static int ++ipq8064_mdio_wait_busy(struct ipq8064_mdio *priv) ++{ ++ u32 busy; ++ ++ return regmap_read_poll_timeout(priv->base, MII_ADDR_REG_ADDR, busy, ++ !(busy & MII_BUSY), MII_MDIO_DELAY_USEC, ++ MII_MDIO_RETRY_MSEC * USEC_PER_MSEC); ++} ++ ++static int ++ipq8064_mdio_read(struct mii_bus *bus, int phy_addr, int reg_offset) ++{ ++ u32 miiaddr = MII_BUSY | MII_CLKRANGE_250_300M; ++ struct ipq8064_mdio *priv = bus->priv; ++ u32 ret_val; ++ int err; ++ ++ /* Reject clause 45 */ ++ if (reg_offset & MII_ADDR_C45) ++ return -EOPNOTSUPP; ++ ++ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | ++ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); ++ ++ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); ++ usleep_range(8, 10); ++ ++ err = ipq8064_mdio_wait_busy(priv); ++ if (err) ++ return err; ++ ++ regmap_read(priv->base, MII_DATA_REG_ADDR, &ret_val); ++ return (int)ret_val; ++} ++ ++static int ++ipq8064_mdio_write(struct mii_bus *bus, int phy_addr, int reg_offset, u16 data) ++{ ++ u32 miiaddr = MII_WRITE | MII_BUSY | MII_CLKRANGE_250_300M; ++ struct ipq8064_mdio *priv = bus->priv; ++ ++ /* Reject clause 45 */ ++ if (reg_offset & MII_ADDR_C45) ++ return -EOPNOTSUPP; ++ ++ regmap_write(priv->base, MII_DATA_REG_ADDR, data); ++ ++ miiaddr |= ((phy_addr << MII_ADDR_SHIFT) & MII_ADDR_MASK) | ++ ((reg_offset << MII_REG_SHIFT) & MII_REG_MASK); ++ ++ regmap_write(priv->base, MII_ADDR_REG_ADDR, miiaddr); ++ usleep_range(8, 10); ++ ++ return ipq8064_mdio_wait_busy(priv); ++} ++ ++static int ++ipq8064_mdio_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct ipq8064_mdio *priv; ++ struct mii_bus *bus; ++ int ret; ++ ++ bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); ++ if (!bus) ++ return -ENOMEM; ++ ++ bus->name = "ipq8064_mdio_bus"; ++ bus->read = ipq8064_mdio_read; ++ bus->write = ipq8064_mdio_write; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev)); ++ bus->parent = &pdev->dev; ++ ++ priv = bus->priv; ++ priv->base = device_node_to_regmap(np); ++ if (IS_ERR(priv->base)) { ++ if (priv->base == ERR_PTR(-EPROBE_DEFER)) ++ return -EPROBE_DEFER; ++ ++ dev_err(&pdev->dev, "error getting device regmap, error=%pe\n", ++ priv->base); ++ return PTR_ERR(priv->base); ++ } ++ ++ ret = of_mdiobus_register(bus, np); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, bus); ++ return 0; ++} ++ ++static int ++ipq8064_mdio_remove(struct platform_device *pdev) ++{ ++ struct mii_bus *bus = platform_get_drvdata(pdev); ++ ++ mdiobus_unregister(bus); ++ ++ return 0; ++} ++ ++static const struct of_device_id ipq8064_mdio_dt_ids[] = { ++ { .compatible = "qcom,ipq8064-mdio" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids); ++ ++static struct platform_driver ipq8064_mdio_driver = { ++ .probe = ipq8064_mdio_probe, ++ .remove = ipq8064_mdio_remove, ++ .driver = { ++ .name = "ipq8064-mdio", ++ .of_match_table = ipq8064_mdio_dt_ids, ++ }, ++}; ++ ++module_platform_driver(ipq8064_mdio_driver); ++ ++MODULE_DESCRIPTION("Qualcomm IPQ8064 MDIO interface driver"); ++MODULE_AUTHOR("Christian Lamparter "); ++MODULE_AUTHOR("Ansuel Smith "); ++MODULE_LICENSE("GPL"); diff --git a/ipq806x/patches-5.4/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch b/ipq806x/patches-5.4/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch new file mode 100644 index 0000000..47dc455 --- /dev/null +++ b/ipq806x/patches-5.4/095-1-v5.9-phy-qualcomm-add-qcom-ipq806x-dwc-usb-phy-driver.patch @@ -0,0 +1,621 @@ +From ef19b117b83466e1c030368101a24367a34be7f0 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 17 Jul 2020 15:16:31 +0200 +Subject: phy: qualcomm: add qcom ipq806x dwc usb phy driver + +This has lost in the original push for the dwc3 qcom driver. +This is needed for ipq806x SoC as without this the usb ports +doesn't work at all. + +Signed-off-by: Andy Gross +Signed-off-by: Ansuel Smith +Tested-by: Jonathan McDowell +Link: https://lore.kernel.org/r/20200717131635.11076-1-ansuelsmth@gmail.com +Signed-off-by: Vinod Koul +--- + +Light modification to Kconfig as some config are missing in kernel 5.4 + + drivers/phy/qualcomm/Kconfig | 10 + + drivers/phy/qualcomm/Makefile | 1 + + drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 571 ++++++++++++++++++++++++++++ + 3 files changed, 582 insertions(+) + create mode 100644 drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c + +--- a/drivers/phy/qualcomm/Kconfig ++++ b/drivers/phy/qualcomm/Kconfig +@@ -91,3 +91,13 @@ config PHY_QCOM_USB_HSIC + select GENERIC_PHY + help + Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. ++ ++config PHY_QCOM_IPQ806X_USB ++ tristate "Qualcomm IPQ806x DWC3 USB PHY driver" ++ depends on HAS_IOMEM ++ depends on OF && (ARCH_QCOM || COMPILE_TEST) ++ select GENERIC_PHY ++ help ++ This option enables support for the Synopsis PHYs present inside the ++ Qualcomm USB3.0 DWC3 controller on ipq806x SoC. This driver supports ++ both HS and SS PHY controllers. +--- a/drivers/phy/qualcomm/Makefile ++++ b/drivers/phy/qualcomm/Makefile +@@ -10,3 +10,4 @@ obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy- + obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o + obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o + obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o ++obj-$(CONFIG_PHY_QCOM_IPQ806X_USB) += phy-qcom-ipq806x-usb.o +--- /dev/null ++++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +@@ -0,0 +1,571 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* USB QSCRATCH Hardware registers */ ++#define QSCRATCH_GENERAL_CFG (0x08) ++#define HSUSB_PHY_CTRL_REG (0x10) ++ ++/* PHY_CTRL_REG */ ++#define HSUSB_CTRL_DMSEHV_CLAMP BIT(24) ++#define HSUSB_CTRL_USB2_SUSPEND BIT(23) ++#define HSUSB_CTRL_UTMI_CLK_EN BIT(21) ++#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID BIT(20) ++#define HSUSB_CTRL_USE_CLKCORE BIT(18) ++#define HSUSB_CTRL_DPSEHV_CLAMP BIT(17) ++#define HSUSB_CTRL_COMMONONN BIT(11) ++#define HSUSB_CTRL_ID_HV_CLAMP BIT(9) ++#define HSUSB_CTRL_OTGSESSVLD_CLAMP BIT(8) ++#define HSUSB_CTRL_CLAMP_EN BIT(7) ++#define HSUSB_CTRL_RETENABLEN BIT(1) ++#define HSUSB_CTRL_POR BIT(0) ++ ++/* QSCRATCH_GENERAL_CFG */ ++#define HSUSB_GCFG_XHCI_REV BIT(2) ++ ++/* USB QSCRATCH Hardware registers */ ++#define SSUSB_PHY_CTRL_REG (0x00) ++#define SSUSB_PHY_PARAM_CTRL_1 (0x04) ++#define SSUSB_PHY_PARAM_CTRL_2 (0x08) ++#define CR_PROTOCOL_DATA_IN_REG (0x0c) ++#define CR_PROTOCOL_DATA_OUT_REG (0x10) ++#define CR_PROTOCOL_CAP_ADDR_REG (0x14) ++#define CR_PROTOCOL_CAP_DATA_REG (0x18) ++#define CR_PROTOCOL_READ_REG (0x1c) ++#define CR_PROTOCOL_WRITE_REG (0x20) ++ ++/* PHY_CTRL_REG */ ++#define SSUSB_CTRL_REF_USE_PAD BIT(28) ++#define SSUSB_CTRL_TEST_POWERDOWN BIT(27) ++#define SSUSB_CTRL_LANE0_PWR_PRESENT BIT(24) ++#define SSUSB_CTRL_SS_PHY_EN BIT(8) ++#define SSUSB_CTRL_SS_PHY_RESET BIT(7) ++ ++/* SSPHY control registers - Does this need 0x30? */ ++#define SSPHY_CTRL_RX_OVRD_IN_HI(lane) (0x1006 + 0x100 * (lane)) ++#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane) (0x1002 + 0x100 * (lane)) ++ ++/* SSPHY SoC version specific values */ ++#define SSPHY_RX_EQ_VALUE 4 /* Override value for rx_eq */ ++/* Override value for transmit preemphasis */ ++#define SSPHY_TX_DEEMPH_3_5DB 23 ++/* Override value for mpll */ ++#define SSPHY_MPLL_VALUE 0 ++ ++/* QSCRATCH PHY_PARAM_CTRL1 fields */ ++#define PHY_PARAM_CTRL1_TX_FULL_SWING_MASK GENMASK(26, 19) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK GENMASK(19, 13) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK GENMASK(13, 7) ++#define PHY_PARAM_CTRL1_LOS_BIAS_MASK GENMASK(7, 2) ++ ++#define PHY_PARAM_CTRL1_MASK \ ++ (PHY_PARAM_CTRL1_TX_FULL_SWING_MASK | \ ++ PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK | \ ++ PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK | \ ++ PHY_PARAM_CTRL1_LOS_BIAS_MASK) ++ ++#define PHY_PARAM_CTRL1_TX_FULL_SWING(x) \ ++ (((x) << 20) & PHY_PARAM_CTRL1_TX_FULL_SWING_MASK) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x) \ ++ (((x) << 14) & PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK) ++#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x) \ ++ (((x) << 8) & PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK) ++#define PHY_PARAM_CTRL1_LOS_BIAS(x) \ ++ (((x) << 3) & PHY_PARAM_CTRL1_LOS_BIAS_MASK) ++ ++/* RX OVRD IN HI bits */ ++#define RX_OVRD_IN_HI_RX_RESET_OVRD BIT(13) ++#define RX_OVRD_IN_HI_RX_RX_RESET BIT(12) ++#define RX_OVRD_IN_HI_RX_EQ_OVRD BIT(11) ++#define RX_OVRD_IN_HI_RX_EQ_MASK GENMASK(10, 7) ++#define RX_OVRD_IN_HI_RX_EQ(x) ((x) << 8) ++#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD BIT(7) ++#define RX_OVRD_IN_HI_RX_EQ_EN BIT(6) ++#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD BIT(5) ++#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK GENMASK(4, 2) ++#define RX_OVRD_IN_HI_RX_RATE_OVRD BIT(2) ++#define RX_OVRD_IN_HI_RX_RATE_MASK GENMASK(2, 0) ++ ++/* TX OVRD DRV LO register bits */ ++#define TX_OVRD_DRV_LO_AMPLITUDE_MASK GENMASK(6, 0) ++#define TX_OVRD_DRV_LO_PREEMPH_MASK GENMASK(13, 6) ++#define TX_OVRD_DRV_LO_PREEMPH(x) ((x) << 7) ++#define TX_OVRD_DRV_LO_EN BIT(14) ++ ++/* MPLL bits */ ++#define SSPHY_MPLL_MASK GENMASK(8, 5) ++#define SSPHY_MPLL(x) ((x) << 5) ++ ++/* SS CAP register bits */ ++#define SS_CR_CAP_ADDR_REG BIT(0) ++#define SS_CR_CAP_DATA_REG BIT(0) ++#define SS_CR_READ_REG BIT(0) ++#define SS_CR_WRITE_REG BIT(0) ++ ++struct usb_phy { ++ void __iomem *base; ++ struct device *dev; ++ struct clk *xo_clk; ++ struct clk *ref_clk; ++ u32 rx_eq; ++ u32 tx_deamp_3_5db; ++ u32 mpll; ++}; ++ ++struct phy_drvdata { ++ struct phy_ops ops; ++ u32 clk_rate; ++}; ++ ++/** ++ * Write register and read back masked value to confirm it is written ++ * ++ * @base - QCOM DWC3 PHY base virtual address. ++ * @offset - register offset. ++ * @mask - register bitmask specifying what should be updated ++ * @val - value to write. ++ */ ++static inline void usb_phy_write_readback(struct usb_phy *phy_dwc3, ++ u32 offset, ++ const u32 mask, u32 val) ++{ ++ u32 write_val, tmp = readl(phy_dwc3->base + offset); ++ ++ tmp &= ~mask; /* retain other bits */ ++ write_val = tmp | val; ++ ++ writel(write_val, phy_dwc3->base + offset); ++ ++ /* Read back to see if val was written */ ++ tmp = readl(phy_dwc3->base + offset); ++ tmp &= mask; /* clear other bits */ ++ ++ if (tmp != val) ++ dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n", val, offset); ++} ++ ++static int wait_for_latch(void __iomem *addr) ++{ ++ u32 retry = 10; ++ ++ while (true) { ++ if (!readl(addr)) ++ break; ++ ++ if (--retry == 0) ++ return -ETIMEDOUT; ++ ++ usleep_range(10, 20); ++ } ++ ++ return 0; ++} ++ ++/** ++ * Write SSPHY register ++ * ++ * @base - QCOM DWC3 PHY base virtual address. ++ * @addr - SSPHY address to write. ++ * @val - value to write. ++ */ ++static int usb_ss_write_phycreg(struct usb_phy *phy_dwc3, ++ u32 addr, u32 val) ++{ ++ int ret; ++ ++ writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); ++ writel(SS_CR_CAP_ADDR_REG, ++ phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ if (ret) ++ goto err_wait; ++ ++ writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); ++ writel(SS_CR_CAP_DATA_REG, ++ phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG); ++ if (ret) ++ goto err_wait; ++ ++ writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG); ++ ++err_wait: ++ if (ret) ++ dev_err(phy_dwc3->dev, "timeout waiting for latch\n"); ++ return ret; ++} ++ ++/** ++ * Read SSPHY register. ++ * ++ * @base - QCOM DWC3 PHY base virtual address. ++ * @addr - SSPHY address to read. ++ */ ++static int usb_ss_read_phycreg(struct usb_phy *phy_dwc3, ++ u32 addr, u32 *val) ++{ ++ int ret; ++ ++ writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG); ++ writel(SS_CR_CAP_ADDR_REG, ++ phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG); ++ if (ret) ++ goto err_wait; ++ ++ /* ++ * Due to hardware bug, first read of SSPHY register might be ++ * incorrect. Hence as workaround, SW should perform SSPHY register ++ * read twice, but use only second read and ignore first read. ++ */ ++ writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ if (ret) ++ goto err_wait; ++ ++ /* throwaway read */ ++ readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG); ++ ++ writel(SS_CR_READ_REG, phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ ++ ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_READ_REG); ++ if (ret) ++ goto err_wait; ++ ++ *val = readl(phy_dwc3->base + CR_PROTOCOL_DATA_OUT_REG); ++ ++err_wait: ++ return ret; ++} ++ ++static int qcom_ipq806x_usb_hs_phy_init(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ int ret; ++ u32 val; ++ ++ ret = clk_prepare_enable(phy_dwc3->xo_clk); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(phy_dwc3->ref_clk); ++ if (ret) { ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ return ret; ++ } ++ ++ /* ++ * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel ++ * enable clamping, and disable RETENTION (power-on default is ENABLED) ++ */ ++ val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP | ++ HSUSB_CTRL_RETENABLEN | HSUSB_CTRL_COMMONONN | ++ HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP | ++ HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID | ++ HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70; ++ ++ /* use core clock if external reference is not present */ ++ if (!phy_dwc3->xo_clk) ++ val |= HSUSB_CTRL_USE_CLKCORE; ++ ++ writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG); ++ usleep_range(2000, 2200); ++ ++ /* Disable (bypass) VBUS and ID filters */ ++ writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG); ++ ++ return 0; ++} ++ ++static int qcom_ipq806x_usb_hs_phy_exit(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ ++ clk_disable_unprepare(phy_dwc3->ref_clk); ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ ++ return 0; ++} ++ ++static int qcom_ipq806x_usb_ss_phy_init(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ int ret; ++ u32 data; ++ ++ ret = clk_prepare_enable(phy_dwc3->xo_clk); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(phy_dwc3->ref_clk); ++ if (ret) { ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ return ret; ++ } ++ ++ /* reset phy */ ++ data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ writel(data | SSUSB_CTRL_SS_PHY_RESET, ++ phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ usleep_range(2000, 2200); ++ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ ++ /* clear REF_PAD if we don't have XO clk */ ++ if (!phy_dwc3->xo_clk) ++ data &= ~SSUSB_CTRL_REF_USE_PAD; ++ else ++ data |= SSUSB_CTRL_REF_USE_PAD; ++ ++ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ ++ /* wait for ref clk to become stable, this can take up to 30ms */ ++ msleep(30); ++ ++ data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT; ++ writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG); ++ ++ /* ++ * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates ++ * in HS mode instead of SS mode. Workaround it by asserting ++ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode ++ */ ++ ret = usb_ss_read_phycreg(phy_dwc3, 0x102D, &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data |= (1 << 7); ++ ret = usb_ss_write_phycreg(phy_dwc3, 0x102D, data); ++ if (ret) ++ goto err_phy_trans; ++ ++ ret = usb_ss_read_phycreg(phy_dwc3, 0x1010, &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data &= ~0xff0; ++ data |= 0x20; ++ ret = usb_ss_write_phycreg(phy_dwc3, 0x1010, data); ++ if (ret) ++ goto err_phy_trans; ++ ++ /* ++ * Fix RX Equalization setting as follows ++ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 ++ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 ++ * LANE0.RX_OVRD_IN_HI.RX_EQ set based on SoC version ++ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 ++ */ ++ ret = usb_ss_read_phycreg(phy_dwc3, SSPHY_CTRL_RX_OVRD_IN_HI(0), &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data &= ~RX_OVRD_IN_HI_RX_EQ_EN; ++ data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD; ++ data &= ~RX_OVRD_IN_HI_RX_EQ_MASK; ++ data |= RX_OVRD_IN_HI_RX_EQ(phy_dwc3->rx_eq); ++ data |= RX_OVRD_IN_HI_RX_EQ_OVRD; ++ ret = usb_ss_write_phycreg(phy_dwc3, ++ SSPHY_CTRL_RX_OVRD_IN_HI(0), data); ++ if (ret) ++ goto err_phy_trans; ++ ++ /* ++ * Set EQ and TX launch amplitudes as follows ++ * LANE0.TX_OVRD_DRV_LO.PREEMPH set based on SoC version ++ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 110 ++ * LANE0.TX_OVRD_DRV_LO.EN set to 1. ++ */ ++ ret = usb_ss_read_phycreg(phy_dwc3, ++ SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK; ++ data |= TX_OVRD_DRV_LO_PREEMPH(phy_dwc3->tx_deamp_3_5db); ++ data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK; ++ data |= 0x6E; ++ data |= TX_OVRD_DRV_LO_EN; ++ ret = usb_ss_write_phycreg(phy_dwc3, ++ SSPHY_CTRL_TX_OVRD_DRV_LO(0), data); ++ if (ret) ++ goto err_phy_trans; ++ ++ data = 0; ++ data &= ~SSPHY_MPLL_MASK; ++ data |= SSPHY_MPLL(phy_dwc3->mpll); ++ usb_ss_write_phycreg(phy_dwc3, 0x30, data); ++ ++ /* ++ * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows ++ * TX_FULL_SWING [26:20] amplitude to 110 ++ * TX_DEEMPH_6DB [19:14] to 32 ++ * TX_DEEMPH_3_5DB [13:8] set based on SoC version ++ * LOS_BIAS [7:3] to 9 ++ */ ++ data = readl(phy_dwc3->base + SSUSB_PHY_PARAM_CTRL_1); ++ ++ data &= ~PHY_PARAM_CTRL1_MASK; ++ ++ data |= PHY_PARAM_CTRL1_TX_FULL_SWING(0x6e) | ++ PHY_PARAM_CTRL1_TX_DEEMPH_6DB(0x20) | ++ PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(phy_dwc3->tx_deamp_3_5db) | ++ PHY_PARAM_CTRL1_LOS_BIAS(0x9); ++ ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1, ++ PHY_PARAM_CTRL1_MASK, data); ++ ++err_phy_trans: ++ return ret; ++} ++ ++static int qcom_ipq806x_usb_ss_phy_exit(struct phy *phy) ++{ ++ struct usb_phy *phy_dwc3 = phy_get_drvdata(phy); ++ ++ /* Sequence to put SSPHY in low power state: ++ * 1. Clear REF_PHY_EN in PHY_CTRL_REG ++ * 2. Clear REF_USE_PAD in PHY_CTRL_REG ++ * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention ++ */ ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, ++ SSUSB_CTRL_SS_PHY_EN, 0x0); ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, ++ SSUSB_CTRL_REF_USE_PAD, 0x0); ++ usb_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG, ++ SSUSB_CTRL_TEST_POWERDOWN, 0x0); ++ ++ clk_disable_unprepare(phy_dwc3->ref_clk); ++ clk_disable_unprepare(phy_dwc3->xo_clk); ++ ++ return 0; ++} ++ ++static const struct phy_drvdata qcom_ipq806x_usb_hs_drvdata = { ++ .ops = { ++ .init = qcom_ipq806x_usb_hs_phy_init, ++ .exit = qcom_ipq806x_usb_hs_phy_exit, ++ .owner = THIS_MODULE, ++ }, ++ .clk_rate = 60000000, ++}; ++ ++static const struct phy_drvdata qcom_ipq806x_usb_ss_drvdata = { ++ .ops = { ++ .init = qcom_ipq806x_usb_ss_phy_init, ++ .exit = qcom_ipq806x_usb_ss_phy_exit, ++ .owner = THIS_MODULE, ++ }, ++ .clk_rate = 125000000, ++}; ++ ++static const struct of_device_id qcom_ipq806x_usb_phy_table[] = { ++ { .compatible = "qcom,ipq806x-usb-phy-hs", ++ .data = &qcom_ipq806x_usb_hs_drvdata }, ++ { .compatible = "qcom,ipq806x-usb-phy-ss", ++ .data = &qcom_ipq806x_usb_ss_drvdata }, ++ { /* Sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, qcom_ipq806x_usb_phy_table); ++ ++static int qcom_ipq806x_usb_phy_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ resource_size_t size; ++ struct phy *generic_phy; ++ struct usb_phy *phy_dwc3; ++ const struct phy_drvdata *data; ++ struct phy_provider *phy_provider; ++ ++ phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL); ++ if (!phy_dwc3) ++ return -ENOMEM; ++ ++ data = of_device_get_match_data(&pdev->dev); ++ ++ phy_dwc3->dev = &pdev->dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; ++ size = resource_size(res); ++ phy_dwc3->base = devm_ioremap(phy_dwc3->dev, res->start, size); ++ ++ if (IS_ERR(phy_dwc3->base)) { ++ dev_err(phy_dwc3->dev, "failed to map reg\n"); ++ return PTR_ERR(phy_dwc3->base); ++ } ++ ++ phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref"); ++ if (IS_ERR(phy_dwc3->ref_clk)) { ++ dev_dbg(phy_dwc3->dev, "cannot get reference clock\n"); ++ return PTR_ERR(phy_dwc3->ref_clk); ++ } ++ ++ clk_set_rate(phy_dwc3->ref_clk, data->clk_rate); ++ ++ phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo"); ++ if (IS_ERR(phy_dwc3->xo_clk)) { ++ dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n"); ++ phy_dwc3->xo_clk = NULL; ++ } ++ ++ /* Parse device node to probe HSIO settings */ ++ if (device_property_read_u32(&pdev->dev, "qcom,rx-eq", ++ &phy_dwc3->rx_eq)) ++ phy_dwc3->rx_eq = SSPHY_RX_EQ_VALUE; ++ ++ if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db", ++ &phy_dwc3->tx_deamp_3_5db)) ++ phy_dwc3->rx_eq = SSPHY_TX_DEEMPH_3_5DB; ++ ++ if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll)) ++ phy_dwc3->mpll = SSPHY_MPLL_VALUE; ++ ++ generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node, &data->ops); ++ ++ if (IS_ERR(generic_phy)) ++ return PTR_ERR(generic_phy); ++ ++ phy_set_drvdata(generic_phy, phy_dwc3); ++ platform_set_drvdata(pdev, phy_dwc3); ++ ++ phy_provider = devm_of_phy_provider_register(phy_dwc3->dev, ++ of_phy_simple_xlate); ++ ++ if (IS_ERR(phy_provider)) ++ return PTR_ERR(phy_provider); ++ ++ return 0; ++} ++ ++static struct platform_driver qcom_ipq806x_usb_phy_driver = { ++ .probe = qcom_ipq806x_usb_phy_probe, ++ .driver = { ++ .name = "qcom-ipq806x-usb-phy", ++ .owner = THIS_MODULE, ++ .of_match_table = qcom_ipq806x_usb_phy_table, ++ }, ++}; ++ ++module_platform_driver(qcom_ipq806x_usb_phy_driver); ++ ++MODULE_ALIAS("platform:phy-qcom-ipq806x-usb"); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Andy Gross "); ++MODULE_AUTHOR("Ivan T. Ivanov "); ++MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver"); diff --git a/ipq806x/patches-5.4/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch b/ipq806x/patches-5.4/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch new file mode 100644 index 0000000..dedbb51 --- /dev/null +++ b/ipq806x/patches-5.4/095-2-v5.9-phy-qualcomm-fix-setting-of-tx_deamp_3_5db-when-device-property-read-fails.patch @@ -0,0 +1,31 @@ +From 3d7b0ca5300bd01b176f2b4c10e173db802560d8 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Tue, 21 Jul 2020 16:06:13 +0100 +Subject: phy: qualcomm: fix setting of tx_deamp_3_5db when device property + read fails + +Currently when reading of the device property for "qcom,tx-deamp_3_5db" +fails the default is being assigned incorrectly to phy_dwc3->rx_eq. This +looks like a copy-n-paste error and in fact should be assigning the +default instead to phy_dwc3->tx_deamp_3_5db + +Addresses-Coverity: ("Copy-paste error") +Fixes: ef19b117b834 ("phy: qualcomm: add qcom ipq806x dwc usb phy driver") +Signed-off-by: Colin Ian King +Link: https://lore.kernel.org/r/20200721150613.416876-1-colin.king@canonical.com +Signed-off-by: Vinod Koul +--- + drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c ++++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +@@ -531,7 +531,7 @@ static int qcom_ipq806x_usb_phy_probe(st + + if (device_property_read_u32(&pdev->dev, "qcom,tx-deamp_3_5db", + &phy_dwc3->tx_deamp_3_5db)) +- phy_dwc3->rx_eq = SSPHY_TX_DEEMPH_3_5DB; ++ phy_dwc3->tx_deamp_3_5db = SSPHY_TX_DEEMPH_3_5DB; + + if (device_property_read_u32(&pdev->dev, "qcom,mpll", &phy_dwc3->mpll)) + phy_dwc3->mpll = SSPHY_MPLL_VALUE; diff --git a/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch b/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch new file mode 100644 index 0000000..d671110 --- /dev/null +++ b/ipq806x/patches-5.4/098-1-cpufreq-add-Krait-dedicated-scaling-driver.patch @@ -0,0 +1,681 @@ +From cc41a266280cad0b55319e614167c88dff344248 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 16:33:10 +0100 +Subject: [PATCH 1/8] cpufreq: add Krait dedicated scaling driver + +This new driver is based on generic cpufreq-dt driver. +Krait SoCs have 2-4 cpu and one shared L2 cache that can +operate at different frequency based on the maximum cpu clk +across all core. +L2 frequency and voltage are scaled on every frequency change +if needed. On Krait SoCs is present a bug that can cause +transition problem between frequency bin, to workaround this +on more than one transition, the L2 frequency is first set to the +base rate and then to the target rate. +The L2 frequency use the OPP framework and use the opp-level +bindings to link the l2 freq to different cpu freq. This is needed +as the Krait l2 clk are note mapped 1:1 to the core clks and some +of the l2 clk is set based on a range of the cpu clks. If the driver +find a broken config (for example no opp-level set) the l2 scaling is +skipped. + +Signed-off-by: Ansuel Smith +--- + drivers/cpufreq/Kconfig.arm | 14 +- + drivers/cpufreq/Makefile | 2 + + drivers/cpufreq/qcom-cpufreq-krait.c | 589 +++++++++++++++++++++++++++ + 3 files changed, 604 insertions(+), 1 deletion(-) + create mode 100644 drivers/cpufreq/qcom-cpufreq-krait.c + +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -155,6 +155,18 @@ config ARM_QCOM_CPUFREQ_HW + The driver implements the cpufreq interface for this HW engine. + Say Y if you want to support CPUFreq HW. + ++config ARM_QCOM_CPUFREQ_KRAIT ++ tristate "CPU Frequency scaling support for Krait SoCs" ++ depends on ARCH_QCOM || COMPILE_TEST ++ select PM_OPP ++ select ARM_QCOM_CPUFREQ_NVMEM ++ help ++ This adds the CPUFreq driver for Qualcomm Krait SoC based boards. ++ This scale the cache clk and regulator based on the different cpu ++ clks when scaling the different cores clk. ++ ++ If in doubt, say N. ++ + config ARM_RASPBERRYPI_CPUFREQ + tristate "Raspberry Pi cpufreq support" + depends on CLK_RASPBERRYPI || COMPILE_TEST +@@ -338,4 +350,4 @@ config ARM_PXA2xx_CPUFREQ + help + This add the CPUFreq driver support for Intel PXA2xx SOCs. + +- If in doubt, say N. ++ If in doubt, say N. +\ No newline at end of file +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -65,6 +65,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2 + obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o + obj-$(CONFIG_ARM_QCOM_CPUFREQ_NVMEM) += qcom-cpufreq-nvmem.o ++obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRAIT) += qcom-cpufreq-krait.o + obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o + obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o + obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o +@@ -87,6 +88,7 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += te + obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o + obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o + obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o ++obj-$(CONFIG_ARM_KRAIT_CPUFREQ) += krait-cpufreq.o + + + ################################################################################## +--- /dev/null ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -0,0 +1,603 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpufreq-dt.h" ++ ++static struct platform_device *l2_pdev; ++ ++struct private_data { ++ struct opp_table *opp_table; ++ struct device *cpu_dev; ++ const char *reg_name; ++ bool have_static_opps; ++}; ++ ++static int set_target(struct cpufreq_policy *policy, unsigned int index) ++{ ++ struct private_data *priv = policy->driver_data; ++ unsigned long freq = policy->freq_table[index].frequency; ++ unsigned long target_freq = freq * 1000; ++ struct dev_pm_opp *opp; ++ unsigned int level; ++ int cpu, ret; ++ ++ if (l2_pdev) { ++ int policy_cpu = policy->cpu; ++ ++ /* find the max freq across all core */ ++ for_each_present_cpu(cpu) ++ if (cpu != policy_cpu) ++ target_freq = max( ++ target_freq, ++ (unsigned long)cpufreq_quick_get(cpu)); ++ ++ opp = dev_pm_opp_find_freq_exact(priv->cpu_dev, target_freq, ++ true); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, "failed to find OPP for %ld\n", ++ target_freq); ++ return PTR_ERR(opp); ++ } ++ level = dev_pm_opp_get_level(opp); ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Hardware constraint: ++ * Krait CPU cannot operate at 384MHz with L2 at 1Ghz. ++ * Assume index 0 with the idle freq and level > 0 as ++ * any L2 freq > 384MHz. ++ * Skip CPU freq change in this corner case. ++ */ ++ if (unlikely(index == 0 && level != 0)) { ++ dev_err(priv->cpu_dev, "Krait CPU can't operate at idle freq with L2 at 1GHz"); ++ return -EINVAL; ++ } ++ ++ opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); ++ if (IS_ERR(opp)) { ++ dev_err(&l2_pdev->dev, ++ "failed to find level OPP for %d\n", level); ++ return PTR_ERR(opp); ++ } ++ target_freq = dev_pm_opp_get_freq(opp); ++ dev_pm_opp_put(opp); ++ ++ ret = dev_pm_opp_set_rate(&l2_pdev->dev, target_freq); ++ if (ret) ++ return ret; ++ } ++ ++ ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); ++ if (ret) ++ return ret; ++ ++ arch_set_freq_scale(policy->related_cpus, freq, ++ policy->cpuinfo.max_freq); ++ ++ return 0; ++} ++ ++/* ++ * An earlier version of opp-v1 bindings used to name the regulator ++ * "cpu0-supply", we still need to handle that for backwards compatibility. ++ */ ++static const char *find_supply_name(struct device *dev) ++{ ++ struct device_node *np; ++ struct property *pp; ++ int cpu = dev->id; ++ const char *name = NULL; ++ ++ np = of_node_get(dev->of_node); ++ ++ /* This must be valid for sure */ ++ if (WARN_ON(!np)) ++ return NULL; ++ ++ /* Try "cpu0" for older DTs */ ++ if (!cpu) { ++ pp = of_find_property(np, "cpu0-supply", NULL); ++ if (pp) { ++ name = "cpu0"; ++ goto node_put; ++ } ++ } ++ ++ pp = of_find_property(np, "cpu-supply", NULL); ++ if (pp) { ++ name = "cpu"; ++ goto node_put; ++ } ++ ++ dev_dbg(dev, "no regulator for cpu%d\n", cpu); ++node_put: ++ of_node_put(np); ++ return name; ++} ++ ++static int resources_available(void) ++{ ++ struct device *cpu_dev; ++ struct regulator *cpu_reg; ++ struct clk *cpu_clk; ++ int ret = 0; ++ const char *name; ++ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ ret = PTR_ERR_OR_ZERO(cpu_clk); ++ if (ret) { ++ /* ++ * If cpu's clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "clock not ready, retry\n"); ++ else ++ dev_err(cpu_dev, "failed to get clock: %d\n", ret); ++ ++ return ret; ++ } ++ ++ clk_put(cpu_clk); ++ ++ name = find_supply_name(cpu_dev); ++ /* Platform doesn't require regulator */ ++ if (!name) ++ return 0; ++ ++ cpu_reg = regulator_get_optional(cpu_dev, name); ++ ret = PTR_ERR_OR_ZERO(cpu_reg); ++ if (ret) { ++ /* ++ * If cpu's regulator supply node is present, but regulator is ++ * not yet registered, we should try defering probe. ++ */ ++ if (ret == -EPROBE_DEFER) ++ dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n"); ++ else ++ dev_dbg(cpu_dev, "no regulator for cpu0: %d\n", ret); ++ ++ return ret; ++ } ++ ++ regulator_put(cpu_reg); ++ return 0; ++} ++ ++static int cpufreq_init(struct cpufreq_policy *policy) ++{ ++ struct cpufreq_frequency_table *freq_table; ++ struct opp_table *opp_table = NULL; ++ unsigned int transition_latency; ++ struct private_data *priv; ++ struct device *cpu_dev; ++ bool fallback = false; ++ struct clk *cpu_clk; ++ const char *name; ++ int ret; ++ ++ cpu_dev = get_cpu_device(policy->cpu); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu%d device\n", policy->cpu); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, NULL); ++ if (IS_ERR(cpu_clk)) { ++ ret = PTR_ERR(cpu_clk); ++ dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); ++ return ret; ++ } ++ ++ /* Get OPP-sharing information from "operating-points-v2" bindings */ ++ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) { ++ if (ret != -ENOENT) ++ goto out_put_clk; ++ ++ /* ++ * operating-points-v2 not supported, fallback to old method of ++ * finding shared-OPPs for backward compatibility if the ++ * platform hasn't set sharing CPUs. ++ */ ++ if (dev_pm_opp_get_sharing_cpus(cpu_dev, policy->cpus)) ++ fallback = true; ++ } ++ ++ /* ++ * OPP layer will be taking care of regulators now, but it needs to know ++ * the name of the regulator first. ++ */ ++ name = find_supply_name(cpu_dev); ++ if (name) { ++ opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1); ++ if (IS_ERR(opp_table)) { ++ ret = PTR_ERR(opp_table); ++ dev_err(cpu_dev, ++ "Failed to set regulator for cpu%d: %d\n", ++ policy->cpu, ret); ++ goto out_put_clk; ++ } ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto out_put_regulator; ++ } ++ ++ priv->reg_name = name; ++ priv->opp_table = opp_table; ++ ++ /* ++ * Initialize OPP tables for all policy->cpus. They will be shared by ++ * all CPUs which have marked their CPUs shared with OPP bindings. ++ * ++ * For platforms not using operating-points-v2 bindings, we do this ++ * before updating policy->cpus. Otherwise, we will end up creating ++ * duplicate OPPs for policy->cpus. ++ * ++ * OPPs might be populated at runtime, don't check for error here ++ */ ++ if (!dev_pm_opp_of_cpumask_add_table(policy->cpus)) ++ priv->have_static_opps = true; ++ ++ /* ++ * But we need OPP table to function so if it is not there let's ++ * give platform code chance to provide it for us. ++ */ ++ ret = dev_pm_opp_get_opp_count(cpu_dev); ++ if (ret <= 0) { ++ dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n"); ++ ret = -EPROBE_DEFER; ++ goto out_free_opp; ++ } ++ ++ if (fallback) { ++ cpumask_setall(policy->cpus); ++ ++ /* ++ * OPP tables are initialized only for policy->cpu, do it for ++ * others as well. ++ */ ++ ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus); ++ if (ret) ++ dev_err(cpu_dev, ++ "%s: failed to mark OPPs as shared: %d\n", ++ __func__, ret); ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); ++ goto out_free_opp; ++ } ++ ++ priv->cpu_dev = cpu_dev; ++ ++ policy->driver_data = priv; ++ policy->clk = cpu_clk; ++ policy->freq_table = freq_table; ++ ++ policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; ++ ++ transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); ++ if (!transition_latency) ++ transition_latency = CPUFREQ_ETERNAL; ++ ++ policy->cpuinfo.transition_latency = transition_latency; ++ policy->dvfs_possible_from_any_cpu = true; ++ ++ dev_pm_opp_of_register_em(policy->cpus); ++ ++ return 0; ++ ++out_free_opp: ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->cpus); ++ kfree(priv); ++out_put_regulator: ++ if (name) ++ dev_pm_opp_put_regulators(opp_table); ++out_put_clk: ++ clk_put(cpu_clk); ++ ++ return ret; ++} ++ ++static int cpufreq_online(struct cpufreq_policy *policy) ++{ ++ /* We did light-weight tear down earlier, nothing to do here */ ++ return 0; ++} ++ ++static int cpufreq_offline(struct cpufreq_policy *policy) ++{ ++ /* ++ * Preserve policy->driver_data and don't free resources on light-weight ++ * tear down. ++ */ ++ return 0; ++} ++ ++static int cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ struct private_data *priv = policy->driver_data; ++ ++ dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); ++ if (priv->have_static_opps) ++ dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); ++ if (priv->reg_name) ++ dev_pm_opp_put_regulators(priv->opp_table); ++ ++ clk_put(policy->clk); ++ kfree(priv); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver krait_cpufreq_driver = { ++ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | ++ CPUFREQ_IS_COOLING_DEV, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = set_target, ++ .get = cpufreq_generic_get, ++ .init = cpufreq_init, ++ .exit = cpufreq_exit, ++ .online = cpufreq_online, ++ .offline = cpufreq_offline, ++ .name = "krait-cpufreq", ++ .suspend = cpufreq_generic_suspend, ++}; ++ ++struct krait_data { ++ unsigned long idle_freq; ++ bool regulator_enabled; ++}; ++ ++static int krait_cache_set_opp(struct dev_pm_set_opp_data *data) ++{ ++ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; ++ struct dev_pm_opp_supply *supply = &data->new_opp.supplies[0]; ++ struct regulator *reg = data->regulators[0]; ++ struct clk *clk = data->clk; ++ struct krait_data *kdata; ++ unsigned long idle_freq; ++ int ret; ++ ++ kdata = (struct krait_data *)dev_get_drvdata(data->dev); ++ idle_freq = kdata->idle_freq; ++ ++ /* Scaling up? Scale voltage before frequency */ ++ if (freq >= old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ if (ret) ++ goto exit; ++ } ++ ++ /* ++ * Set to idle bin if switching from normal to high bin ++ * or vice versa. It has been notice that a bug is triggered ++ * in cache scaling when more than one bin is scaled, to fix ++ * this we first need to transition to the base rate and then ++ * to target rate ++ */ ++ if (likely(freq != idle_freq && old_freq != idle_freq)) { ++ ret = clk_set_rate(clk, idle_freq); ++ if (ret) ++ goto exit; ++ } ++ ++ ret = clk_set_rate(clk, freq); ++ if (ret) ++ goto exit; ++ ++ /* Scaling down? Scale voltage after frequency */ ++ if (freq < old_freq) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ } ++ ++ if (unlikely(!kdata->regulator_enabled)) { ++ ret = regulator_enable(reg); ++ if (ret < 0) ++ dev_warn(data->dev, "Failed to enable regulator: %d", ret); ++ else ++ kdata->regulator_enabled = true; ++ } ++ ++exit: ++ return ret; ++}; ++ ++static int krait_cache_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct krait_data *data; ++ struct opp_table *table; ++ struct dev_pm_opp *opp; ++ struct device *cpu_dev; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ table = dev_pm_opp_set_regulators(dev, (const char *[]){ "l2" }, 1); ++ if (IS_ERR(table)) { ++ ret = PTR_ERR(table); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to set regulators %d\n", ret); ++ ++ return ret; ++ } ++ ++ ret = PTR_ERR_OR_ZERO( ++ dev_pm_opp_register_set_opp_helper(dev, krait_cache_set_opp)); ++ if (ret) ++ return ret; ++ ++ ret = dev_pm_opp_of_add_table(dev); ++ if (ret) { ++ dev_err(dev, "failed to parse L2 freq thresholds\n"); ++ return ret; ++ } ++ ++ opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq); ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check opp-level configuration ++ * At least 2 level must be set or the cache will always be scaled ++ * the idle freq causing some performance problem ++ * ++ * In case of invalid configuration, the l2 scaling is skipped ++ */ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ /* ++ * Check if we have at least opp-level 1, 0 should always be set to ++ * the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of l2 opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ /* ++ * Check if we have at least opp-level 1 in the cpu opp, 0 should always ++ * be set to the idle freq ++ */ ++ opp = dev_pm_opp_find_level_exact(cpu_dev, 1); ++ if (IS_ERR(opp)) { ++ dev_err(dev, ++ "Invalid configuration found of cpu opp. Can't find opp-level 1"); ++ goto invalid_conf; ++ } ++ dev_pm_opp_put(opp); ++ ++ platform_set_drvdata(pdev, data); ++ ++ /* The l2 scaling is enabled by linking the cpufreq driver */ ++ l2_pdev = pdev; ++ ++ return 0; ++ ++invalid_conf: ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return -EINVAL; ++}; ++ ++static int krait_cache_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct opp_table *table = dev_pm_opp_get_opp_table(dev); ++ ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ ++ return 0; ++}; ++ ++static const struct of_device_id krait_cache_match_table[] = { ++ { .compatible = "qcom,krait-cache" }, ++ {} ++}; ++ ++static struct platform_driver krait_cache_driver = { ++ .driver = { ++ .name = "krait-cache", ++ .of_match_table = krait_cache_match_table, ++ }, ++ .probe = krait_cache_probe, ++ .remove = krait_cache_remove, ++}; ++module_platform_driver(krait_cache_driver); ++ ++static int krait_cpufreq_probe(struct platform_device *pdev) ++{ ++ struct cpufreq_dt_platform_data *data = dev_get_platdata(&pdev->dev); ++ int ret; ++ ++ /* ++ * All per-cluster (CPUs sharing clock/voltages) initialization is done ++ * from ->init(). In probe(), we just need to make sure that clk and ++ * regulators are available. Else defer probe and retry. ++ * ++ * FIXME: Is checking this only for CPU0 sufficient ? ++ */ ++ ret = resources_available(); ++ if (ret) ++ return ret; ++ ++ if (data) { ++ if (data->have_governor_per_policy) ++ krait_cpufreq_driver.flags |= ++ CPUFREQ_HAVE_GOVERNOR_PER_POLICY; ++ ++ krait_cpufreq_driver.resume = data->resume; ++ if (data->suspend) ++ krait_cpufreq_driver.suspend = data->suspend; ++ } ++ ++ ret = cpufreq_register_driver(&krait_cpufreq_driver); ++ if (ret) ++ dev_err(&pdev->dev, "failed register driver: %d\n", ret); ++ ++ return ret; ++} ++ ++static int krait_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&krait_cpufreq_driver); ++ return 0; ++} ++ ++static struct platform_driver krait_cpufreq_platdrv = { ++ .driver = { ++ .name = "krait-cpufreq", ++ }, ++ .probe = krait_cpufreq_probe, ++ .remove = krait_cpufreq_remove, ++}; ++module_platform_driver(krait_cpufreq_platdrv); ++ ++MODULE_ALIAS("platform:krait-cpufreq"); ++MODULE_AUTHOR("Ansuel Smith "); ++MODULE_DESCRIPTION("Dedicated Krait SoC cpufreq driver"); ++MODULE_LICENSE("GPL"); diff --git a/ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch b/ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch new file mode 100644 index 0000000..316e18b --- /dev/null +++ b/ipq806x/patches-5.4/098-2-Documentation-cpufreq-add-qcom-krait-cpufreq-binding.patch @@ -0,0 +1,237 @@ +From c9ecd920324a647bf1f2b47f771c8f599cc7b551 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 22 Feb 2020 18:02:17 +0100 +Subject: [PATCH 2/8] Documentation: cpufreq: add qcom,krait-cache bindings + +Document dedicated cpufreq for Krait CPUs. + +Signed-off-by: Ansuel Smith +--- + .../bindings/cpufreq/qcom-cpufreq-krait.yaml | 221 ++++++++++++++++++ + 1 file changed, 221 insertions(+) + create mode 100644 Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-krait.yaml +@@ -0,0 +1,221 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/cpufreq/qcom-cpufreq-krait.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: CPU Frequency scaling driver for Krait SoCs ++ ++maintainers: ++ - Ansuel Smith ++ ++description: | ++ The krait cpufreq driver is a dedicated frequency scaling driver ++ based on cpufreq-dt generic driver that scale L2 cache and the ++ cores. TEST ++ ++ The L2 cache is scaled based on the max clk across all cores and ++ the clock is decided based on the opp-level set in the device tree. ++ ++ Different core freq can be linked to a specific l2 freq and the driver ++ on frequency change will scale the core and the l2 clk based of the ++ linked freq. ++ ++ On Krait SoC is present a bug and on every L2 clk change the driver ++ needs to set the clk to the idle freq before changing it to the new value. ++ ++ This requires the qcom cpufreq nvmem driver to parse the different opp ++ core clk and an additional opp table for the l2 scaling. ++ ++ If the driver detect broken config (for example missing opp-level) the ++ cpufreq driver skips the l2 scaling ++ ++ Referring to this example opp-level can be used to link a range of cpu freq ++ to a specific l2 freq: ++ cpu opp freq 384000000 has opp-level 0 ++ l2 opp freq 384000000 has opp-level 0 ++ The driver will scale l2 to 384000000 ++ ++ cpu opp freq 600000000-1000000000 has opp-level 1 ++ l2 opp freq 1000000000 has opp-level 1 ++ The driver will scale l2 to 1000000000 ++ ++allOf: ++ - $ref: /schemas/cache-controller.yaml# ++ ++select: ++ properties: ++ compatible: ++ items: ++ - enum: ++ - qcom,krait-cache ++ ++ required: ++ - compatible ++ ++properties: ++ compatible: ++ items: ++ - const: qcom,krait-cache ++ - const: cache ++ ++ cache-level: ++ const: 2 ++ ++ clocks: ++ maxItems: 1 ++ ++ clock-names: ++ const: l2 ++ ++ l2-supply: true ++ ++ operating-points-v2: true ++ ++required: ++ - compatible ++ - cache-level ++ - clocks ++ - clock-names ++ - l2-supply ++ - operating-points-v2 ++ ++additionalProperties: false ++ ++examples: ++ - | ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "qcom,krait"; ++ enable-method = "qcom,kpss-acc-v1"; ++ device_type = "cpu"; ++ reg = <0>; ++ next-level-cache = <&L2>; ++ qcom,acc = <&acc0>; ++ qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ cpu-supply = <&smb208_s2a>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; ++ }; ++ ++ /* ... */ ++ ++ }; ++ ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1000000>; ++ opp-microvolt-speed0-pvs1-v0 = <925000>; ++ opp-microvolt-speed0-pvs2-v0 = <875000>; ++ opp-microvolt-speed0-pvs3-v0 = <800000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <975000>; ++ opp-microvolt-speed0-pvs2-v0 = <925000>; ++ opp-microvolt-speed0-pvs3-v0 = <850000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1100000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000>; ++ opp-microvolt-speed0-pvs2-v0 = <995000>; ++ opp-microvolt-speed0-pvs3-v0 = <900000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1150000>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000>; ++ opp-microvolt-speed0-pvs3-v0 = <950000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1200000>; ++ opp-microvolt-speed0-pvs1-v0 = <1125000>; ++ opp-microvolt-speed0-pvs2-v0 = <1075000>; ++ opp-microvolt-speed0-pvs3-v0 = <1000000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1250000>; ++ opp-microvolt-speed0-pvs1-v0 = <1175000>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000>; ++ opp-microvolt-speed0-pvs3-v0 = <1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ soc { ++ L2: l2-cache { ++ compatible = "qcom,krait-cache", "cache"; ++ cache-level = <2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ l2-supply = <&smb208_s1a>; ++ operating-points-v2 = <&opp_table_l2>; ++ }; ++ }; ++ ++... diff --git a/ipq806x/patches-5.4/098-3-add-fab-scaling-support-with-cpufreq.patch b/ipq806x/patches-5.4/098-3-add-fab-scaling-support-with-cpufreq.patch new file mode 100644 index 0000000..8ce3f06 --- /dev/null +++ b/ipq806x/patches-5.4/098-3-add-fab-scaling-support-with-cpufreq.patch @@ -0,0 +1,243 @@ +--- a/drivers/clk/qcom/Makefile ++++ b/drivers/clk/qcom/Makefile +@@ -15,6 +15,7 @@ clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-k + clk-qcom-y += clk-hfpll.o + clk-qcom-y += reset.o + clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o ++clk-qcom-y += fab_scaling.o + + # Keep alphabetically sorted by config + obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o +--- /dev/null ++++ b/drivers/clk/qcom/fab_scaling.c +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct qcom_fab_scaling_data { ++ u32 fab_freq_high; ++ u32 fab_freq_nominal; ++ u32 cpu_freq_threshold; ++ struct clk *apps_fab_clk; ++ struct clk *ddr_fab_clk; ++}; ++ ++static struct qcom_fab_scaling_data *drv_data; ++ ++int scale_fabrics(unsigned long max_cpu_freq) ++{ ++ struct clk *apps_fab_clk = drv_data->apps_fab_clk, ++ *ddr_fab_clk = drv_data->ddr_fab_clk; ++ unsigned long target_freq, cur_freq; ++ int ret; ++ ++ /* Skip fab scaling if the driver is not ready */ ++ if (!apps_fab_clk || !ddr_fab_clk) ++ return 0; ++ ++ if (max_cpu_freq > drv_data->cpu_freq_threshold) ++ target_freq = drv_data->fab_freq_high; ++ else ++ target_freq = drv_data->fab_freq_nominal; ++ ++ cur_freq = clk_get_rate(ddr_fab_clk); ++ ++ if (target_freq != cur_freq) { ++ ret = clk_set_rate(apps_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ ret = clk_set_rate(ddr_fab_clk, target_freq); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(scale_fabrics); ++ ++static int ipq806x_fab_scaling_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct clk *apps_fab_clk, *ddr_fab_clk; ++ int ret; ++ ++ if (!np) ++ return -ENODEV; ++ ++ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); ++ if (!drv_data) ++ return -ENOMEM; ++ ++ if (of_property_read_u32(np, "fab_freq_high", &drv_data->fab_freq_high)) { ++ pr_err("FABRICS turbo freq not found. Using defaults...\n"); ++ drv_data->fab_freq_high = 533000000; ++ } ++ ++ if (of_property_read_u32(np, "fab_freq_nominal", &drv_data->fab_freq_nominal)) { ++ pr_err("FABRICS nominal freq not found. Using defaults...\n"); ++ drv_data->fab_freq_nominal = 400000000; ++ } ++ ++ if (of_property_read_u32(np, "cpu_freq_threshold", &drv_data->cpu_freq_threshold)) { ++ pr_err("FABRICS cpu freq threshold not found. Using defaults...\n"); ++ drv_data->cpu_freq_threshold = 1000000000; ++ } ++ ++ apps_fab_clk = devm_clk_get(&pdev->dev, "apps-fab-clk"); ++ ret = PTR_ERR_OR_ZERO(apps_fab_clk); ++ if (ret) { ++ /* ++ * If apps fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get APPS FABRIC clock: %d\n", ret); ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_prepare_enable(apps_fab_clk); ++ clk_set_rate(apps_fab_clk, drv_data->fab_freq_high); ++ drv_data->apps_fab_clk = apps_fab_clk; ++ ++ ddr_fab_clk = devm_clk_get(&pdev->dev, "ddr-fab-clk"); ++ ret = PTR_ERR_OR_ZERO(ddr_fab_clk); ++ if (ret) { ++ /* ++ * If ddr fab clk node is present, but clock is not yet ++ * registered, we should try defering probe. ++ */ ++ if (ret != -EPROBE_DEFER) { ++ pr_err("Failed to get DDR FABRIC clock: %d\n", ret); ++ ddr_fab_clk = NULL; ++ ret = -ENODEV; ++ } ++ goto err; ++ } ++ ++ clk_prepare_enable(ddr_fab_clk); ++ clk_set_rate(ddr_fab_clk, drv_data->fab_freq_high); ++ drv_data->ddr_fab_clk = ddr_fab_clk; ++ ++ return 0; ++err: ++ kfree(drv_data); ++ return ret; ++} ++ ++static int ipq806x_fab_scaling_remove(struct platform_device *pdev) ++{ ++ kfree(drv_data); ++ return 0; ++} ++ ++static const struct of_device_id fab_scaling_ipq806x_match_table[] = { ++ { .compatible = "qcom,fab-scaling" }, ++ { } ++}; ++ ++static struct platform_driver fab_scaling_ipq806x_driver = { ++ .probe = ipq806x_fab_scaling_probe, ++ .remove = ipq806x_fab_scaling_remove, ++ .driver = { ++ .name = "fab-scaling", ++ .of_match_table = fab_scaling_ipq806x_match_table, ++ }, ++}; ++ ++static int __init fab_scaling_ipq806x_init(void) ++{ ++ return platform_driver_register(&fab_scaling_ipq806x_driver); ++} ++late_initcall(fab_scaling_ipq806x_init); ++ ++static void __exit fab_scaling_ipq806x_exit(void) ++{ ++ platform_driver_unregister(&fab_scaling_ipq806x_driver); ++} ++module_exit(fab_scaling_ipq806x_exit); +--- /dev/null ++++ b/include/linux/fab_scaling.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++ ++#ifndef __FAB_SCALING_H ++#define __FAB_SCALING_H ++ ++/** ++ * scale_fabrics - Scale DDR and APPS FABRICS ++ * ++ * This function monitors all the registered clocks and does APPS ++ * and DDR FABRIC scaling based on the idle frequencies with which ++ * it was registered. ++ * ++ */ ++int scale_fabrics(unsigned long max_cpu_freq); ++ ++#endif +--- a/drivers/cpufreq/qcom-cpufreq-krait.c ++++ b/drivers/cpufreq/qcom-cpufreq-krait.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include "cpufreq-dt.h" + +@@ -68,6 +69,13 @@ static int set_target(struct cpufreq_pol + return -EINVAL; + } + ++ /* ++ * Scale fabrics with max freq across all cores ++ */ ++ ret = scale_fabrics(target_freq); ++ if (ret) ++ return ret; ++ + opp = dev_pm_opp_find_level_exact(&l2_pdev->dev, level); + if (IS_ERR(opp)) { + dev_err(&l2_pdev->dev, diff --git a/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch b/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch new file mode 100644 index 0000000..3c497ea --- /dev/null +++ b/ipq806x/patches-5.4/100-dwmac-ipq806x-qsgmii-pcs-all-ch-ctl.patch @@ -0,0 +1,83 @@ +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -64,6 +64,17 @@ + #define NSS_COMMON_CLK_DIV_SGMII_100 4 + #define NSS_COMMON_CLK_DIV_SGMII_10 49 + ++#define QSGMII_PCS_ALL_CH_CTL 0x80 ++#define QSGMII_PCS_CH_SPEED_FORCE 0x2 ++#define QSGMII_PCS_CH_SPEED_10 0x0 ++#define QSGMII_PCS_CH_SPEED_100 0x4 ++#define QSGMII_PCS_CH_SPEED_1000 0x8 ++#define QSGMII_PCS_CH_SPEED_MASK (QSGMII_PCS_CH_SPEED_FORCE | \ ++ QSGMII_PCS_CH_SPEED_10 | \ ++ QSGMII_PCS_CH_SPEED_100 | \ ++ QSGMII_PCS_CH_SPEED_1000) ++#define QSGMII_PCS_CH_SPEED_SHIFT(x) (x * 4) ++ + #define QSGMII_PCS_CAL_LCKDT_CTL 0x120 + #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) + +@@ -241,6 +252,36 @@ static void ipq806x_gmac_fix_mac_speed(v + ipq806x_gmac_set_speed(gmac, speed); + } + ++static int ++ipq806x_gmac_get_qsgmii_pcs_speed_val(struct platform_device *pdev) { ++ struct device_node *fixed_link_node; ++ int rv; ++ int fixed_link_speed; ++ ++ if (!of_phy_is_fixed_link(pdev->dev.of_node)) ++ return 0; ++ ++ fixed_link_node = of_get_child_by_name(pdev->dev.of_node, "fixed-link"); ++ if (!fixed_link_node) ++ return -1; ++ ++ rv = of_property_read_u32(fixed_link_node, "speed", &fixed_link_speed); ++ of_node_put(fixed_link_node); ++ if (rv) ++ return -1; ++ ++ switch (fixed_link_speed) { ++ case SPEED_1000: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_1000; ++ case SPEED_100: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_100; ++ case SPEED_10: ++ return QSGMII_PCS_CH_SPEED_FORCE | QSGMII_PCS_CH_SPEED_10; ++ } ++ ++ return -1; ++} ++ + static int ipq806x_gmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -249,6 +290,7 @@ static int ipq806x_gmac_probe(struct pla + struct ipq806x_gmac *gmac; + int val; + int err; ++ int qsgmii_pcs_speed; + + val = stmmac_get_platform_resources(pdev, &stmmac_res); + if (val) +@@ -345,6 +387,17 @@ static int ipq806x_gmac_probe(struct pla + 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | + 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | + 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); ++ ++ qsgmii_pcs_speed = ipq806x_gmac_get_qsgmii_pcs_speed_val(pdev); ++ if (qsgmii_pcs_speed != -1) { ++ regmap_update_bits( ++ gmac->qsgmii_csr, ++ QSGMII_PCS_ALL_CH_CTL, ++ QSGMII_PCS_CH_SPEED_MASK << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), ++ qsgmii_pcs_speed << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id)); ++ } + } + + plat_dat->has_gmac = true; diff --git a/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch b/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch new file mode 100644 index 0000000..2d24da0 --- /dev/null +++ b/ipq806x/patches-5.4/100-v5.11-dmaengine-qcom-add_ADM_driver.patch @@ -0,0 +1,965 @@ +From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001 +From: Jonathan McDowell +Date: Sat, 14 Nov 2020 14:02:33 +0000 +Subject: dmaengine: qcom: Add ADM driver + +Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA +controller found in the MSM8x60 and IPQ/APQ8064 platforms. + +The ADM supports both memory to memory transactions and memory +to/from peripheral device transactions. The controller also provides +flow control capabilities for transactions to/from peripheral devices. + +The initial release of this driver supports slave transfers to/from +peripherals and also incorporates CRCI (client rate control interface) +flow control. + +The hardware only supports a 32 bit physical address, so specifying +!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to +spend effort on kludging things in the code that will never actually be +needed on real hardware. + +Signed-off-by: Andy Gross +Signed-off-by: Thomas Pedersen +Signed-off-by: Jonathan McDowell +Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li +Signed-off-by: Vinod Koul +--- + drivers/dma/qcom/Kconfig | 11 + + drivers/dma/qcom/Makefile | 1 + + drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 915 insertions(+) + create mode 100644 drivers/dma/qcom/qcom_adm.c + +--- a/drivers/dma/qcom/Kconfig ++++ b/drivers/dma/qcom/Kconfig +@@ -1,4 +1,15 @@ + # SPDX-License-Identifier: GPL-2.0-only ++config QCOM_ADM ++ tristate "Qualcomm ADM support" ++ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT ++ select DMA_ENGINE ++ select DMA_VIRTUAL_CHANNELS ++ help ++ Enable support for the Qualcomm Application Data Mover (ADM) DMA ++ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. ++ This controller provides DMA capabilities for both general purpose ++ and on-chip peripheral devices. ++ + config QCOM_BAM_DMA + tristate "QCOM BAM DMA support" + depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) +--- a/drivers/dma/qcom/Makefile ++++ b/drivers/dma/qcom/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_QCOM_ADM) += qcom_adm.o + obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o + obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o + hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o +--- /dev/null ++++ b/drivers/dma/qcom/qcom_adm.c +@@ -0,0 +1,903 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../dmaengine.h" ++#include "../virt-dma.h" ++ ++/* ADM registers - calculated from channel number and security domain */ ++#define ADM_CHAN_MULTI 0x4 ++#define ADM_CI_MULTI 0x4 ++#define ADM_CRCI_MULTI 0x4 ++#define ADM_EE_MULTI 0x800 ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) ++#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) ++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) ++#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) ++#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) ++#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) ++#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) ++#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) ++#define ADM_GP_CTL 0x3d8 ++#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ ++ ADM_EE_OFFS(ee)) ++ ++/* channel status */ ++#define ADM_CH_STATUS_VALID BIT(1) ++ ++/* channel result */ ++#define ADM_CH_RSLT_VALID BIT(31) ++#define ADM_CH_RSLT_ERR BIT(3) ++#define ADM_CH_RSLT_FLUSH BIT(2) ++#define ADM_CH_RSLT_TPD BIT(1) ++ ++/* channel conf */ ++#define ADM_CH_CONF_SHADOW_EN BIT(12) ++#define ADM_CH_CONF_MPU_DISABLE BIT(11) ++#define ADM_CH_CONF_PERM_MPU_CONF BIT(9) ++#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) ++#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) ++ ++/* channel result conf */ ++#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) ++#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) ++ ++/* CRCI CTL */ ++#define ADM_CRCI_CTL_MUX_SEL BIT(18) ++#define ADM_CRCI_CTL_RST BIT(17) ++ ++/* CI configuration */ ++#define ADM_CI_RANGE_END(x) ((x) << 24) ++#define ADM_CI_RANGE_START(x) ((x) << 16) ++#define ADM_CI_BURST_4_WORDS BIT(2) ++#define ADM_CI_BURST_8_WORDS BIT(3) ++ ++/* GP CTL */ ++#define ADM_GP_CTL_LP_EN BIT(12) ++#define ADM_GP_CTL_LP_CNT(x) ((x) << 8) ++ ++/* Command pointer list entry */ ++#define ADM_CPLE_LP BIT(31) ++#define ADM_CPLE_CMD_PTR_LIST BIT(29) ++ ++/* Command list entry */ ++#define ADM_CMD_LC BIT(31) ++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) ++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) ++ ++#define ADM_CMD_TYPE_SINGLE 0x0 ++#define ADM_CMD_TYPE_BOX 0x3 ++ ++#define ADM_CRCI_MUX_SEL BIT(4) ++#define ADM_DESC_ALIGN 8 ++#define ADM_MAX_XFER (SZ_64K - 1) ++#define ADM_MAX_ROWS (SZ_64K - 1) ++#define ADM_MAX_CHANNELS 16 ++ ++struct adm_desc_hw_box { ++ u32 cmd; ++ u32 src_addr; ++ u32 dst_addr; ++ u32 row_len; ++ u32 num_rows; ++ u32 row_offset; ++}; ++ ++struct adm_desc_hw_single { ++ u32 cmd; ++ u32 src_addr; ++ u32 dst_addr; ++ u32 len; ++}; ++ ++struct adm_async_desc { ++ struct virt_dma_desc vd; ++ struct adm_device *adev; ++ ++ size_t length; ++ enum dma_transfer_direction dir; ++ dma_addr_t dma_addr; ++ size_t dma_len; ++ ++ void *cpl; ++ dma_addr_t cp_addr; ++ u32 crci; ++ u32 mux; ++ u32 blk_size; ++}; ++ ++struct adm_chan { ++ struct virt_dma_chan vc; ++ struct adm_device *adev; ++ ++ /* parsed from DT */ ++ u32 id; /* channel id */ ++ ++ struct adm_async_desc *curr_txd; ++ struct dma_slave_config slave; ++ struct list_head node; ++ ++ int error; ++ int initialized; ++}; ++ ++static inline struct adm_chan *to_adm_chan(struct dma_chan *common) ++{ ++ return container_of(common, struct adm_chan, vc.chan); ++} ++ ++struct adm_device { ++ void __iomem *regs; ++ struct device *dev; ++ struct dma_device common; ++ struct device_dma_parameters dma_parms; ++ struct adm_chan *channels; ++ ++ u32 ee; ++ ++ struct clk *core_clk; ++ struct clk *iface_clk; ++ ++ struct reset_control *clk_reset; ++ struct reset_control *c0_reset; ++ struct reset_control *c1_reset; ++ struct reset_control *c2_reset; ++ int irq; ++}; ++ ++/** ++ * adm_free_chan - Frees dma resources associated with the specific channel ++ * ++ * Free all allocated descriptors associated with this channel ++ * ++ */ ++static void adm_free_chan(struct dma_chan *chan) ++{ ++ /* free all queued descriptors */ ++ vchan_free_chan_resources(to_virt_chan(chan)); ++} ++ ++/** ++ * adm_get_blksize - Get block size from burst value ++ * ++ */ ++static int adm_get_blksize(unsigned int burst) ++{ ++ int ret; ++ ++ switch (burst) { ++ case 16: ++ case 32: ++ case 64: ++ case 128: ++ ret = ffs(burst >> 4) - 1; ++ break; ++ case 192: ++ ret = 4; ++ break; ++ case 256: ++ ret = 5; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/** ++ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers ++ * ++ * @achan: ADM channel ++ * @desc: Descriptor memory pointer ++ * @sg: Scatterlist entry ++ * @crci: CRCI value ++ * @burst: Burst size of transaction ++ * @direction: DMA transfer direction ++ */ ++static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, u32 crci, ++ u32 burst, ++ enum dma_transfer_direction direction) ++{ ++ struct adm_desc_hw_box *box_desc = NULL; ++ struct adm_desc_hw_single *single_desc; ++ u32 remainder = sg_dma_len(sg); ++ u32 rows, row_offset, crci_cmd; ++ u32 mem_addr = sg_dma_address(sg); ++ u32 *incr_addr = &mem_addr; ++ u32 *src, *dst; ++ ++ if (direction == DMA_DEV_TO_MEM) { ++ crci_cmd = ADM_CMD_SRC_CRCI(crci); ++ row_offset = burst; ++ src = &achan->slave.src_addr; ++ dst = &mem_addr; ++ } else { ++ crci_cmd = ADM_CMD_DST_CRCI(crci); ++ row_offset = burst << 16; ++ src = &mem_addr; ++ dst = &achan->slave.dst_addr; ++ } ++ ++ while (remainder >= burst) { ++ box_desc = desc; ++ box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd; ++ box_desc->row_offset = row_offset; ++ box_desc->src_addr = *src; ++ box_desc->dst_addr = *dst; ++ ++ rows = remainder / burst; ++ rows = min_t(u32, rows, ADM_MAX_ROWS); ++ box_desc->num_rows = rows << 16 | rows; ++ box_desc->row_len = burst << 16 | burst; ++ ++ *incr_addr += burst * rows; ++ remainder -= burst * rows; ++ desc += sizeof(*box_desc); ++ } ++ ++ /* if leftover bytes, do one single descriptor */ ++ if (remainder) { ++ single_desc = desc; ++ single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd; ++ single_desc->len = remainder; ++ single_desc->src_addr = *src; ++ single_desc->dst_addr = *dst; ++ desc += sizeof(*single_desc); ++ ++ if (sg_is_last(sg)) ++ single_desc->cmd |= ADM_CMD_LC; ++ } else { ++ if (box_desc && sg_is_last(sg)) ++ box_desc->cmd |= ADM_CMD_LC; ++ } ++ ++ return desc; ++} ++ ++/** ++ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers ++ * ++ * @achan: ADM channel ++ * @desc: Descriptor memory pointer ++ * @sg: Scatterlist entry ++ * @direction: DMA transfer direction ++ */ ++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, ++ struct scatterlist *sg, ++ enum dma_transfer_direction direction) ++{ ++ struct adm_desc_hw_single *single_desc; ++ u32 remainder = sg_dma_len(sg); ++ u32 mem_addr = sg_dma_address(sg); ++ u32 *incr_addr = &mem_addr; ++ u32 *src, *dst; ++ ++ if (direction == DMA_DEV_TO_MEM) { ++ src = &achan->slave.src_addr; ++ dst = &mem_addr; ++ } else { ++ src = &mem_addr; ++ dst = &achan->slave.dst_addr; ++ } ++ ++ do { ++ single_desc = desc; ++ single_desc->cmd = ADM_CMD_TYPE_SINGLE; ++ single_desc->src_addr = *src; ++ single_desc->dst_addr = *dst; ++ single_desc->len = (remainder > ADM_MAX_XFER) ? ++ ADM_MAX_XFER : remainder; ++ ++ remainder -= single_desc->len; ++ *incr_addr += single_desc->len; ++ desc += sizeof(*single_desc); ++ } while (remainder); ++ ++ /* set last command if this is the end of the whole transaction */ ++ if (sg_is_last(sg)) ++ single_desc->cmd |= ADM_CMD_LC; ++ ++ return desc; ++} ++ ++/** ++ * adm_prep_slave_sg - Prep slave sg transaction ++ * ++ * @chan: dma channel ++ * @sgl: scatter gather list ++ * @sg_len: length of sg ++ * @direction: DMA transfer direction ++ * @flags: DMA flags ++ * @context: transfer context (unused) ++ */ ++static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, ++ struct scatterlist *sgl, ++ unsigned int sg_len, ++ enum dma_transfer_direction direction, ++ unsigned long flags, ++ void *context) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct adm_device *adev = achan->adev; ++ struct adm_async_desc *async_desc; ++ struct scatterlist *sg; ++ dma_addr_t cple_addr; ++ u32 i, burst; ++ u32 single_count = 0, box_count = 0, crci = 0; ++ void *desc; ++ u32 *cple; ++ int blk_size = 0; ++ ++ if (!is_slave_direction(direction)) { ++ dev_err(adev->dev, "invalid dma direction\n"); ++ return NULL; ++ } ++ ++ /* ++ * get burst value from slave configuration ++ */ ++ burst = (direction == DMA_MEM_TO_DEV) ? ++ achan->slave.dst_maxburst : ++ achan->slave.src_maxburst; ++ ++ /* if using flow control, validate burst and crci values */ ++ if (achan->slave.device_fc) { ++ blk_size = adm_get_blksize(burst); ++ if (blk_size < 0) { ++ dev_err(adev->dev, "invalid burst value: %d\n", ++ burst); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ crci = achan->slave.slave_id & 0xf; ++ if (!crci || achan->slave.slave_id > 0x1f) { ++ dev_err(adev->dev, "invalid crci value\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ ++ /* iterate through sgs and compute allocation size of structures */ ++ for_each_sg(sgl, sg, sg_len, i) { ++ if (achan->slave.device_fc) { ++ box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst, ++ ADM_MAX_ROWS); ++ if (sg_dma_len(sg) % burst) ++ single_count++; ++ } else { ++ single_count += DIV_ROUND_UP(sg_dma_len(sg), ++ ADM_MAX_XFER); ++ } ++ } ++ ++ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); ++ if (!async_desc) ++ return ERR_PTR(-ENOMEM); ++ ++ if (crci) ++ async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ? ++ ADM_CRCI_CTL_MUX_SEL : 0; ++ async_desc->crci = crci; ++ async_desc->blk_size = blk_size; ++ async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) + ++ box_count * sizeof(struct adm_desc_hw_box) + ++ sizeof(*cple) + 2 * ADM_DESC_ALIGN; ++ ++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); ++ if (!async_desc->cpl) ++ goto free; ++ ++ async_desc->adev = adev; ++ ++ /* both command list entry and descriptors must be 8 byte aligned */ ++ cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN); ++ desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN); ++ ++ for_each_sg(sgl, sg, sg_len, i) { ++ async_desc->length += sg_dma_len(sg); ++ ++ if (achan->slave.device_fc) ++ desc = adm_process_fc_descriptors(achan, desc, sg, crci, ++ burst, direction); ++ else ++ desc = adm_process_non_fc_descriptors(achan, desc, sg, ++ direction); ++ } ++ ++ async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, ++ async_desc->dma_len, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(adev->dev, async_desc->dma_addr)) ++ goto free; ++ ++ cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl); ++ ++ /* init cmd list */ ++ dma_sync_single_for_cpu(adev->dev, cple_addr, sizeof(*cple), ++ DMA_TO_DEVICE); ++ *cple = ADM_CPLE_LP; ++ *cple |= (async_desc->dma_addr + ADM_DESC_ALIGN) >> 3; ++ dma_sync_single_for_device(adev->dev, cple_addr, sizeof(*cple), ++ DMA_TO_DEVICE); ++ ++ return vchan_tx_prep(&achan->vc, &async_desc->vd, flags); ++ ++free: ++ kfree(async_desc); ++ return ERR_PTR(-ENOMEM); ++} ++ ++/** ++ * adm_terminate_all - terminate all transactions on a channel ++ * @achan: adm dma channel ++ * ++ * Dequeues and frees all transactions, aborts current transaction ++ * No callbacks are done ++ * ++ */ ++static int adm_terminate_all(struct dma_chan *chan) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct adm_device *adev = achan->adev; ++ unsigned long flags; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ vchan_get_all_descriptors(&achan->vc, &head); ++ ++ /* send flush command to terminate current transaction */ ++ writel_relaxed(0x0, ++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ ++ vchan_dma_desc_free_list(&achan->vc, &head); ++ ++ return 0; ++} ++ ++static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ unsigned long flag; ++ ++ spin_lock_irqsave(&achan->vc.lock, flag); ++ memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); ++ spin_unlock_irqrestore(&achan->vc.lock, flag); ++ ++ return 0; ++} ++ ++/** ++ * adm_start_dma - start next transaction ++ * @achan - ADM dma channel ++ */ ++static void adm_start_dma(struct adm_chan *achan) ++{ ++ struct virt_dma_desc *vd = vchan_next_desc(&achan->vc); ++ struct adm_device *adev = achan->adev; ++ struct adm_async_desc *async_desc; ++ ++ lockdep_assert_held(&achan->vc.lock); ++ ++ if (!vd) ++ return; ++ ++ list_del(&vd->node); ++ ++ /* write next command list out to the CMD FIFO */ ++ async_desc = container_of(vd, struct adm_async_desc, vd); ++ achan->curr_txd = async_desc; ++ ++ /* reset channel error */ ++ achan->error = 0; ++ ++ if (!achan->initialized) { ++ /* enable interrupts */ ++ writel(ADM_CH_CONF_SHADOW_EN | ++ ADM_CH_CONF_PERM_MPU_CONF | ++ ADM_CH_CONF_MPU_DISABLE | ++ ADM_CH_CONF_SEC_DOMAIN(adev->ee), ++ adev->regs + ADM_CH_CONF(achan->id)); ++ ++ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, ++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ ++ achan->initialized = 1; ++ } ++ ++ /* set the crci block size if this transaction requires CRCI */ ++ if (async_desc->crci) { ++ writel(async_desc->mux | async_desc->blk_size, ++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); ++ } ++ ++ /* make sure IRQ enable doesn't get reordered */ ++ wmb(); ++ ++ /* write next command list out to the CMD FIFO */ ++ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, ++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); ++} ++ ++/** ++ * adm_dma_irq - irq handler for ADM controller ++ * @irq: IRQ of interrupt ++ * @data: callback data ++ * ++ * IRQ handler for the bam controller ++ */ ++static irqreturn_t adm_dma_irq(int irq, void *data) ++{ ++ struct adm_device *adev = data; ++ u32 srcs, i; ++ struct adm_async_desc *async_desc; ++ unsigned long flags; ++ ++ srcs = readl_relaxed(adev->regs + ++ ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee)); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) { ++ struct adm_chan *achan = &adev->channels[i]; ++ u32 status, result; ++ ++ if (srcs & BIT(i)) { ++ status = readl_relaxed(adev->regs + ++ ADM_CH_STATUS_SD(i, adev->ee)); ++ ++ /* if no result present, skip */ ++ if (!(status & ADM_CH_STATUS_VALID)) ++ continue; ++ ++ result = readl_relaxed(adev->regs + ++ ADM_CH_RSLT(i, adev->ee)); ++ ++ /* no valid results, skip */ ++ if (!(result & ADM_CH_RSLT_VALID)) ++ continue; ++ ++ /* flag error if transaction was flushed or failed */ ++ if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH)) ++ achan->error = 1; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ async_desc = achan->curr_txd; ++ ++ achan->curr_txd = NULL; ++ ++ if (async_desc) { ++ vchan_cookie_complete(&async_desc->vd); ++ ++ /* kick off next DMA */ ++ adm_start_dma(achan); ++ } ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * adm_tx_status - returns status of transaction ++ * @chan: dma channel ++ * @cookie: transaction cookie ++ * @txstate: DMA transaction state ++ * ++ * Return status of dma transaction ++ */ ++static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ struct virt_dma_desc *vd; ++ enum dma_status ret; ++ unsigned long flags; ++ size_t residue = 0; ++ ++ ret = dma_cookie_status(chan, cookie, txstate); ++ if (ret == DMA_COMPLETE || !txstate) ++ return ret; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ ++ vd = vchan_find_desc(&achan->vc, cookie); ++ if (vd) ++ residue = container_of(vd, struct adm_async_desc, vd)->length; ++ ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++ ++ /* ++ * residue is either the full length if it is in the issued list, or 0 ++ * if it is in progress. We have no reliable way of determining ++ * anything inbetween ++ */ ++ dma_set_residue(txstate, residue); ++ ++ if (achan->error) ++ return DMA_ERROR; ++ ++ return ret; ++} ++ ++/** ++ * adm_issue_pending - starts pending transactions ++ * @chan: dma channel ++ * ++ * Issues all pending transactions and starts DMA ++ */ ++static void adm_issue_pending(struct dma_chan *chan) ++{ ++ struct adm_chan *achan = to_adm_chan(chan); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&achan->vc.lock, flags); ++ ++ if (vchan_issue_pending(&achan->vc) && !achan->curr_txd) ++ adm_start_dma(achan); ++ spin_unlock_irqrestore(&achan->vc.lock, flags); ++} ++ ++/** ++ * adm_dma_free_desc - free descriptor memory ++ * @vd: virtual descriptor ++ * ++ */ ++static void adm_dma_free_desc(struct virt_dma_desc *vd) ++{ ++ struct adm_async_desc *async_desc = container_of(vd, ++ struct adm_async_desc, vd); ++ ++ dma_unmap_single(async_desc->adev->dev, async_desc->dma_addr, ++ async_desc->dma_len, DMA_TO_DEVICE); ++ kfree(async_desc->cpl); ++ kfree(async_desc); ++} ++ ++static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, ++ u32 index) ++{ ++ achan->id = index; ++ achan->adev = adev; ++ ++ vchan_init(&achan->vc, &adev->common); ++ achan->vc.desc_free = adm_dma_free_desc; ++} ++ ++static int adm_dma_probe(struct platform_device *pdev) ++{ ++ struct adm_device *adev; ++ int ret; ++ u32 i; ++ ++ adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL); ++ if (!adev) ++ return -ENOMEM; ++ ++ adev->dev = &pdev->dev; ++ ++ adev->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(adev->regs)) ++ return PTR_ERR(adev->regs); ++ ++ adev->irq = platform_get_irq(pdev, 0); ++ if (adev->irq < 0) ++ return adev->irq; ++ ++ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee); ++ if (ret) { ++ dev_err(adev->dev, "Execution environment unspecified\n"); ++ return ret; ++ } ++ ++ adev->core_clk = devm_clk_get(adev->dev, "core"); ++ if (IS_ERR(adev->core_clk)) ++ return PTR_ERR(adev->core_clk); ++ ++ adev->iface_clk = devm_clk_get(adev->dev, "iface"); ++ if (IS_ERR(adev->iface_clk)) ++ return PTR_ERR(adev->iface_clk); ++ ++ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); ++ if (IS_ERR(adev->clk_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 reset\n"); ++ return PTR_ERR(adev->clk_reset); ++ } ++ ++ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); ++ if (IS_ERR(adev->c0_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); ++ return PTR_ERR(adev->c0_reset); ++ } ++ ++ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); ++ if (IS_ERR(adev->c1_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); ++ return PTR_ERR(adev->c1_reset); ++ } ++ ++ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); ++ if (IS_ERR(adev->c2_reset)) { ++ dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); ++ return PTR_ERR(adev->c2_reset); ++ } ++ ++ ret = clk_prepare_enable(adev->core_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable core clock\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(adev->iface_clk); ++ if (ret) { ++ dev_err(adev->dev, "failed to prepare/enable iface clock\n"); ++ goto err_disable_core_clk; ++ } ++ ++ reset_control_assert(adev->clk_reset); ++ reset_control_assert(adev->c0_reset); ++ reset_control_assert(adev->c1_reset); ++ reset_control_assert(adev->c2_reset); ++ ++ udelay(2); ++ ++ reset_control_deassert(adev->clk_reset); ++ reset_control_deassert(adev->c0_reset); ++ reset_control_deassert(adev->c1_reset); ++ reset_control_deassert(adev->c2_reset); ++ ++ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, ++ sizeof(*adev->channels), GFP_KERNEL); ++ ++ if (!adev->channels) { ++ ret = -ENOMEM; ++ goto err_disable_clks; ++ } ++ ++ /* allocate and initialize channels */ ++ INIT_LIST_HEAD(&adev->common.channels); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) ++ adm_channel_init(adev, &adev->channels[i], i); ++ ++ /* reset CRCIs */ ++ for (i = 0; i < 16; i++) ++ writel(ADM_CRCI_CTL_RST, adev->regs + ++ ADM_CRCI_CTL(i, adev->ee)); ++ ++ /* configure client interfaces */ ++ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); ++ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); ++ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | ++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); ++ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), ++ adev->regs + ADM_GP_CTL); ++ ++ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, ++ 0, "adm_dma", adev); ++ if (ret) ++ goto err_disable_clks; ++ ++ platform_set_drvdata(pdev, adev); ++ ++ adev->common.dev = adev->dev; ++ adev->common.dev->dma_parms = &adev->dma_parms; ++ ++ /* set capabilities */ ++ dma_cap_zero(adev->common.cap_mask); ++ dma_cap_set(DMA_SLAVE, adev->common.cap_mask); ++ dma_cap_set(DMA_PRIVATE, adev->common.cap_mask); ++ ++ /* initialize dmaengine apis */ ++ adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV); ++ adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; ++ adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ adev->common.device_free_chan_resources = adm_free_chan; ++ adev->common.device_prep_slave_sg = adm_prep_slave_sg; ++ adev->common.device_issue_pending = adm_issue_pending; ++ adev->common.device_tx_status = adm_tx_status; ++ adev->common.device_terminate_all = adm_terminate_all; ++ adev->common.device_config = adm_slave_config; ++ ++ ret = dma_async_device_register(&adev->common); ++ if (ret) { ++ dev_err(adev->dev, "failed to register dma async device\n"); ++ goto err_disable_clks; ++ } ++ ++ ret = of_dma_controller_register(pdev->dev.of_node, ++ of_dma_xlate_by_chan_id, ++ &adev->common); ++ if (ret) ++ goto err_unregister_dma; ++ ++ return 0; ++ ++err_unregister_dma: ++ dma_async_device_unregister(&adev->common); ++err_disable_clks: ++ clk_disable_unprepare(adev->iface_clk); ++err_disable_core_clk: ++ clk_disable_unprepare(adev->core_clk); ++ ++ return ret; ++} ++ ++static int adm_dma_remove(struct platform_device *pdev) ++{ ++ struct adm_device *adev = platform_get_drvdata(pdev); ++ struct adm_chan *achan; ++ u32 i; ++ ++ of_dma_controller_free(pdev->dev.of_node); ++ dma_async_device_unregister(&adev->common); ++ ++ for (i = 0; i < ADM_MAX_CHANNELS; i++) { ++ achan = &adev->channels[i]; ++ ++ /* mask IRQs for this channel/EE pair */ ++ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); ++ ++ tasklet_kill(&adev->channels[i].vc.task); ++ adm_terminate_all(&adev->channels[i].vc.chan); ++ } ++ ++ devm_free_irq(adev->dev, adev->irq, adev); ++ ++ clk_disable_unprepare(adev->core_clk); ++ clk_disable_unprepare(adev->iface_clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id adm_of_match[] = { ++ { .compatible = "qcom,adm", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, adm_of_match); ++ ++static struct platform_driver adm_dma_driver = { ++ .probe = adm_dma_probe, ++ .remove = adm_dma_remove, ++ .driver = { ++ .name = "adm-dma-engine", ++ .of_match_table = adm_of_match, ++ }, ++}; ++ ++module_platform_driver(adm_dma_driver); ++ ++MODULE_AUTHOR("Andy Gross "); ++MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch b/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch new file mode 100644 index 0000000..a78dc82 --- /dev/null +++ b/ipq806x/patches-5.4/101-5.12-mtd-parsers-Add-Qcom-SMEM-parser.patch @@ -0,0 +1,217 @@ +From 803eb124e1a64e42888542c3444bfe6dac412c7f Mon Sep 17 00:00:00 2001 +From: Manivannan Sadhasivam +Date: Mon, 4 Jan 2021 09:41:35 +0530 +Subject: mtd: parsers: Add Qcom SMEM parser + +NAND based Qualcomm platforms have the partition table populated in the +Shared Memory (SMEM). Hence, add a parser for parsing the partitions +from it. + +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20210104041137.113075-3-manivannan.sadhasivam@linaro.org +--- + drivers/mtd/parsers/Kconfig | 8 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/qcomsmempart.c | 170 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 179 insertions(+) + create mode 100644 drivers/mtd/parsers/qcomsmempart.c + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -196,6 +196,14 @@ config MTD_REDBOOT_PARTS_READONLY + + endif # MTD_REDBOOT_PARTS + ++config MTD_QCOMSMEM_PARTS ++ tristate "Qualcomm SMEM NAND flash partition parser" ++ depends on MTD_NAND_QCOM || COMPILE_TEST ++ depends on QCOM_SMEM ++ help ++ This provides support for parsing partitions from Shared Memory (SMEM) ++ for NAND flash on Qualcomm platforms. ++ + config MTD_ROUTERBOOT_PARTS + tristate "RouterBoot flash partition parser" + depends on MTD && OF +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -13,4 +13,5 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o ++obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o + obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o +--- /dev/null ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -0,0 +1,170 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Qualcomm SMEM NAND flash partition parser ++ * ++ * Copyright (C) 2020, Linaro Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SMEM_AARM_PARTITION_TABLE 9 ++#define SMEM_APPS 0 ++ ++#define SMEM_FLASH_PART_MAGIC1 0x55ee73aa ++#define SMEM_FLASH_PART_MAGIC2 0xe35ebddb ++#define SMEM_FLASH_PTABLE_V3 3 ++#define SMEM_FLASH_PTABLE_V4 4 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V3 16 ++#define SMEM_FLASH_PTABLE_MAX_PARTS_V4 48 ++#define SMEM_FLASH_PTABLE_HDR_LEN (4 * sizeof(u32)) ++#define SMEM_FLASH_PTABLE_NAME_SIZE 16 ++ ++/** ++ * struct smem_flash_pentry - SMEM Flash partition entry ++ * @name: Name of the partition ++ * @offset: Offset in blocks ++ * @length: Length of the partition in blocks ++ * @attr: Flags for this partition ++ */ ++struct smem_flash_pentry { ++ char name[SMEM_FLASH_PTABLE_NAME_SIZE]; ++ __le32 offset; ++ __le32 length; ++ u8 attr; ++} __packed __aligned(4); ++ ++/** ++ * struct smem_flash_ptable - SMEM Flash partition table ++ * @magic1: Partition table Magic 1 ++ * @magic2: Partition table Magic 2 ++ * @version: Partition table version ++ * @numparts: Number of partitions in this ptable ++ * @pentry: Flash partition entries belonging to this ptable ++ */ ++struct smem_flash_ptable { ++ __le32 magic1; ++ __le32 magic2; ++ __le32 version; ++ __le32 numparts; ++ struct smem_flash_pentry pentry[SMEM_FLASH_PTABLE_MAX_PARTS_V4]; ++} __packed __aligned(4); ++ ++static int parse_qcomsmem_part(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct smem_flash_pentry *pentry; ++ struct smem_flash_ptable *ptable; ++ size_t len = SMEM_FLASH_PTABLE_HDR_LEN; ++ struct mtd_partition *parts; ++ int ret, i, numparts; ++ char *name, *c; ++ ++ pr_debug("Parsing partition table info from SMEM\n"); ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR(ptable)) { ++ pr_err("Error reading partition table header\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ /* Verify ptable magic */ ++ if (le32_to_cpu(ptable->magic1) != SMEM_FLASH_PART_MAGIC1 || ++ le32_to_cpu(ptable->magic2) != SMEM_FLASH_PART_MAGIC2) { ++ pr_err("Partition table magic verification failed\n"); ++ return -EINVAL; ++ } ++ ++ /* Ensure that # of partitions is less than the max we have allocated */ ++ numparts = le32_to_cpu(ptable->numparts); ++ if (numparts > SMEM_FLASH_PTABLE_MAX_PARTS_V4) { ++ pr_err("Partition numbers exceed the max limit\n"); ++ return -EINVAL; ++ } ++ ++ /* Find out length of partition data based on table version */ ++ if (le32_to_cpu(ptable->version) <= SMEM_FLASH_PTABLE_V3) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V3 * ++ sizeof(struct smem_flash_pentry); ++ } else if (le32_to_cpu(ptable->version) == SMEM_FLASH_PTABLE_V4) { ++ len = SMEM_FLASH_PTABLE_HDR_LEN + SMEM_FLASH_PTABLE_MAX_PARTS_V4 * ++ sizeof(struct smem_flash_pentry); ++ } else { ++ pr_err("Unknown ptable version (%d)", le32_to_cpu(ptable->version)); ++ return -EINVAL; ++ } ++ ++ /* ++ * Now that the partition table header has been parsed, verified ++ * and the length of the partition table calculated, read the ++ * complete partition table ++ */ ++ ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); ++ if (IS_ERR_OR_NULL(ptable)) { ++ pr_err("Error reading partition table\n"); ++ return PTR_ERR(ptable); ++ } ++ ++ parts = kcalloc(numparts, sizeof(*parts), GFP_KERNEL); ++ if (!parts) ++ return -ENOMEM; ++ ++ for (i = 0; i < numparts; i++) { ++ pentry = &ptable->pentry[i]; ++ if (pentry->name[0] == '\0') ++ continue; ++ ++ name = kstrdup(pentry->name, GFP_KERNEL); ++ if (!name) { ++ ret = -ENOMEM; ++ goto out_free_parts; ++ } ++ ++ /* Convert name to lower case */ ++ for (c = name; *c != '\0'; c++) ++ *c = tolower(*c); ++ ++ parts[i].name = name; ++ parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; ++ parts[i].mask_flags = pentry->attr; ++ parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", ++ i, pentry->name, le32_to_cpu(pentry->offset), ++ le32_to_cpu(pentry->length), pentry->attr); ++ } ++ ++ pr_debug("SMEM partition table found: ver: %d len: %d\n", ++ le32_to_cpu(ptable->version), numparts); ++ *pparts = parts; ++ ++ return numparts; ++ ++out_free_parts: ++ while (--i >= 0) ++ kfree(parts[i].name); ++ kfree(parts); ++ *pparts = NULL; ++ ++ return ret; ++} ++ ++static const struct of_device_id qcomsmem_of_match_table[] = { ++ { .compatible = "qcom,smem-part" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, qcomsmem_of_match_table); ++ ++static struct mtd_part_parser mtd_parser_qcomsmem = { ++ .parse_fn = parse_qcomsmem_part, ++ .name = "qcomsmem", ++ .of_match_table = qcomsmem_of_match_table, ++}; ++module_mtd_part_parser(mtd_parser_qcomsmem); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Manivannan Sadhasivam "); ++MODULE_DESCRIPTION("Qualcomm SMEM NAND flash partition parser"); diff --git a/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 0000000..e838729 --- /dev/null +++ b/ipq806x/patches-5.4/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,24 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin +--- + drivers/mtd/parsers/qcomsmempart.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/parsers/qcomsmempart.c ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -132,6 +132,11 @@ static int parse_qcomsmem_part(struct mt + parts[i].offset = le32_to_cpu(pentry->offset) * mtd->erasesize; + parts[i].mask_flags = pentry->attr; + parts[i].size = le32_to_cpu(pentry->length) * mtd->erasesize; ++ ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(mtd) && !strcmp(name, "rootfs")) ++ parts[i].name = "ubi"; ++ + pr_debug("%d: %s offs=0x%08x size=0x%08x attr:0x%08x\n", + i, pentry->name, le32_to_cpu(pentry->offset), + le32_to_cpu(pentry->length), pentry->attr); diff --git a/ipq806x/patches-5.4/850-soc-add-qualcomm-syscon.patch b/ipq806x/patches-5.4/850-soc-add-qualcomm-syscon.patch new file mode 100644 index 0000000..9e1ac7d --- /dev/null +++ b/ipq806x/patches-5.4/850-soc-add-qualcomm-syscon.patch @@ -0,0 +1,121 @@ +From: Christian Lamparter +Subject: SoC: add qualcomm syscon +--- a/drivers/soc/qcom/Makefile ++++ b/drivers/soc/qcom/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o + obj-$(CONFIG_QCOM_SMSM) += smsm.o + obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o + obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o ++obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o + obj-$(CONFIG_QCOM_APR) += apr.o + obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o + obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o +--- a/drivers/soc/qcom/Kconfig ++++ b/drivers/soc/qcom/Kconfig +@@ -183,6 +183,13 @@ config QCOM_SOCINFO + Say yes here to support the Qualcomm socinfo driver, providing + information about the SoC to user space. + ++config QCOM_TCSR ++ tristate "QCOM Top Control and Status Registers" ++ depends on ARCH_QCOM ++ help ++ Say y here to enable TCSR support. The TCSR provides control ++ functions for various peripherals. ++ + config QCOM_WCNSS_CTRL + tristate "Qualcomm WCNSS control driver" + depends on ARCH_QCOM || COMPILE_TEST +--- /dev/null ++++ b/drivers/soc/qcom/qcom_tcsr.c +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (c) 2014, The Linux foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License rev 2 and ++ * only rev 2 as published by the free Software foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TCSR_USB_PORT_SEL 0xb0 ++ ++static int tcsr_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ const struct device_node *node = pdev->dev.of_node; ++ void __iomem *base; ++ u32 val; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) { ++ dev_err(&pdev->dev, "setting usb port select = %d\n", val); ++ writel(val, base + TCSR_USB_PORT_SEL); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id tcsr_dt_match[] = { ++ { .compatible = "qcom,tcsr", }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, tcsr_dt_match); ++ ++static struct platform_driver tcsr_driver = { ++ .driver = { ++ .name = "tcsr", ++ .owner = THIS_MODULE, ++ .of_match_table = tcsr_dt_match, ++ }, ++ .probe = tcsr_probe, ++}; ++ ++module_platform_driver(tcsr_driver); ++ ++MODULE_AUTHOR("Andy Gross "); ++MODULE_DESCRIPTION("QCOM TCSR driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/include/dt-bindings/soc/qcom,tcsr.h +@@ -0,0 +1,23 @@ ++/* Copyright (c) 2014, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#ifndef __DT_BINDINGS_QCOM_TCSR_H ++#define __DT_BINDINGS_QCOM_TCSR_H ++ ++#define TCSR_USB_SELECT_USB3_P0 0x1 ++#define TCSR_USB_SELECT_USB3_P1 0x2 ++#define TCSR_USB_SELECT_USB3_DUAL 0x3 ++ ++/* TCSR A/B REG */ ++#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL 0 ++#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL 1 ++ ++#endif diff --git a/ipq806x/patches-5.4/851-add-gsbi1-dts.patch b/ipq806x/patches-5.4/851-add-gsbi1-dts.patch new file mode 100644 index 0000000..a123189 --- /dev/null +++ b/ipq806x/patches-5.4/851-add-gsbi1-dts.patch @@ -0,0 +1,44 @@ +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -894,6 +894,41 @@ + reg = <0x12100000 0x10000>; + }; + ++ gsbi1: gsbi@12440000 { ++ compatible = "qcom,gsbi-v1.0.0"; ++ cell-index = <1>; ++ reg = <0x12440000 0x100>; ++ clocks = <&gcc GSBI1_H_CLK>; ++ clock-names = "iface"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ status = "disabled"; ++ ++ syscon-tcsr = <&tcsr>; ++ ++ gsbi1_serial: serial@12450000 { ++ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; ++ reg = <0x12450000 0x100>, ++ <0x12400000 0x03>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ status = "disabled"; ++ }; ++ ++ gsbi1_i2c: i2c@12460000 { ++ compatible = "qcom,i2c-qup-v1.1.1"; ++ reg = <0x12460000 0x1000>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ }; ++ + gsbi2: gsbi@12480000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <2>; diff --git a/ipq806x/patches-5.4/900-arm-add-cmdline-override.patch b/ipq806x/patches-5.4/900-arm-add-cmdline-override.patch new file mode 100644 index 0000000..17f20f0 --- /dev/null +++ b/ipq806x/patches-5.4/900-arm-add-cmdline-override.patch @@ -0,0 +1,37 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1841,6 +1841,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL + + endchoice + ++config CMDLINE_OVERRIDE ++ bool "Use alternative cmdline from device tree" ++ help ++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can ++ be used, this is not a good option for kernels that are shared across ++ devices. This setting enables using "chosen/cmdline-override" as the ++ cmdline if it exists in the device tree. ++ + config CMDLINE + string "Default kernel command string" + default "" +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1060,6 +1060,17 @@ int __init early_init_dt_scan_chosen(uns + if (p != NULL && l > 0) + strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); + ++ /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different ++ * device tree option of chosen/bootargs-override. This is ++ * helpful on boards where u-boot sets bootargs, and is unable ++ * to be modified. ++ */ ++#ifdef CONFIG_CMDLINE_OVERRIDE ++ p = of_get_flat_dt_prop(node, "bootargs-override", &l); ++ if (p != NULL && l > 0) ++ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++#endif ++ + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else + * managed to set the command line, unless CONFIG_CMDLINE_FORCE diff --git a/ipq806x/patches-5.4/997-device_tree_cmdline.patch b/ipq806x/patches-5.4/997-device_tree_cmdline.patch new file mode 100644 index 0000000..b6b1b04 --- /dev/null +++ b/ipq806x/patches-5.4/997-device_tree_cmdline.patch @@ -0,0 +1,12 @@ +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1059,6 +1059,9 @@ int __init early_init_dt_scan_chosen(uns + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + + /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different + * device tree option of chosen/bootargs-override. This is diff --git a/ipq806x/patches-5.4/999-HAVE_LD_DEAD_CODE_DATA_ELIMINATION.patch b/ipq806x/patches-5.4/999-HAVE_LD_DEAD_CODE_DATA_ELIMINATION.patch new file mode 100644 index 0000000..4832d65 --- /dev/null +++ b/ipq806x/patches-5.4/999-HAVE_LD_DEAD_CODE_DATA_ELIMINATION.patch @@ -0,0 +1,10 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -112,7 +112,6 @@ config ARM + select HAVE_UID16 + select HAVE_VIRT_CPU_ACCOUNTING_GEN + select IRQ_FORCED_THREADING +- select HAVE_LD_DEAD_CODE_DATA_ELIMINATION + select MODULES_USE_ELF_REL + select NEED_DMA_MAP_STATE + select OF_EARLY_FLATTREE if OF diff --git a/ipq806x/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch b/ipq806x/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch new file mode 100644 index 0000000..33eb34c --- /dev/null +++ b/ipq806x/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch @@ -0,0 +1,26 @@ +From d9c8bc8c1408f3e8529db6e4e04017b4c579c342 Mon Sep 17 00:00:00 2001 +From: Pawel Dembicki +Date: Sun, 18 Feb 2018 17:08:04 +0100 +Subject: [PATCH] w1: gpio: fix problem with platfom data in w1-gpio + +In devices, where fdt is used, is impossible to apply platform data +without proper fdt node. + +This patch allow to use platform data in devices with fdt. + +Signed-off-by: Pawel Dembicki +--- + drivers/w1/masters/w1-gpio.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/w1/masters/w1-gpio.c ++++ b/drivers/w1/masters/w1-gpio.c +@@ -76,7 +76,7 @@ static int w1_gpio_probe(struct platform + enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + int err; + +- if (of_have_populated_dt()) { ++ if (of_have_populated_dt() && !dev_get_platdata(&pdev->dev)) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; diff --git a/ipq806x/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch b/ipq806x/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch new file mode 100644 index 0000000..4531941 --- /dev/null +++ b/ipq806x/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch @@ -0,0 +1,57 @@ +From: Felix Fietkau +Date: Wed, 18 Apr 2018 10:50:05 +0200 +Subject: [PATCH] MIPS: only process negative stack offsets on stack traces + +Fixes endless back traces in cases where the compiler emits a stack +pointer increase in a branch delay slot (probably for some form of +function return). + +[ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low! +[ 3.480070] turning off the locking correctness validator. +[ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0 +[ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000 +[ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f +[ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000 +[ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000 +[ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000 +[ 3.532942] ... +[ 3.535362] Call Trace: +[ 3.537818] [<80010a48>] show_stack+0x58/0x100 +[ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170 +[ 3.546613] [<80079f90>] save_trace+0xf0/0x110 +[ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c +[ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08 +[ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c +[ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78 +[ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac + +Signed-off-by: Felix Fietkau +--- + +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -365,6 +365,8 @@ static inline int is_sp_move_ins(union m + + if (ip->i_format.opcode == addiu_op || + ip->i_format.opcode == daddiu_op) { ++ if (ip->i_format.simmediate > 0) ++ return 0; + *frame_size = -ip->i_format.simmediate; + return 1; + } diff --git a/ipq806x/pending-5.4/103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch b/ipq806x/pending-5.4/103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch new file mode 100644 index 0000000..4e7a532 --- /dev/null +++ b/ipq806x/pending-5.4/103-MIPS-select-CPU_MIPS64-for-remaining-MIPS64-CPUs.patch @@ -0,0 +1,37 @@ +From 31ca877744d95713e4925de542e1c686ab08a542 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sat, 27 Feb 2021 13:20:24 +0100 +Subject: [PATCH] MIPS: select CPU_MIPS64 for remaining MIPS64 CPUs + +The CPU_MIPS64 and CPU_MIPS32 variables are supposed to be able to +distinguish broadly between 64-bit and 32-bit MIPS CPUs. However, they +weren't selected by the specialty CPUs, Octeon and Loongson, which meant +it was possible to hit a weird state of: + + MIPS=y, CONFIG_64BIT=y, CPU_MIPS64=n + +This commit rectifies the issue by having CPU_MIPS64 be selected when +the missing Octeon or Loongson models are selected. + +Cc: Thomas Bogendoerfer +Cc: Ralf Baechle +Cc: George Cherian +Cc: Huacai Chen +Cc: Jiaxun Yang +Signed-off-by: Jason A. Donenfeld +--- + arch/mips/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -2037,7 +2037,8 @@ config CPU_MIPS32 + + config CPU_MIPS64 + bool +- default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6 ++ default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6 || \ ++ CPU_LOONGSON64 || CPU_CAVIUM_OCTEON + + # + # These indicate the revision of the architecture diff --git a/ipq806x/pending-5.4/110-ehci_hcd_ignore_oc.patch b/ipq806x/pending-5.4/110-ehci_hcd_ignore_oc.patch new file mode 100644 index 0000000..ce583ce --- /dev/null +++ b/ipq806x/pending-5.4/110-ehci_hcd_ignore_oc.patch @@ -0,0 +1,79 @@ +From: Florian Fainelli +Subject: USB: EHCI: add ignore_oc flag to disable overcurrent checking + +This patch adds an ignore_oc flag which can be set by EHCI controller +not supporting or wanting to disable overcurrent checking. The EHCI +platform data in include/linux/usb/ehci_pdriver.h is also augmented to +take advantage of this new flag. + +Signed-off-by: Florian Fainelli +--- + drivers/usb/host/ehci-hcd.c | 2 +- + drivers/usb/host/ehci-hub.c | 4 ++-- + drivers/usb/host/ehci-platform.c | 1 + + drivers/usb/host/ehci.h | 1 + + include/linux/usb/ehci_pdriver.h | 1 + + 5 files changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -651,7 +651,7 @@ static int ehci_run (struct usb_hcd *hcd + "USB %x.%x started, EHCI %x.%02x%s\n", + ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), + temp >> 8, temp & 0xff, +- ignore_oc ? ", overcurrent ignored" : ""); ++ (ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : ""); + + ehci_writel(ehci, INTR_MASK, + &ehci->regs->intr_enable); /* Turn On Interrupts */ +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -643,7 +643,7 @@ ehci_hub_status_data (struct usb_hcd *hc + * always set, seem to clear PORT_OCC and PORT_CSC when writing to + * PORT_POWER; that's surprising, but maybe within-spec. + */ +- if (!ignore_oc) ++ if (!ignore_oc && !ehci->ignore_oc) + mask = PORT_CSC | PORT_PEC | PORT_OCC; + else + mask = PORT_CSC | PORT_PEC; +@@ -1013,7 +1013,7 @@ int ehci_hub_control( + if (temp & PORT_PEC) + status |= USB_PORT_STAT_C_ENABLE << 16; + +- if ((temp & PORT_OCC) && !ignore_oc){ ++ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){ + status |= USB_PORT_STAT_C_OVERCURRENT << 16; + + /* +--- a/drivers/usb/host/ehci-platform.c ++++ b/drivers/usb/host/ehci-platform.c +@@ -319,6 +319,8 @@ static int ehci_platform_probe(struct pl + hcd->has_tt = 1; + if (pdata->reset_on_resume) + priv->reset_on_resume = true; ++ if (pdata->ignore_oc) ++ ehci->ignore_oc = 1; + + #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + if (ehci->big_endian_mmio) { +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -218,6 +218,7 @@ struct ehci_hcd { /* one per controlle + unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ + unsigned need_oc_pp_cycle:1; /* MPC834X port power */ + unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ ++ unsigned ignore_oc:1; + + /* required for usb32 quirk */ + #define OHCI_CTRL_HCFS (3 << 6) +--- a/include/linux/usb/ehci_pdriver.h ++++ b/include/linux/usb/ehci_pdriver.h +@@ -50,6 +50,7 @@ struct usb_ehci_pdata { + unsigned no_io_watchdog:1; + unsigned reset_on_resume:1; + unsigned dma_mask_64:1; ++ unsigned ignore_oc:1; + + /* Turn on all power and clocks */ + int (*power_on)(struct platform_device *pdev); diff --git a/ipq806x/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/ipq806x/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch new file mode 100644 index 0000000..6acb2dc --- /dev/null +++ b/ipq806x/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch @@ -0,0 +1,82 @@ +From: Tobias Wolf +Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation + +An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any +kernel beyond version 4.3 resulting in: + +BUG: Bad page state in process swapper pfn:086ac + +bisect resulted in: + +a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit +commit a1c34a3bf00af2cede839879502e12dc68491ad5 +Author: Laura Abbott +Date: Thu Nov 5 18:48:46 2015 -0800 + + mm: Don't offset memmap for flatmem + + Srinivas Kandagatla reported bad page messages when trying to remove the + bottom 2MB on an ARM based IFC6410 board + + BUG: Bad page state in process swapper pfn:fffa8 + page:ef7fb500 count:0 mapcount:0 mapping: (null) index:0x0 + flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked) + page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set + bad because of flags: + flags: 0x200041(locked|active|mlocked) + Modules linked in: + CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty +#816 + Hardware name: Qualcomm (Flattened Device Tree) + unwind_backtrace + show_stack + dump_stack + bad_page + free_pages_prepare + free_hot_cold_page + __free_pages + free_highmem_page + mem_init + start_kernel + Disabling lock debugging due to kernel taint + [...] +:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4 +0a8156f848733dfa21e16c196dfb6c0a76290709 M mm + +This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by +page_to_pfn anymore. + +The following output was generated with two hacked in printk statements: + +printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map - +(pgdat->node_start_pfn - ARCH_PFN_OFFSET)); + if (page_to_pfn(mem_map) != pgdat->node_start_pfn) + mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET); +printk("after %p\n", mem_map); + +Output: + +[ 0.000000] before 8861b280 vs. 8861b280 or 8851b280 +[ 0.000000] after 8851b280 + +As seen in the first line mem_map with subtraction of offset does not equal the +mem_map after subtraction of ARCH_PFN_OFFSET. + +After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the +previously calculated offset is zero for the named platform it is able to boot +4.4 and 4.9-rc7 again. + +Signed-off-by: Tobias Wolf +--- + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -6884,7 +6884,7 @@ static void __ref alloc_node_mem_map(str + mem_map = NODE_DATA(0)->node_mem_map; + #if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM) + if (page_to_pfn(mem_map) != pgdat->node_start_pfn) +- mem_map -= offset; ++ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET); + #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ + } + #endif diff --git a/ipq806x/pending-5.4/130-add-linux-spidev-compatible-si3210.patch b/ipq806x/pending-5.4/130-add-linux-spidev-compatible-si3210.patch new file mode 100644 index 0000000..eedb2bb --- /dev/null +++ b/ipq806x/pending-5.4/130-add-linux-spidev-compatible-si3210.patch @@ -0,0 +1,18 @@ +From: Giuseppe Lippolis +Subject: Add the linux,spidev compatible in spidev Several device in ramips have this binding in the dts + +Signed-off-by: Giuseppe Lippolis +--- + drivers/spi/spidev.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/spi/spidev.c ++++ b/drivers/spi/spidev.c +@@ -678,6 +678,7 @@ static const struct of_device_id spidev_ + { .compatible = "lwn,bk4" }, + { .compatible = "dh,dhcom-board" }, + { .compatible = "menlo,m53cpld" }, ++ { .compatible = "siliconlabs,si3210" }, + {}, + }; + MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/ipq806x/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/ipq806x/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch new file mode 100644 index 0000000..b9bb3f7 --- /dev/null +++ b/ipq806x/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch @@ -0,0 +1,62 @@ +From: Felix Fietkau +Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -756,6 +756,24 @@ static int jffs2_mknod (struct inode *di + return ret; + } + ++static int jffs2_whiteout (struct inode *old_dir, struct dentry *old_dentry) ++{ ++ struct dentry *wh; ++ int err; ++ ++ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name); ++ if (!wh) ++ return -ENOMEM; ++ ++ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV); ++ if (err) ++ return err; ++ ++ d_rehash(wh); ++ return 0; ++} ++ + static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, + struct inode *new_dir_i, struct dentry *new_dentry, + unsigned int flags) +@@ -766,7 +784,7 @@ static int jffs2_rename (struct inode *o + uint8_t type; + uint32_t now; + +- if (flags & ~RENAME_NOREPLACE) ++ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) + return -EINVAL; + + /* The VFS will check for us and prevent trying to rename a +@@ -832,9 +850,14 @@ static int jffs2_rename (struct inode *o + if (d_is_dir(old_dentry) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ + diff --git a/ipq806x/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch b/ipq806x/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch new file mode 100644 index 0000000..4b30bc7 --- /dev/null +++ b/ipq806x/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch @@ -0,0 +1,73 @@ +From: Felix Fietkau +Subject: jffs2: add RENAME_EXCHANGE support + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -781,18 +781,31 @@ static int jffs2_rename (struct inode *o + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); + struct jffs2_inode_info *victim_f = NULL; ++ struct inode *fst_inode = d_inode(old_dentry); ++ struct inode *snd_inode = d_inode(new_dentry); + uint8_t type; + uint32_t now; + +- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) ++ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE)) + return -EINVAL; + ++ if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) { ++ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { ++ inc_nlink(new_dir_i); ++ drop_nlink(old_dir_i); ++ } ++ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { ++ drop_nlink(new_dir_i); ++ inc_nlink(old_dir_i); ++ } ++ } ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem + * needs to do that for itself. + */ +- if (d_really_is_positive(new_dentry)) { ++ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) { + victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); + if (d_is_dir(new_dentry)) { + struct jffs2_full_dirent *fd; +@@ -827,7 +840,7 @@ static int jffs2_rename (struct inode *o + if (ret) + return ret; + +- if (victim_f) { ++ if (victim_f && !(flags & RENAME_EXCHANGE)) { + /* There was a victim. Kill it off nicely */ + if (d_is_dir(new_dentry)) + clear_nlink(d_inode(new_dentry)); +@@ -853,6 +866,12 @@ static int jffs2_rename (struct inode *o + if (flags & RENAME_WHITEOUT) + /* Replace with whiteout */ + ret = jffs2_whiteout(old_dir_i, old_dentry); ++ else if (flags & RENAME_EXCHANGE) ++ /* Replace the original */ ++ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i), ++ d_inode(new_dentry)->i_ino, type, ++ old_dentry->d_name.name, old_dentry->d_name.len, ++ now); + else + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +@@ -884,7 +903,7 @@ static int jffs2_rename (struct inode *o + return ret; + } + +- if (d_is_dir(old_dentry)) ++ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE)) + drop_nlink(old_dir_i); + + new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); diff --git a/ipq806x/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch b/ipq806x/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch new file mode 100644 index 0000000..c63268e --- /dev/null +++ b/ipq806x/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch @@ -0,0 +1,45 @@ +From: Stephen Hemminger +Subject: bridge: allow receiption on disabled port + +When an ethernet device is enslaved to a bridge, and the bridge STP +detects loss of carrier (or operational state down), then normally +packet receiption is blocked. + +This breaks control applications like WPA which maybe expecting to +receive packets to negotiate to bring link up. The bridge needs to +block forwarding packets from these disabled ports, but there is no +hard requirement to not allow local packet delivery. + +Signed-off-by: Stephen Hemminger +Signed-off-by: Felix Fietkau + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -190,6 +190,9 @@ static void __br_handle_local_finish(str + /* note: already called with rcu_read_lock */ + static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) + { ++ struct net_bridge_port *p = br_port_get_rcu(skb->dev); ++ ++ if (p->state != BR_STATE_DISABLED) + __br_handle_local_finish(skb); + + /* return 1 to signal the okfn() was called so it's ok to use the skb */ +@@ -340,6 +343,17 @@ rx_handler_result_t br_handle_frame(stru + + forward: + switch (p->state) { ++ case BR_STATE_DISABLED: ++ if (ether_addr_equal(p->br->dev->dev_addr, dest)) ++ skb->pkt_type = PACKET_HOST; ++ ++ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, ++ dev_net(skb->dev), NULL, skb, skb->dev, NULL, ++ br_handle_local_finish) == 1) { ++ return RX_HANDLER_PASS; ++ } ++ break; ++ + case BR_STATE_FORWARDING: + case BR_STATE_LEARNING: + if (ether_addr_equal(p->br->dev->dev_addr, dest)) diff --git a/ipq806x/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch b/ipq806x/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch new file mode 100644 index 0000000..9b88282 --- /dev/null +++ b/ipq806x/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch @@ -0,0 +1,63 @@ +From: Felix Fietkau +Subject: net: phy: at803x: add support for AT8032 + +Like AT8030, this PHY needs the GPIO reset workaround + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -64,8 +64,10 @@ + + #define ATH8030_PHY_ID 0x004dd076 + #define ATH8031_PHY_ID 0x004dd074 ++#define ATH8032_PHY_ID 0x004dd023 + #define ATH8035_PHY_ID 0x004dd072 + #define AT803X_PHY_ID_MASK 0xffffffef ++#define AT8032_PHY_ID_MASK 0xffffffff + + MODULE_DESCRIPTION("Atheros 803x PHY driver"); + MODULE_AUTHOR("Matus Ujhelyi"); +@@ -314,7 +316,7 @@ static int at803x_config_intr(struct phy + static void at803x_link_change_notify(struct phy_device *phydev) + { + /* +- * Conduct a hardware reset for AT8030 every time a link loss is ++ * Conduct a hardware reset for AT8030/2 every time a link loss is + * signalled. This is necessary to circumvent a hardware bug that + * occurs when the cable is unplugged while TX packets are pending + * in the FIFO. In such cases, the FIFO enters an error mode it +@@ -471,6 +473,24 @@ static struct phy_driver at803x_driver[] + .aneg_done = at803x_aneg_done, + .ack_interrupt = &at803x_ack_interrupt, + .config_intr = &at803x_config_intr, ++}, { ++ /* ATHEROS 8032 */ ++ .phy_id = ATH8032_PHY_ID, ++ .name = "Atheros 8032 ethernet", ++ .phy_id_mask = AT8032_PHY_ID_MASK, ++ .probe = at803x_probe, ++ .config_init = at803x_config_init, ++ .link_change_notify = at803x_link_change_notify, ++ .set_wol = at803x_set_wol, ++ .get_wol = at803x_get_wol, ++ .suspend = at803x_suspend, ++ .resume = at803x_resume, ++ /* PHY_BASIC_FEATURES */ ++ .read_status = at803x_read_status, ++ .config_aneg = genphy_config_aneg, ++ .read_status = genphy_read_status, ++ .ack_interrupt = at803x_ack_interrupt, ++ .config_intr = at803x_config_intr, + } }; + + module_phy_driver(at803x_driver); +@@ -478,6 +498,7 @@ module_phy_driver(at803x_driver); + static struct mdio_device_id __maybe_unused atheros_tbl[] = { + { ATH8030_PHY_ID, AT803X_PHY_ID_MASK }, + { ATH8031_PHY_ID, AT803X_PHY_ID_MASK }, ++ { ATH8032_PHY_ID, AT8032_PHY_ID_MASK }, + { ATH8035_PHY_ID, AT803X_PHY_ID_MASK }, + { } + }; diff --git a/ipq806x/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch b/ipq806x/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch new file mode 100644 index 0000000..13b79b5 --- /dev/null +++ b/ipq806x/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch @@ -0,0 +1,94 @@ +From: Daniel González Cabanelas +Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week + +The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week +alarms. + +Read the "wday" alarm register and convert it to a date to support up 1 +week in our driver. + +Signed-off-by: Daniel González Cabanelas +--- + drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++----- + 1 file changed, 42 insertions(+), 6 deletions(-) + +--- a/drivers/rtc/rtc-rs5c372.c ++++ b/drivers/rtc/rtc-rs5c372.c +@@ -393,7 +393,9 @@ static int rs5c_read_alarm(struct device + { + struct i2c_client *client = to_i2c_client(dev); + struct rs5c372 *rs5c = i2c_get_clientdata(client); +- int status; ++ int status, wday_offs; ++ struct rtc_time rtc; ++ unsigned long alarm_secs; + + status = rs5c_get_regs(rs5c); + if (status < 0) +@@ -403,6 +405,30 @@ static int rs5c_read_alarm(struct device + t->time.tm_sec = 0; + t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); + t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); ++ t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1; ++ ++ /* determine the day, month and year based on alarm wday, taking as a ++ * reference the current time from the rtc ++ */ ++ status = rs5c372_rtc_read_time(dev, &rtc); ++ if (status < 0) ++ return status; ++ ++ wday_offs = t->time.tm_wday - rtc.tm_wday; ++ alarm_secs = mktime64(rtc.tm_year + 1900, ++ rtc.tm_mon + 1, ++ rtc.tm_mday + wday_offs, ++ t->time.tm_hour, ++ t->time.tm_min, ++ t->time.tm_sec); ++ ++ if (wday_offs < 0 || (wday_offs == 0 && ++ (t->time.tm_hour < rtc.tm_hour || ++ (t->time.tm_hour == rtc.tm_hour && ++ t->time.tm_min <= rtc.tm_min)))) ++ alarm_secs += 7 * 86400; ++ ++ rtc_time64_to_tm(alarm_secs, &t->time); + + /* ... and status */ + t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); +@@ -417,12 +443,20 @@ static int rs5c_set_alarm(struct device + struct rs5c372 *rs5c = i2c_get_clientdata(client); + int status, addr, i; + unsigned char buf[3]; ++ struct rtc_time rtc_tm; ++ unsigned long rtc_secs, alarm_secs; + +- /* only handle up to 24 hours in the future, like RTC_ALM_SET */ +- if (t->time.tm_mday != -1 +- || t->time.tm_mon != -1 +- || t->time.tm_year != -1) ++ /* chip only can handle alarms up to one week in the future*/ ++ status = rs5c372_rtc_read_time(dev, &rtc_tm); ++ if (status) ++ return status; ++ rtc_secs = rtc_tm_to_time64(&rtc_tm); ++ alarm_secs = rtc_tm_to_time64(&t->time); ++ if (alarm_secs >= rtc_secs + 7 * 86400) { ++ dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n", ++ __func__, status); + return -EINVAL; ++ } + + /* REVISIT: round up tm_sec */ + +@@ -443,7 +477,9 @@ static int rs5c_set_alarm(struct device + /* set alarm */ + buf[0] = bin2bcd(t->time.tm_min); + buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour); +- buf[2] = 0x7f; /* any/all days */ ++ /* each bit is the day of the week, 0x7f means all days */ ++ buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ? ++ BIT(t->time.tm_wday) : 0x7f; + + for (i = 0; i < sizeof(buf); i++) { + addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); diff --git a/ipq806x/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch b/ipq806x/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch new file mode 100644 index 0000000..7e9d0e6 --- /dev/null +++ b/ipq806x/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch @@ -0,0 +1,70 @@ +From: Daniel González Cabanelas +Subject: [PATCH 2/2] rtc: rs5c372: let the alarm to be used as wakeup source + +Currently there is no use for the interrupts on the rs5c372 RTC and the +wakealarm isn't enabled. There are some devices like NASes which use this +RTC to wake up from the power off state when the INTR pin is activated by +the alarm clock. + +Enable the alarm and let to be used as a wakeup source. + +Tested on a Buffalo LS421DE NAS. + +Signed-off-by: Daniel González Cabanelas +--- + drivers/rtc/rtc-rs5c372.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/rtc/rtc-rs5c372.c ++++ b/drivers/rtc/rtc-rs5c372.c +@@ -654,6 +654,7 @@ static int rs5c372_probe(struct i2c_clie + int err = 0; + int smbus_mode = 0; + struct rs5c372 *rs5c372; ++ bool rs5c372_can_wakeup_device = false; + + dev_dbg(&client->dev, "%s\n", __func__); + +@@ -689,6 +690,12 @@ static int rs5c372_probe(struct i2c_clie + else + rs5c372->type = id->driver_data; + ++#ifdef CONFIG_OF ++ if(of_property_read_bool(client->dev.of_node, ++ "wakeup-source")) ++ rs5c372_can_wakeup_device = true; ++#endif ++ + /* we read registers 0x0f then 0x00-0x0f; skip the first one */ + rs5c372->regs = &rs5c372->buf[1]; + rs5c372->smbus = smbus_mode; +@@ -722,6 +729,8 @@ static int rs5c372_probe(struct i2c_clie + goto exit; + } + ++ rs5c372->has_irq = 1; ++ + /* if the oscillator lost power and no other software (like + * the bootloader) set it up, do it here. + * +@@ -748,6 +757,10 @@ static int rs5c372_probe(struct i2c_clie + ); + + /* REVISIT use client->irq to register alarm irq ... */ ++ if (rs5c372_can_wakeup_device) { ++ device_init_wakeup(&client->dev, true); ++ } ++ + rs5c372->rtc = devm_rtc_device_register(&client->dev, + rs5c372_driver.driver.name, + &rs5c372_rtc_ops, THIS_MODULE); +@@ -761,6 +774,9 @@ static int rs5c372_probe(struct i2c_clie + if (err) + goto exit; + ++ /* the rs5c372 alarm only supports a minute accuracy */ ++ rs5c372->rtc->uie_unsupported = 1; ++ + return 0; + + exit: diff --git a/ipq806x/pending-5.4/201-extra_optimization.patch b/ipq806x/pending-5.4/201-extra_optimization.patch new file mode 100644 index 0000000..c606487 --- /dev/null +++ b/ipq806x/pending-5.4/201-extra_optimization.patch @@ -0,0 +1,31 @@ +From: Felix Fietkau +Subject: Upgrade to Linux 2.6.19 + +- Includes large parts of the patch from #1021 by dpalffy +- Includes RB532 NAND driver changes by n0-1 + +[john@phrozen.org: feix will add this to his upstream queue] + +lede-commit: bff468813f78f81e36ebb2a3f4354de7365e640f +Signed-off-by: Felix Fietkau +--- + Makefile | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -719,11 +719,11 @@ KBUILD_CFLAGS += $(call cc-disable-warni + KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) + + ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE +-KBUILD_CFLAGS += -O2 ++KBUILD_CFLAGS += -O2 $(EXTRA_OPTIMIZATION) + else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3 +-KBUILD_CFLAGS += -O3 ++KBUILD_CFLAGS += -O3 $(EXTRA_OPTIMIZATION) + else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE +-KBUILD_CFLAGS += -Os ++KBUILD_CFLAGS += -Os -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION) + endif + + # Tell gcc to never replace conditional load with a non-conditional one diff --git a/ipq806x/pending-5.4/203-kallsyms_uncompressed.patch b/ipq806x/pending-5.4/203-kallsyms_uncompressed.patch new file mode 100644 index 0000000..68a2d4d --- /dev/null +++ b/ipq806x/pending-5.4/203-kallsyms_uncompressed.patch @@ -0,0 +1,119 @@ +From: Felix Fietkau +Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx + +[john@phrozen.org: added to my upstream queue 30.12.2016] +lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed +Signed-off-by: Felix Fietkau +--- + init/Kconfig | 11 +++++++++++ + kernel/kallsyms.c | 8 ++++++++ + scripts/kallsyms.c | 12 ++++++++++++ + scripts/link-vmlinux.sh | 4 ++++ + 4 files changed, 35 insertions(+) + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1280,6 +1280,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW + the unaligned access emulation. + see arch/parisc/kernel/unaligned.c for reference + ++config KALLSYMS_UNCOMPRESSED ++ bool "Keep kallsyms uncompressed" ++ depends on KALLSYMS ++ help ++ Normally kallsyms contains compressed symbols (using a token table), ++ reducing the uncompressed kernel image size. Keeping the symbol table ++ uncompressed significantly improves the size of this part in compressed ++ kernel images. ++ ++ Say N unless you need compressed kernel images to be small. ++ + config HAVE_PCSPKR_PLATFORM + bool + +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -75,6 +75,11 @@ static unsigned int kallsyms_expand_symb + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ memcpy(result, data + 1, len - 1); ++ result += len - 1; ++ len = 0; ++#endif + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; + data++; +@@ -107,6 +112,9 @@ tail: + */ + static char kallsyms_get_symbol_type(unsigned int off) + { ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ return kallsyms_names[off + 1]; ++#endif + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -59,6 +59,7 @@ static struct addr_range percpu_range = + static struct sym_entry *table; + static unsigned int table_size, table_cnt; + static int all_symbols = 0; ++static int uncompressed = 0; + static int absolute_percpu = 0; + static int base_relative = 0; + +@@ -440,6 +441,9 @@ static void write_src(void) + + free(markers); + ++ if (uncompressed) ++ return; ++ + output_label("kallsyms_token_table"); + off = 0; + for (i = 0; i < 256; i++) { +@@ -500,6 +504,9 @@ static void *find_token(unsigned char *s + { + int i; + ++ if (uncompressed) ++ return NULL; ++ + for (i = 0; i < len - 1; i++) { + if (str[i] == token[0] && str[i+1] == token[1]) + return &str[i]; +@@ -572,6 +579,9 @@ static void optimize_result(void) + { + int i, best; + ++ if (uncompressed) ++ return; ++ + /* using the '\0' symbol last allows compress_symbols to use standard + * fast string functions */ + for (i = 255; i >= 0; i--) { +@@ -751,6 +761,8 @@ int main(int argc, char **argv) + absolute_percpu = 1; + else if (strcmp(argv[i], "--base-relative") == 0) + base_relative = 1; ++ else if (strcmp(argv[i], "--uncompressed") == 0) ++ uncompressed = 1; + else + usage(); + } +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -160,6 +160,10 @@ kallsyms() + kallsymopt="${kallsymopt} --base-relative" + fi + ++ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then ++ kallsymopt="${kallsymopt} --uncompressed" ++ fi ++ + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + diff --git a/ipq806x/pending-5.4/205-backtrace_module_info.patch b/ipq806x/pending-5.4/205-backtrace_module_info.patch new file mode 100644 index 0000000..6048c25 --- /dev/null +++ b/ipq806x/pending-5.4/205-backtrace_module_info.patch @@ -0,0 +1,41 @@ +From: Felix Fietkau +Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries + +[john@phrozen.org: felix will add this to his upstream queue] + +lede-commit 53827cdc824556cda910b23ce5030c363b8f1461 +Signed-off-by: Felix Fietkau +--- + lib/vsprintf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -940,8 +940,10 @@ char *symbol_string(char *buf, char *end + struct printf_spec spec, const char *fmt) + { + unsigned long value; +-#ifdef CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; ++#ifndef CONFIG_KALLSYMS ++ struct module *mod; ++ int len; + #endif + + if (fmt[1] == 'R') +@@ -958,8 +960,14 @@ char *symbol_string(char *buf, char *end + + return string_nocheck(buf, end, sym, spec); + #else +- return special_hex_number(buf, end, value, sizeof(void *)); ++ len = snprintf(sym, sizeof(sym), "0x%lx", value); ++ mod = __module_address(value); ++ if (mod) ++ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]", ++ mod->name, mod->core_layout.base, ++ mod->core_layout.size); + #endif ++ return string(buf, end, sym, spec); + } + + static const struct printf_spec default_str_spec = { diff --git a/ipq806x/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch b/ipq806x/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch new file mode 100644 index 0000000..7d890d3 --- /dev/null +++ b/ipq806x/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch @@ -0,0 +1,47 @@ +From: Gabor Juhos +Subject: usr: sanitize deps_initramfs list + +If any filename in the intramfs dependency +list contains a colon, that causes a kernel +build error like this: + +/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop. +make[5]: *** [usr] Error 2 + +Fix it by removing such filenames from the +deps_initramfs list. + +Signed-off-by: Gabor Juhos +--- + usr/Makefile | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -42,21 +42,23 @@ ifneq ($(wildcard $(obj)/$(datafile_d_y) + include $(obj)/$(datafile_d_y) + endif + ++deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v))) ++ + quiet_cmd_initfs = GEN $@ + cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) + + targets := $(datafile_y) + + # do not try to update files included in initramfs +-$(deps_initramfs): ; ++$(deps_initramfs_sane): ; + +-$(deps_initramfs): klibcdirs ++$(deps_initramfs_sane): klibcdirs + # We rebuild initramfs_data.cpio if: + # 1) Any included file is newer than initramfs_data.cpio + # 2) There are changes in which files are included (added or deleted) + # 3) If gen_init_cpio are newer than initramfs_data.cpio + # 4) Arguments to gen_initramfs.sh changes +-$(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs ++$(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs + $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/$(datafile_d_y) + $(call if_changed,initfs) + diff --git a/ipq806x/pending-5.4/261-enable_wilink_platform_without_drivers.patch b/ipq806x/pending-5.4/261-enable_wilink_platform_without_drivers.patch new file mode 100644 index 0000000..c4cf2cc --- /dev/null +++ b/ipq806x/pending-5.4/261-enable_wilink_platform_without_drivers.patch @@ -0,0 +1,20 @@ +From: Imre Kaloz +Subject: [PATCH] hack: net: wireless: make the wl12xx glue code available with + compat-wireless, too + +Signed-off-by: Imre Kaloz +--- + drivers/net/wireless/ti/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ti/Kconfig ++++ b/drivers/net/wireless/ti/Kconfig +@@ -20,7 +20,7 @@ source "drivers/net/wireless/ti/wlcore/K + + config WILINK_PLATFORM_DATA + bool "TI WiLink platform data" +- depends on WLCORE_SDIO || WL1251_SDIO ++ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS + default y + ---help--- + Small platform data bit needed to pass data to the sdio modules. diff --git a/ipq806x/pending-5.4/270-platform-mikrotik-build-bits.patch b/ipq806x/pending-5.4/270-platform-mikrotik-build-bits.patch new file mode 100644 index 0000000..df738ef --- /dev/null +++ b/ipq806x/pending-5.4/270-platform-mikrotik-build-bits.patch @@ -0,0 +1,31 @@ +From c2deb5ef01a0ef09088832744cbace9e239a6ee0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= +Date: Sat, 28 Mar 2020 12:11:50 +0100 +Subject: [PATCH] generic: platform/mikrotik build bits (5.4) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds platform/mikrotik kernel build bits + +Signed-off-by: Thibaut VARÈNE +--- + drivers/platform/Kconfig | 2 ++ + drivers/platform/Makefile | 1 + + 2 files changed, 3 insertions(+) + +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -13,3 +13,5 @@ source "drivers/platform/chrome/Kconfig" + source "drivers/platform/mellanox/Kconfig" + + source "drivers/platform/olpc/Kconfig" ++ ++source "drivers/platform/mikrotik/Kconfig" +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -9,3 +9,4 @@ obj-$(CONFIG_MIPS) += mips/ + obj-$(CONFIG_OLPC_EC) += olpc/ + obj-$(CONFIG_GOLDFISH) += goldfish/ + obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ ++obj-$(CONFIG_MIKROTIK) += mikrotik/ diff --git a/ipq806x/pending-5.4/300-mips_expose_boot_raw.patch b/ipq806x/pending-5.4/300-mips_expose_boot_raw.patch new file mode 100644 index 0000000..7b9ae65 --- /dev/null +++ b/ipq806x/pending-5.4/300-mips_expose_boot_raw.patch @@ -0,0 +1,40 @@ +From: Mark Miller +Subject: mips: expose CONFIG_BOOT_RAW + +This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on +certain Broadcom chipsets running CFE in order to load the kernel. + +Signed-off-by: Mark Miller +Acked-by: Rob Landley +--- +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1069,9 +1069,6 @@ config FW_ARC + config ARCH_MAY_HAVE_PC_FDC + bool + +-config BOOT_RAW +- bool +- + config CEVT_BCM1480 + bool + +@@ -3044,6 +3041,18 @@ choice + bool "Extend builtin kernel arguments with bootloader arguments" + endchoice + ++config BOOT_RAW ++ bool "Enable the kernel to be executed from the load address" ++ default n ++ help ++ Allow the kernel to be executed from the load address for ++ bootloaders which cannot read the ELF format. This places ++ a jump to start_kernel at the load address. ++ ++ If unsure, say N. ++ ++ ++ + endmenu + + config LOCKDEP_SUPPORT diff --git a/ipq806x/pending-5.4/302-mips_no_branch_likely.patch b/ipq806x/pending-5.4/302-mips_no_branch_likely.patch new file mode 100644 index 0000000..bf1b489 --- /dev/null +++ b/ipq806x/pending-5.4/302-mips_no_branch_likely.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: mips: use -mno-branch-likely for kernel and userspace + +saves ~11k kernel size after lzma and ~12k squashfs size in the + +lede-commit: 41a039f46450ffae9483d6216422098669da2900 +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -92,7 +92,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # machines may also. Since BFD is incredibly buggy with respect to + # crossformat linking we rely on the elf2ecoff tool for format conversion. + # +-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe ++cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib + KBUILD_AFLAGS_MODULE += -mlong-calls diff --git a/ipq806x/pending-5.4/305-mips_module_reloc.patch b/ipq806x/pending-5.4/305-mips_module_reloc.patch new file mode 100644 index 0000000..40a219f --- /dev/null +++ b/ipq806x/pending-5.4/305-mips_module_reloc.patch @@ -0,0 +1,371 @@ +From: Felix Fietkau +Subject: mips: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to + +lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 5 + + arch/mips/include/asm/module.h | 5 + + arch/mips/kernel/module.c | 279 ++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 284 insertions(+), 5 deletions(-) + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -95,8 +95,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib ++ifdef CONFIG_64BIT + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls ++else ++ ifdef CONFIG_DYNAMIC_FTRACE ++ KBUILD_AFLAGS_MODULE += -mlong-calls ++ KBUILD_CFLAGS_MODULE += -mlong-calls ++ else ++ KBUILD_AFLAGS_MODULE += -mno-long-calls ++ KBUILD_CFLAGS_MODULE += -mno-long-calls ++ endif ++endif + + ifeq ($(CONFIG_RELOCATABLE),y) + LDFLAGS_vmlinux += --emit-relocs +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -12,6 +12,11 @@ struct mod_arch_specific { + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; + struct mips_hi16 *r_mips_hi16_list; ++ ++ void *phys_plt_tbl; ++ void *virt_plt_tbl; ++ unsigned int phys_plt_offset; ++ unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -32,14 +32,221 @@ struct mips_hi16 { + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + +-#ifdef MODULE_START ++/* ++ * Get the potential max trampolines size required of the init and ++ * non-init sections. Only used if we cannot find enough contiguous ++ * physically mapped memory to put the module into. ++ */ ++static unsigned int ++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, ++ const char *secstrings, unsigned int symindex, bool is_init) ++{ ++ unsigned long ret = 0; ++ unsigned int i, j; ++ Elf_Sym *syms; ++ ++ /* Everything marked ALLOC (this includes the exported symbols) */ ++ for (i = 1; i < hdr->e_shnum; ++i) { ++ unsigned int info = sechdrs[i].sh_info; ++ ++ if (sechdrs[i].sh_type != SHT_REL ++ && sechdrs[i].sh_type != SHT_RELA) ++ continue; ++ ++ /* Not a valid relocation section? */ ++ if (info >= hdr->e_shnum) ++ continue; ++ ++ /* Don't bother with non-allocated sections */ ++ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) ++ continue; ++ ++ /* If it's called *.init*, and we're not init, we're ++ not interested */ ++ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) ++ != is_init) ++ continue; ++ ++ syms = (Elf_Sym *) sechdrs[symindex].sh_addr; ++ if (sechdrs[i].sh_type == SHT_REL) { ++ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rel); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rel[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } else { ++ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rela); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rela[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#ifndef MODULE_START ++static void *alloc_phys(unsigned long size) ++{ ++ unsigned order; ++ struct page *page; ++ struct page *p; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_THISNODE, order); ++ if (!page) ++ return NULL; ++ ++ split_page(page, order); ++ ++ /* mark all pages except for the last one */ ++ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p) ++ set_bit(PG_owner_priv_1, &p->flags); ++ ++ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) ++ __free_page(p); ++ ++ return page_address(page); ++} ++#endif ++ ++static void free_phys(void *ptr) ++{ ++ struct page *page; ++ bool free; ++ ++ page = virt_to_page(ptr); ++ do { ++ free = test_and_clear_bit(PG_owner_priv_1, &page->flags); ++ __free_page(page); ++ page++; ++ } while (free); ++} ++ ++ + void *module_alloc(unsigned long size) + { ++#ifdef MODULE_START + return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, + GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, + __builtin_return_address(0)); ++#else ++ void *ptr; ++ ++ if (size == 0) ++ return NULL; ++ ++ ptr = alloc_phys(size); ++ ++ /* If we failed to allocate physically contiguous memory, ++ * fall back to regular vmalloc. The module loader code will ++ * create jump tables to handle long jumps */ ++ if (!ptr) ++ return vmalloc(size); ++ ++ return ptr; ++#endif + } ++ ++static inline bool is_phys_addr(void *ptr) ++{ ++#ifdef CONFIG_64BIT ++ return (KSEGX((unsigned long)ptr) == CKSEG0); ++#else ++ return (KSEGX(ptr) == KSEG0); + #endif ++} ++ ++/* Free memory returned from module_alloc */ ++void module_memfree(void *module_region) ++{ ++ if (is_phys_addr(module_region)) ++ free_phys(module_region); ++ else ++ vfree(module_region); ++} ++ ++static void *__module_alloc(int size, bool phys) ++{ ++ void *ptr; ++ ++ if (phys) ++ ptr = kmalloc(size, GFP_KERNEL); ++ else ++ ptr = vmalloc(size); ++ return ptr; ++} ++ ++static void __module_free(void *ptr) ++{ ++ if (is_phys_addr(ptr)) ++ kfree(ptr); ++ else ++ vfree(ptr); ++} ++ ++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ++ char *secstrings, struct module *mod) ++{ ++ unsigned int symindex = 0; ++ unsigned int core_size, init_size; ++ int i; ++ ++ mod->arch.phys_plt_offset = 0; ++ mod->arch.virt_plt_offset = 0; ++ mod->arch.phys_plt_tbl = NULL; ++ mod->arch.virt_plt_tbl = NULL; ++ ++ if (IS_ENABLED(CONFIG_64BIT)) ++ return 0; ++ ++ for (i = 1; i < hdr->e_shnum; i++) ++ if (sechdrs[i].sh_type == SHT_SYMTAB) ++ symindex = i; ++ ++ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); ++ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); ++ ++ if ((core_size + init_size) == 0) ++ return 0; ++ ++ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); ++ if (!mod->arch.phys_plt_tbl) ++ return -ENOMEM; ++ ++ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); ++ if (!mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ return -ENOMEM; ++ } ++ ++ return 0; ++} + + static int apply_r_mips_none(struct module *me, u32 *location, + u32 base, Elf_Addr v, bool rela) +@@ -55,9 +262,40 @@ static int apply_r_mips_32(struct module + return 0; + } + ++static Elf_Addr add_plt_entry_to(unsigned *plt_offset, ++ void *start, Elf_Addr v) ++{ ++ unsigned *tramp = start + *plt_offset; ++ *plt_offset += 4 * sizeof(int); ++ ++ /* adjust carry for addiu */ ++ if (v & 0x00008000) ++ v += 0x10000; ++ ++ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ ++ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ ++ tramp[2] = 0x03200008; /* jr t9 */ ++ tramp[3] = 0x00000000; /* nop */ ++ ++ return (Elf_Addr) tramp; ++} ++ ++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) ++{ ++ if (is_phys_addr(location)) ++ return add_plt_entry_to(&me->arch.phys_plt_offset, ++ me->arch.phys_plt_tbl, v); ++ else ++ return add_plt_entry_to(&me->arch.virt_plt_offset, ++ me->arch.virt_plt_tbl, v); ++ ++} ++ + static int apply_r_mips_26(struct module *me, u32 *location, + u32 base, Elf_Addr v, bool rela) + { ++ u32 ofs = base & 0x03ffffff; ++ + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 relocation\n", + me->name); +@@ -65,13 +303,17 @@ static int apply_r_mips_26(struct module + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- pr_err("module %s: relocation overflow\n", +- me->name); +- return -ENOEXEC; ++ v = add_plt_entry(me, location, v + (ofs << 2)); ++ if (!v) { ++ pr_err("module %s: relocation overflow\n", ++ me->name); ++ return -ENOEXEC; ++ } ++ ofs = 0; + } + + *location = (*location & ~0x03ffffff) | +- ((base + (v >> 2)) & 0x03ffffff); ++ ((ofs + (v >> 2)) & 0x03ffffff); + + return 0; + } +@@ -447,9 +689,36 @@ int module_finalize(const Elf_Ehdr *hdr, + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } ++ ++ /* Get rid of the fixup trampoline if we're running the module ++ * from physically mapped address space */ ++ if (me->arch.phys_plt_offset == 0) { ++ __module_free(me->arch.phys_plt_tbl); ++ me->arch.phys_plt_tbl = NULL; ++ } ++ if (me->arch.virt_plt_offset == 0) { ++ __module_free(me->arch.virt_plt_tbl); ++ me->arch.virt_plt_tbl = NULL; ++ } ++ + return 0; + } + ++void module_arch_freeing_init(struct module *mod) ++{ ++ if (mod->state == MODULE_STATE_LIVE) ++ return; ++ ++ if (mod->arch.phys_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ } ++ if (mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.virt_plt_tbl); ++ mod->arch.virt_plt_tbl = NULL; ++ } ++} ++ + void module_arch_cleanup(struct module *mod) + { + spin_lock_irq(&dbe_lock); diff --git a/ipq806x/pending-5.4/307-mips_highmem_offset.patch b/ipq806x/pending-5.4/307-mips_highmem_offset.patch new file mode 100644 index 0000000..9dd2fa9 --- /dev/null +++ b/ipq806x/pending-5.4/307-mips_highmem_offset.patch @@ -0,0 +1,19 @@ +From: Felix Fietkau +Subject: kernel: adjust mips highmem offset to avoid the need for -mlong-calls on systems with >256M RAM + +Signed-off-by: Felix Fietkau +--- + arch/mips/include/asm/mach-generic/spaces.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/mips/include/asm/mach-generic/spaces.h ++++ b/arch/mips/include/asm/mach-generic/spaces.h +@@ -50,7 +50,7 @@ + * Memory above this physical address will be considered highmem. + */ + #ifndef HIGHMEM_START +-#define HIGHMEM_START _AC(0x20000000, UL) ++#define HIGHMEM_START _AC(0x10000000, UL) + #endif + + #endif /* CONFIG_32BIT */ diff --git a/ipq806x/pending-5.4/308-mips32r2_tune.patch b/ipq806x/pending-5.4/308-mips32r2_tune.patch new file mode 100644 index 0000000..8636511 --- /dev/null +++ b/ipq806x/pending-5.4/308-mips32r2_tune.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2 + +This provides a good tradeoff across at least 24Kc-74Kc, while also +producing smaller code. + +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -177,7 +177,7 @@ cflags-$(CONFIG_CPU_VR41XX) += -march=r4 + cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap + cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap + cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap +-cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap ++cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -mtune=34kc -Wa,--trap + cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg + cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap + cflags-$(CONFIG_CPU_MIPS64_R2) += -march=mips64r2 -Wa,--trap diff --git a/ipq806x/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch b/ipq806x/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch new file mode 100644 index 0000000..e4075a2 --- /dev/null +++ b/ipq806x/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch @@ -0,0 +1,142 @@ +From 87ec87c2ad615c1a177cd08ef5fa29fc739f6e50 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Sun, 23 Dec 2018 18:06:53 +0100 +Subject: [PATCH] MIPS: Add CPU option reporting to /proc/cpuinfo + +Many MIPS CPUs have optional CPU features which are not activates for +all CPU cores. Print the CPU options which are implemented in the core +in /proc/cpuinfo. This makes it possible to see what features are +supported and which are not supported. This should cover all standard +MIPS extensions, before it only printed information about the main MIPS +ASEs. + +Signed-off-by: Hauke Mehrtens +--- + arch/mips/kernel/proc.c | 116 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 116 insertions(+) + +--- a/arch/mips/kernel/proc.c ++++ b/arch/mips/kernel/proc.c +@@ -134,6 +134,122 @@ static int show_cpuinfo(struct seq_file + seq_printf(m, "micromips kernel\t: %s\n", + (read_c0_config3() & MIPS_CONF3_ISA_OE) ? "yes" : "no"); + } ++ ++ seq_printf(m, "Options implemented\t:"); ++ if (cpu_has_tlb) ++ seq_printf(m, "%s", " tlb"); ++ if (cpu_has_ftlb) ++ seq_printf(m, "%s", " ftlb"); ++ if (cpu_has_tlbinv) ++ seq_printf(m, "%s", " tlbinv"); ++ if (cpu_has_segments) ++ seq_printf(m, "%s", " segments"); ++ if (cpu_has_rixiex) ++ seq_printf(m, "%s", " rixiex"); ++ if (cpu_has_ldpte) ++ seq_printf(m, "%s", " ldpte"); ++ if (cpu_has_maar) ++ seq_printf(m, "%s", " maar"); ++ if (cpu_has_rw_llb) ++ seq_printf(m, "%s", " rw_llb"); ++ if (cpu_has_4kex) ++ seq_printf(m, "%s", " 4kex"); ++ if (cpu_has_3k_cache) ++ seq_printf(m, "%s", " 3k_cache"); ++ if (cpu_has_4k_cache) ++ seq_printf(m, "%s", " 4k_cache"); ++ if (cpu_has_6k_cache) ++ seq_printf(m, "%s", " 6k_cache"); ++ if (cpu_has_8k_cache) ++ seq_printf(m, "%s", " 8k_cache"); ++ if (cpu_has_tx39_cache) ++ seq_printf(m, "%s", " tx39_cache"); ++ if (cpu_has_octeon_cache) ++ seq_printf(m, "%s", " octeon_cache"); ++ if (cpu_has_fpu) ++ seq_printf(m, "%s", " fpu"); ++ if (cpu_has_32fpr) ++ seq_printf(m, "%s", " 32fpr"); ++ if (cpu_has_cache_cdex_p) ++ seq_printf(m, "%s", " cache_cdex_p"); ++ if (cpu_has_cache_cdex_s) ++ seq_printf(m, "%s", " cache_cdex_s"); ++ if (cpu_has_prefetch) ++ seq_printf(m, "%s", " prefetch"); ++ if (cpu_has_mcheck) ++ seq_printf(m, "%s", " mcheck"); ++ if (cpu_has_ejtag) ++ seq_printf(m, "%s", " ejtag"); ++ if (cpu_has_llsc) ++ seq_printf(m, "%s", " llsc"); ++ if (cpu_has_bp_ghist) ++ seq_printf(m, "%s", " bp_ghist"); ++ if (cpu_has_guestctl0ext) ++ seq_printf(m, "%s", " guestctl0ext"); ++ if (cpu_has_guestctl1) ++ seq_printf(m, "%s", " guestctl1"); ++ if (cpu_has_guestctl2) ++ seq_printf(m, "%s", " guestctl2"); ++ if (cpu_has_guestid) ++ seq_printf(m, "%s", " guestid"); ++ if (cpu_has_drg) ++ seq_printf(m, "%s", " drg"); ++ if (cpu_has_rixi) ++ seq_printf(m, "%s", " rixi"); ++ if (cpu_has_lpa) ++ seq_printf(m, "%s", " lpa"); ++ if (cpu_has_mvh) ++ seq_printf(m, "%s", " mvh"); ++ if (cpu_has_vtag_icache) ++ seq_printf(m, "%s", " vtag_icache"); ++ if (cpu_has_dc_aliases) ++ seq_printf(m, "%s", " dc_aliases"); ++ if (cpu_has_ic_fills_f_dc) ++ seq_printf(m, "%s", " ic_fills_f_dc"); ++ if (cpu_has_pindexed_dcache) ++ seq_printf(m, "%s", " pindexed_dcache"); ++ if (cpu_has_userlocal) ++ seq_printf(m, "%s", " userlocal"); ++ if (cpu_has_nofpuex) ++ seq_printf(m, "%s", " nofpuex"); ++ if (cpu_has_vint) ++ seq_printf(m, "%s", " vint"); ++ if (cpu_has_veic) ++ seq_printf(m, "%s", " veic"); ++ if (cpu_has_inclusive_pcaches) ++ seq_printf(m, "%s", " inclusive_pcaches"); ++ if (cpu_has_perf_cntr_intr_bit) ++ seq_printf(m, "%s", " perf_cntr_intr_bit"); ++ if (cpu_has_ufr) ++ seq_printf(m, "%s", " ufr"); ++ if (cpu_has_fre) ++ seq_printf(m, "%s", " fre"); ++ if (cpu_has_cdmm) ++ seq_printf(m, "%s", " cdmm"); ++ if (cpu_has_small_pages) ++ seq_printf(m, "%s", " small_pages"); ++ if (cpu_has_nan_legacy) ++ seq_printf(m, "%s", " nan_legacy"); ++ if (cpu_has_nan_2008) ++ seq_printf(m, "%s", " nan_2008"); ++ if (cpu_has_ebase_wg) ++ seq_printf(m, "%s", " ebase_wg"); ++ if (cpu_has_badinstr) ++ seq_printf(m, "%s", " badinstr"); ++ if (cpu_has_badinstrp) ++ seq_printf(m, "%s", " badinstrp"); ++ if (cpu_has_contextconfig) ++ seq_printf(m, "%s", " contextconfig"); ++ if (cpu_has_perf) ++ seq_printf(m, "%s", " perf"); ++ if (cpu_has_shared_ftlb_ram) ++ seq_printf(m, "%s", " shared_ftlb_ram"); ++ if (cpu_has_shared_ftlb_entries) ++ seq_printf(m, "%s", " shared_ftlb_entries"); ++ if (cpu_has_mipsmt_pertccounters) ++ seq_printf(m, "%s", " mipsmt_pertccounters"); ++ seq_printf(m, "\n"); ++ + seq_printf(m, "shadow register sets\t: %d\n", + cpu_data[n].srsets); + seq_printf(m, "kscratch registers\t: %d\n", diff --git a/ipq806x/pending-5.4/310-arm_module_unresolved_weak_sym.patch b/ipq806x/pending-5.4/310-arm_module_unresolved_weak_sym.patch new file mode 100644 index 0000000..24807f7 --- /dev/null +++ b/ipq806x/pending-5.4/310-arm_module_unresolved_weak_sym.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: fix errors in unresolved weak symbols on arm + +lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f +Signed-off-by: Felix Fietkau +--- + arch/arm/kernel/module.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/kernel/module.c ++++ b/arch/arm/kernel/module.c +@@ -99,6 +99,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons + return -ENOEXEC; + } + ++ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) && ++ ELF_ST_BIND(sym->st_info) == STB_WEAK) ++ continue; ++ + loc = dstsec->sh_addr + rel->r_offset; + + switch (ELF32_R_TYPE(rel->r_info)) { diff --git a/ipq806x/pending-5.4/311-MIPS-zboot-put-appended-dtb-into-a-section.patch b/ipq806x/pending-5.4/311-MIPS-zboot-put-appended-dtb-into-a-section.patch new file mode 100644 index 0000000..3f8808f --- /dev/null +++ b/ipq806x/pending-5.4/311-MIPS-zboot-put-appended-dtb-into-a-section.patch @@ -0,0 +1,36 @@ +From 7d1531c81c0fb4c93bea8dc316043ad0e4d0c270 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Sun, 25 Oct 2020 23:19:40 +0800 +Subject: [PATCH] MIPS: zboot: put appended dtb into a section + +This will make a separated section for dtb appear in ELF, and we can +then use objcopy to patch a dtb into vmlinuz when RAW_APPENDED_DTB +is set in kernel config. + +command to patch a dtb: +objcopy --set-section-flags=.appended_dtb=alloc,contents \ + --update-section=.appended_dtb=.dtb vmlinuz vmlinuz-dtb + +Signed-off-by: Chuanhong Guo +--- + arch/mips/boot/compressed/ld.script | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/arch/mips/boot/compressed/ld.script ++++ b/arch/mips/boot/compressed/ld.script +@@ -31,9 +31,12 @@ SECTIONS + CONSTRUCTORS + . = ALIGN(16); + } +- __appended_dtb = .; +- /* leave space for appended DTB */ +- . += 0x100000; ++ ++ .appended_dtb : { ++ __appended_dtb = .; ++ /* leave space for appended DTB */ ++ . += 0x100000; ++ } + + _edata = .; + /* End of data section */ diff --git a/ipq806x/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/ipq806x/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch new file mode 100644 index 0000000..2808c95 --- /dev/null +++ b/ipq806x/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch @@ -0,0 +1,281 @@ +From: Yousong Zhou +Subject: MIPS: kexec: Accept command line parameters from userspace. + +Signed-off-by: Yousong Zhou +--- + arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++----- + arch/mips/kernel/machine_kexec.h | 20 +++++ + arch/mips/kernel/relocate_kernel.S | 21 +++-- + 3 files changed, 167 insertions(+), 27 deletions(-) + create mode 100644 arch/mips/kernel/machine_kexec.h + +--- a/arch/mips/kernel/machine_kexec.c ++++ b/arch/mips/kernel/machine_kexec.c +@@ -9,14 +9,11 @@ + #include + #include + ++#include + #include + #include +- +-extern const unsigned char relocate_new_kernel[]; +-extern const size_t relocate_new_kernel_size; +- +-extern unsigned long kexec_start_address; +-extern unsigned long kexec_indirection_page; ++#include ++#include "machine_kexec.h" + + static unsigned long reboot_code_buffer; + +@@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL + void (*_machine_kexec_shutdown)(void) = NULL; + void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; + ++static void machine_kexec_print_args(void) ++{ ++ unsigned long argc = (int)kexec_args[0]; ++ int i; ++ ++ pr_info("kexec_args[0] (argc): %lu\n", argc); ++ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); ++ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); ++ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); ++ ++ for (i = 0; i < argc; i++) { ++ pr_info("kexec_argv[%d] = %p, %s\n", ++ i, kexec_argv[i], kexec_argv[i]); ++ } ++} ++ ++static void machine_kexec_init_argv(struct kimage *image) ++{ ++ void __user *buf = NULL; ++ size_t bufsz; ++ size_t size; ++ int i; ++ ++ bufsz = 0; ++ for (i = 0; i < image->nr_segments; i++) { ++ struct kexec_segment *seg; ++ ++ seg = &image->segment[i]; ++ if (seg->bufsz < 6) ++ continue; ++ ++ if (strncmp((char *) seg->buf, "kexec ", 6)) ++ continue; ++ ++ buf = seg->buf; ++ bufsz = seg->bufsz; ++ break; ++ } ++ ++ if (!buf) ++ return; ++ ++ size = KEXEC_COMMAND_LINE_SIZE; ++ size = min(size, bufsz); ++ if (size < bufsz) ++ pr_warn("kexec command line truncated to %zd bytes\n", size); ++ ++ /* Copy to kernel space */ ++ if (copy_from_user(kexec_argv_buf, buf, size)) ++ pr_warn("kexec command line copy to kernel space failed\n"); ++ ++ kexec_argv_buf[size - 1] = 0; ++} ++ ++static void machine_kexec_parse_argv(struct kimage *image) ++{ ++ char *reboot_code_buffer; ++ int reloc_delta; ++ char *ptr; ++ int argc; ++ int i; ++ ++ ptr = kexec_argv_buf; ++ argc = 0; ++ ++ /* ++ * convert command line string to array of parameters ++ * (as bootloader does). ++ */ ++ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) { ++ if (*ptr == ' ') { ++ *ptr++ = '\0'; ++ continue; ++ } ++ ++ kexec_argv[argc++] = ptr; ++ ptr = strchr(ptr, ' '); ++ } ++ ++ if (!argc) ++ return; ++ ++ kexec_args[0] = argc; ++ kexec_args[1] = (unsigned long)kexec_argv; ++ kexec_args[2] = 0; ++ kexec_args[3] = 0; ++ ++ reboot_code_buffer = page_address(image->control_code_page); ++ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel; ++ ++ kexec_args[1] += reloc_delta; ++ for (i = 0; i < argc; i++) ++ kexec_argv[i] += reloc_delta; ++} ++ + static void kexec_image_info(const struct kimage *kimage) + { + unsigned long i; +@@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim + #endif + + kexec_image_info(kimage); ++ /* ++ * Whenever arguments passed from kexec-tools, Init the arguments as ++ * the original ones to try avoiding booting failure. ++ */ ++ ++ kexec_args[0] = fw_arg0; ++ kexec_args[1] = fw_arg1; ++ kexec_args[2] = fw_arg2; ++ kexec_args[3] = fw_arg3; ++ ++ machine_kexec_init_argv(kimage); ++ machine_kexec_parse_argv(kimage); + + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); +@@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r + void kexec_nonboot_cpu_jump(void) + { + local_flush_icache_range((unsigned long)relocated_kexec_smp_wait, +- reboot_code_buffer + relocate_new_kernel_size); ++ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); + + relocated_kexec_smp_wait(NULL); + } +@@ -199,7 +303,7 @@ void kexec_reboot(void) + * machine_kexec() CPU. + */ + local_flush_icache_range(reboot_code_buffer, +- reboot_code_buffer + relocate_new_kernel_size); ++ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); + + do_kexec = (void *)reboot_code_buffer; + do_kexec(); +@@ -212,10 +316,12 @@ machine_kexec(struct kimage *image) + unsigned long *ptr; + + reboot_code_buffer = +- (unsigned long)page_address(image->control_code_page); ++ (unsigned long)page_address(image->control_code_page); ++ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); + + kexec_start_address = + (unsigned long) phys_to_virt(image->start); ++ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address); + + if (image->type == KEXEC_TYPE_DEFAULT) { + kexec_indirection_page = +@@ -223,9 +329,19 @@ machine_kexec(struct kimage *image) + } else { + kexec_indirection_page = (unsigned long)&image->head; + } ++ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page); + +- memcpy((void*)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); ++ pr_info("Where is memcpy: %p\n", memcpy); ++ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n", ++ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end); ++ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE, ++ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer); ++ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel, ++ KEXEC_RELOCATE_NEW_KERNEL_SIZE); ++ ++ pr_info("Before _print_args().\n"); ++ machine_kexec_print_args(); ++ pr_info("Before eval loop.\n"); + + /* + * The generic kexec code builds a page list with physical +@@ -256,7 +372,7 @@ machine_kexec(struct kimage *image) + #ifdef CONFIG_SMP + /* All secondary cpus now may jump to kexec_wait cycle */ + relocated_kexec_smp_wait = reboot_code_buffer + +- (void *)(kexec_smp_wait - relocate_new_kernel); ++ (void *)(kexec_smp_wait - kexec_relocate_new_kernel); + smp_wmb(); + atomic_set(&kexec_ready_to_reboot, 1); + #endif +--- /dev/null ++++ b/arch/mips/kernel/machine_kexec.h +@@ -0,0 +1,20 @@ ++#ifndef _MACHINE_KEXEC_H ++#define _MACHINE_KEXEC_H ++ ++#ifndef __ASSEMBLY__ ++extern const unsigned char kexec_relocate_new_kernel[]; ++extern unsigned long kexec_relocate_new_kernel_end; ++extern unsigned long kexec_start_address; ++extern unsigned long kexec_indirection_page; ++ ++extern char kexec_argv_buf[]; ++extern char *kexec_argv[]; ++ ++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel) ++#endif /* !__ASSEMBLY__ */ ++ ++#define KEXEC_COMMAND_LINE_SIZE 256 ++#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16) ++#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long)) ++ ++#endif +--- a/arch/mips/kernel/relocate_kernel.S ++++ b/arch/mips/kernel/relocate_kernel.S +@@ -10,8 +10,9 @@ + #include + #include + #include ++#include "machine_kexec.h" + +-LEAF(relocate_new_kernel) ++LEAF(kexec_relocate_new_kernel) + PTR_L a0, arg0 + PTR_L a1, arg1 + PTR_L a2, arg2 +@@ -96,7 +97,7 @@ done: + #endif + /* jump to kexec_start_address */ + j s1 +- END(relocate_new_kernel) ++ END(kexec_relocate_new_kernel) + + #ifdef CONFIG_SMP + /* +@@ -182,9 +183,15 @@ kexec_indirection_page: + PTR 0 + .size kexec_indirection_page, PTRSIZE + +-relocate_new_kernel_end: ++kexec_argv_buf: ++ EXPORT(kexec_argv_buf) ++ .skip KEXEC_COMMAND_LINE_SIZE ++ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE ++ ++kexec_argv: ++ EXPORT(kexec_argv) ++ .skip KEXEC_ARGV_SIZE ++ .size kexec_argv, KEXEC_ARGV_SIZE + +-relocate_new_kernel_size: +- EXPORT(relocate_new_kernel_size) +- PTR relocate_new_kernel_end - relocate_new_kernel +- .size relocate_new_kernel_size, PTRSIZE ++kexec_relocate_new_kernel_end: ++ EXPORT(kexec_relocate_new_kernel_end) diff --git a/ipq806x/pending-5.4/332-arc-add-OWRTDTB-section.patch b/ipq806x/pending-5.4/332-arc-add-OWRTDTB-section.patch new file mode 100644 index 0000000..4b0534e --- /dev/null +++ b/ipq806x/pending-5.4/332-arc-add-OWRTDTB-section.patch @@ -0,0 +1,84 @@ +From bb0c3b0175240bf152fd7c644821a0cf9f77c37c Mon Sep 17 00:00:00 2001 +From: Evgeniy Didin +Date: Fri, 15 Mar 2019 18:53:38 +0300 +Subject: [PATCH] arc add OWRTDTB section + +This change allows OpenWRT to patch resulting kernel binary with +external .dtb. + +That allows us to re-use exactky the same vmlinux on different boards +given its ARC core configurations match (at least cache line sizes etc). + +""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external +.dtb right after it, keeping the string in place. + +Signed-off-by: Eugeniy Paltsev +Signed-off-by: Alexey Brodkin +Signed-off-by: Evgeniy Didin +--- + arch/arc/kernel/head.S | 10 ++++++++++ + arch/arc/kernel/setup.c | 4 +++- + arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++ + 3 files changed, 26 insertions(+), 1 deletion(-) + +--- a/arch/arc/kernel/head.S ++++ b/arch/arc/kernel/head.S +@@ -61,6 +61,16 @@ + #endif + .endm + ++ ; Here "patch-dtb" will embed external .dtb ++ ; Note "patch-dtb" searches for ASCII "OWRTDTB:" string ++ ; and pastes .dtb right after it, hense the string precedes ++ ; __image_dtb symbol. ++ .section .owrt, "aw",@progbits ++ .ascii "OWRTDTB:" ++ENTRY(__image_dtb) ++ .fill 0x4000 ++END(__image_dtb) ++ + .section .init.text, "ax",@progbits + + ;---------------------------------------------------------------- +--- a/arch/arc/kernel/setup.c ++++ b/arch/arc/kernel/setup.c +@@ -492,6 +492,8 @@ static inline bool uboot_arg_invalid(uns + /* We always pass 0 as magic from U-boot */ + #define UBOOT_MAGIC_VALUE 0 + ++extern struct boot_param_header __image_dtb; ++ + void __init handle_uboot_args(void) + { + bool use_embedded_dtb = true; +@@ -530,7 +532,7 @@ void __init handle_uboot_args(void) + ignore_uboot_args: + + if (use_embedded_dtb) { +- machine_desc = setup_machine_fdt(__dtb_start); ++ machine_desc = setup_machine_fdt(&__image_dtb); + if (!machine_desc) + panic("Embedded DT invalid\n"); + } +--- a/arch/arc/kernel/vmlinux.lds.S ++++ b/arch/arc/kernel/vmlinux.lds.S +@@ -27,6 +27,19 @@ SECTIONS + + . = CONFIG_LINUX_LINK_BASE; + ++ /* ++ * In OpenWRT we want to patch built binary embedding .dtb of choice. ++ * This is implemented with "patch-dtb" utility which searches for ++ * "OWRTDTB:" string in first 16k of image and if it is found ++ * copies .dtb right after mentioned string. ++ * ++ * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it. ++ */ ++ .owrt : { ++ *(.owrt) ++ . = ALIGN(PAGE_SIZE); ++ } ++ + _int_vec_base_lds = .; + .vector : { + *(.vector) diff --git a/ipq806x/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch b/ipq806x/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch new file mode 100644 index 0000000..1848a84 --- /dev/null +++ b/ipq806x/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch @@ -0,0 +1,24 @@ +From: Alexey Brodkin +Subject: arc: enable unaligned access in kernel mode + +This enables misaligned access handling even in kernel mode. +Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses +here and there and to cope with that without fixing stuff in the drivers +we're just gracefully handling it on ARC. + +Signed-off-by: Alexey Brodkin +--- + arch/arc/kernel/unaligned.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arc/kernel/unaligned.c ++++ b/arch/arc/kernel/unaligned.c +@@ -202,7 +202,7 @@ int misaligned_fixup(unsigned long addre + char buf[TASK_COMM_LEN]; + + /* handle user mode only and only if enabled by sysadmin */ +- if (!user_mode(regs) || !unaligned_enabled) ++ if (!unaligned_enabled) + return 1; + + if (no_unaligned_warning) { diff --git a/ipq806x/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch b/ipq806x/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch new file mode 100644 index 0000000..8d4c742 --- /dev/null +++ b/ipq806x/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch @@ -0,0 +1,25 @@ +From 66770a004afe10df11d3902e16eaa0c2c39436bb Mon Sep 17 00:00:00 2001 +From: Pawel Dembicki +Date: Fri, 24 May 2019 17:56:19 +0200 +Subject: [PATCH] powerpc: Enable kernel XZ compression option on PPC_85xx + +Enable kernel XZ compression option on PPC_85xx. Tested with +simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor). + +Suggested-by: Christian Lamparter +Signed-off-by: Pawel Dembicki +--- + arch/powerpc/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -205,7 +205,7 @@ config PPC + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE + select HAVE_KERNEL_LZO if DEFAULT_UIMAGE +- select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x ++ select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x || PPC_85xx + select HAVE_KPROBES + select HAVE_KPROBES_ON_FTRACE + select HAVE_KRETPROBES diff --git a/ipq806x/pending-5.4/400-mtd-add-rootfs-split-support.patch b/ipq806x/pending-5.4/400-mtd-add-rootfs-split-support.patch new file mode 100644 index 0000000..83a4ed3 --- /dev/null +++ b/ipq806x/pending-5.4/400-mtd-add-rootfs-split-support.patch @@ -0,0 +1,107 @@ +From: Felix Fietkau +Subject: make rootfs split/detection more generic - patch can be moved to generic-2.6 after testing on other platforms + +lede-commit: 328e660b31f0937d52c5ae3d6e7029409918a9df +Signed-off-by: Felix Fietkau +--- + drivers/mtd/Kconfig | 17 +++++++++++++++++ + drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++++++++++++ + include/linux/mtd/partitions.h | 2 ++ + 3 files changed, 54 insertions(+) + +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -12,6 +12,23 @@ menuconfig MTD + + if MTD + ++menu "OpenWrt specific MTD options" ++ ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ default y ++ ++config MTD_SPLIT_FIRMWARE ++ bool "Automatically split firmware partition for kernel+rootfs" ++ default y ++ ++config MTD_SPLIT_FIRMWARE_NAME ++ string "Firmware partition name" ++ depends on MTD_SPLIT_FIRMWARE ++ default "firmware" ++ ++endmenu ++ + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -15,10 +15,12 @@ + #include + #include + #include ++#include + #include + #include + + #include "mtdcore.h" ++#include "mtdsplit/mtdsplit.h" + + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); +@@ -38,6 +40,8 @@ struct mtd_part { + struct list_head list; + }; + ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part); ++ + /* + * Given a pointer to the MTD object in the mtd_part structure, we can retrieve + * the pointer to that structure. +@@ -612,6 +616,7 @@ int mtd_add_partition(struct mtd_info *p + if (ret) + goto err_remove_part; + ++ mtd_partition_split(parent, new); + mtd_add_partition_attrs(new); + + return 0; +@@ -698,6 +703,29 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#else ++#define SPLIT_FIRMWARE_NAME "unused" ++#endif ++ ++static void split_firmware(struct mtd_info *master, struct mtd_part *part) ++{ ++} ++ ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part) ++{ ++ static int rootfs_found = 0; ++ ++ if (rootfs_found) ++ return; ++ ++ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) && ++ !strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && ++ !of_find_property(mtd_get_of_node(&part->mtd), "compatible", NULL)) ++ split_firmware(master, part); ++} ++ + /* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to +@@ -738,6 +766,7 @@ int add_mtd_partitions(struct mtd_info * + goto err_del_partitions; + } + ++ mtd_partition_split(master, slave); + mtd_add_partition_attrs(slave); + /* Look for subpartitions */ + parse_mtd_partitions(&slave->mtd, parts[i].types, NULL); diff --git a/ipq806x/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch b/ipq806x/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch new file mode 100644 index 0000000..f471c62 --- /dev/null +++ b/ipq806x/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch @@ -0,0 +1,142 @@ +From: Gabor Juhos +Subject: mtd: add support for different partition parser types + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/mtdpart.c | 56 ++++++++++++++++++++++++++++++++++++++++ + include/linux/mtd/partitions.h | 11 ++++++++ + 2 files changed, 67 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -41,6 +41,10 @@ struct mtd_part { + }; + + static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part); ++static int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data); + + /* + * Given a pointer to the MTD object in the mtd_part structure, we can retrieve +@@ -703,6 +707,36 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++static int ++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type) ++{ ++ struct mtd_partition *parts; ++ int nr_parts; ++ int i; ++ ++ nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, (const struct mtd_partition **)&parts, ++ NULL); ++ if (nr_parts <= 0) ++ return nr_parts; ++ ++ if (WARN_ON(!parts)) ++ return 0; ++ ++ for (i = 0; i < nr_parts; i++) { ++ /* adjust partition offsets */ ++ parts[i].offset += slave->offset; ++ ++ mtd_add_partition(slave->parent, ++ parts[i].name, ++ parts[i].offset, ++ parts[i].size); ++ } ++ ++ kfree(parts); ++ ++ return nr_parts; ++} ++ + #ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME + #define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME + #else +@@ -1052,6 +1086,61 @@ void mtd_part_parser_cleanup(struct mtd_ + } + } + ++static struct mtd_part_parser * ++get_partition_parser_by_type(enum mtd_parser_type type, ++ struct mtd_part_parser *start) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ p = list_prepare_entry(start, &part_parsers, list); ++ if (start) ++ mtd_part_parser_put(start); ++ ++ list_for_each_entry_continue(p, &part_parsers, list) { ++ if (p->type == type && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ ++static int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_part_parser *prev = NULL; ++ int ret = 0; ++ ++ while (1) { ++ struct mtd_part_parser *parser; ++ ++ parser = get_partition_parser_by_type(type, prev); ++ if (!parser) ++ break; ++ ++ ret = (*parser->parse_fn)(master, pparts, data); ++ ++ if (ret > 0) { ++ mtd_part_parser_put(parser); ++ printk(KERN_NOTICE ++ "%d %s partitions found on MTD device %s\n", ++ ret, parser->name, master->name); ++ break; ++ } ++ ++ prev = parser; ++ } ++ ++ return ret; ++} ++ + int mtd_is_partition(const struct mtd_info *mtd) + { + struct mtd_part *part; +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -73,6 +73,10 @@ struct mtd_part_parser_data { + * Functions dealing with the various ways of partitioning the space + */ + ++enum mtd_parser_type { ++ MTD_PARSER_TYPE_DEVICE = 0, ++}; ++ + struct mtd_part_parser { + struct list_head list; + struct module *owner; +@@ -81,6 +85,7 @@ struct mtd_part_parser { + int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, + struct mtd_part_parser_data *); + void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); ++ enum mtd_parser_type type; + }; + + /* Container for passing around a set of parsed partitions */ diff --git a/ipq806x/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch b/ipq806x/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch new file mode 100644 index 0000000..afe3ec7 --- /dev/null +++ b/ipq806x/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch @@ -0,0 +1,44 @@ +From: Gabor Juhos +Subject: kernel/3.10: allow to use partition parsers for rootfs and firmware split + +lede-commit: 3b71cd94bc9517bc25267dccb393b07d4b54564e +Signed-off-by: Gabor Juhos +--- + drivers/mtd/mtdpart.c | 37 +++++++++++++++++++++++++++++++++++++ + include/linux/mtd/partitions.h | 2 ++ + 2 files changed, 39 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -745,6 +745,7 @@ run_parsers_by_type(struct mtd_part *sla + + static void split_firmware(struct mtd_info *master, struct mtd_part *part) + { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); + } + + static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part) +@@ -754,6 +755,12 @@ static void mtd_partition_split(struct m + if (rootfs_found) + return; + ++ if (!strcmp(part->mtd.name, "rootfs")) { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ rootfs_found = 1; ++ } ++ + if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) && + !strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && + !of_find_property(mtd_get_of_node(&part->mtd), "compatible", NULL)) +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -75,6 +75,8 @@ struct mtd_part_parser_data { + + enum mtd_parser_type { + MTD_PARSER_TYPE_DEVICE = 0, ++ MTD_PARSER_TYPE_ROOTFS, ++ MTD_PARSER_TYPE_FIRMWARE, + }; + + struct mtd_part_parser { diff --git a/ipq806x/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch b/ipq806x/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch new file mode 100644 index 0000000..5d868ff --- /dev/null +++ b/ipq806x/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch @@ -0,0 +1,32 @@ +From: Gabor Juhos +Subject: [PATCH] kernel/3.10: move squashfs check from rootfs split code into a separate file + +lede-commit: d89bea92b31b4e157a0fa438e75370f089f73427 +Signed-off-by: Gabor Juhos +--- + drivers/mtd/Kconfig | 2 ++ + drivers/mtd/Makefile | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME + depends on MTD_SPLIT_FIRMWARE + default "firmware" + ++source "drivers/mtd/mtdsplit/Kconfig" ++ + endmenu + + config MTD_TESTS +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc + + obj-y += parsers/ + ++obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ ++ + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o + obj-$(CONFIG_MTD_BLOCK) += mtdblock.o diff --git a/ipq806x/pending-5.4/404-mtd-add-more-helper-functions.patch b/ipq806x/pending-5.4/404-mtd-add-more-helper-functions.patch new file mode 100644 index 0000000..059a440 --- /dev/null +++ b/ipq806x/pending-5.4/404-mtd-add-more-helper-functions.patch @@ -0,0 +1,76 @@ +From: Gabor Juhos +Subject: kernel/3.10: add separate rootfs partition parser + +lede-commit: daec7ad7688415156e2730e401503d09bd3acf91 +Signed-off-by: Gabor Juhos +--- + drivers/mtd/mtdpart.c | 29 +++++++++++++++++++++++++++++ + include/linux/mtd/mtd.h | 18 ++++++++++++++++++ + include/linux/mtd/partitions.h | 2 ++ + 3 files changed, 49 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -1165,6 +1165,24 @@ int mtd_is_partition(const struct mtd_in + } + EXPORT_SYMBOL_GPL(mtd_is_partition); + ++struct mtd_info *mtd_get_master(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return (struct mtd_info *)mtd; ++ ++ return mtd_to_part(mtd)->parent; ++} ++EXPORT_SYMBOL_GPL(mtd_get_master); ++ ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return 0; ++ ++ return mtd_to_part(mtd)->offset; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_offset); ++ + /* Returns the size of the entire flash chip */ + uint64_t mtd_get_device_size(const struct mtd_info *mtd) + { +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -504,6 +504,24 @@ static inline void mtd_align_erase_req(s + req->len += mtd->erasesize - mod; + } + ++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round up to next erase block */ ++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; ++} ++ ++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round down to the start of the current erase block */ ++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; ++} ++ + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) + { + if (mtd->writesize_shift) +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -116,6 +116,8 @@ int mtd_is_partition(const struct mtd_in + int mtd_add_partition(struct mtd_info *master, const char *name, + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); ++struct mtd_info *mtd_get_master(const struct mtd_info *mtd); ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd); + uint64_t mtd_get_device_size(const struct mtd_info *mtd); + + #endif diff --git a/ipq806x/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch b/ipq806x/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch new file mode 100644 index 0000000..d0fc1d5 --- /dev/null +++ b/ipq806x/pending-5.4/410-mtd-parsers-ofpart-fix-parsing-subpartitions.patch @@ -0,0 +1,76 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 6 May 2021 12:33:58 +0200 +Subject: [PATCH] mtd: parsers: ofpart: fix parsing subpartitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ofpart was recently patched to not scan random partition nodes as +subpartitions. That change unfortunately broke scanning valid +subpartitions like: + +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + compatible = "fixed-partitions"; + label = "bootloader"; + reg = <0x0 0x100000>; + + partition@0 { + label = "config"; + reg = <0x80000 0x80000>; + }; + }; +}; + +Fix that regression by adding 1 more code path. We actually need 3 +conditional blocks to support 3 possible cases. This change also makes +code easier to understand & follow. + +Reported-by: David Bauer +Fixes: 2d751203aacf ("mtd: parsers: ofpart: limit parsing of deprecated DT syntax +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/parsers/ofpart_core.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +--- a/drivers/mtd/parsers/ofpart_core.c ++++ b/drivers/mtd/parsers/ofpart_core.c +@@ -57,20 +57,22 @@ static int parse_fixed_partitions(struct + if (!mtd_node) + return 0; + +- ofpart_node = of_get_child_by_name(mtd_node, "partitions"); +- if (!ofpart_node && !mtd_is_partition(master)) { +- /* +- * We might get here even when ofpart isn't used at all (e.g., +- * when using another parser), so don't be louder than +- * KERN_DEBUG +- */ +- pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", +- master->name, mtd_node); ++ if (!mtd_is_partition(master)) { /* Master */ ++ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); ++ if (!ofpart_node) { ++ /* ++ * We might get here even when ofpart isn't used at all (e.g., ++ * when using another parser), so don't be louder than ++ * KERN_DEBUG ++ */ ++ pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", ++ master->name, mtd_node); ++ ofpart_node = mtd_node; ++ dedicated = false; ++ } ++ } else { /* Partition */ + ofpart_node = mtd_node; +- dedicated = false; + } +- if (!ofpart_node) +- return 0; + + of_id = of_match_node(parse_ofpart_match_table, ofpart_node); + if (dedicated && !of_id) { diff --git a/ipq806x/pending-5.4/411-mtd-partial_eraseblock_write.patch b/ipq806x/pending-5.4/411-mtd-partial_eraseblock_write.patch new file mode 100644 index 0000000..c48a144 --- /dev/null +++ b/ipq806x/pending-5.4/411-mtd-partial_eraseblock_write.patch @@ -0,0 +1,130 @@ +From: Felix Fietkau +Subject: mtd: implement write support for partitions covering only a part of an eraseblock (buffer data that would otherwise be erased) + +lede-commit: 87a8e8ac1067f58ba831c4aae443f3655c31cd80 +Signed-off-by: Felix Fietkau +--- + drivers/mtd/mtdpart.c | 90 ++++++++++++++++++++++++++++++++++++++++++++----- + include/linux/mtd/mtd.h | 4 +++ + 2 files changed, 85 insertions(+), 9 deletions(-) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -22,6 +22,8 @@ + #include "mtdcore.h" + #include "mtdsplit/mtdsplit.h" + ++#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */ ++ + /* Our partition linked list */ + static LIST_HEAD(mtd_partitions); + static DEFINE_MUTEX(mtd_partitions_mutex); +@@ -206,11 +208,77 @@ static int part_erase(struct mtd_info *m + { + struct mtd_part *part = mtd_to_part(mtd); + int ret; ++ size_t wrlen = 0; ++ u8 *erase_buf = NULL; ++ u32 erase_buf_ofs = 0; ++ bool partial_start = false; ++ ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ size_t readlen = 0; ++ u64 mtd_ofs; ++ ++ erase_buf = kmalloc(part->parent->erasesize, GFP_ATOMIC); ++ if (!erase_buf) ++ return -ENOMEM; ++ ++ mtd_ofs = part->offset + instr->addr; ++ erase_buf_ofs = do_div(mtd_ofs, part->parent->erasesize); ++ ++ if (erase_buf_ofs > 0) { ++ instr->addr -= erase_buf_ofs; ++ ret = mtd_read(part->parent, ++ instr->addr + part->offset, ++ part->parent->erasesize, ++ &readlen, erase_buf); ++ ++ instr->len += erase_buf_ofs; ++ partial_start = true; ++ } else { ++ mtd_ofs = part->offset + part->mtd.size; ++ erase_buf_ofs = part->parent->erasesize - ++ do_div(mtd_ofs, part->parent->erasesize); ++ ++ if (erase_buf_ofs > 0) { ++ instr->len += erase_buf_ofs; ++ ret = mtd_read(part->parent, ++ part->offset + instr->addr + ++ instr->len - part->parent->erasesize, ++ part->parent->erasesize, &readlen, ++ erase_buf); ++ } else { ++ ret = 0; ++ } ++ } ++ if (ret < 0) { ++ kfree(erase_buf); ++ return ret; ++ } ++ ++ } + + instr->addr += part->offset; + ret = part->parent->_erase(part->parent, instr); + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; ++ ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ if (partial_start) { ++ part->parent->_write(part->parent, ++ instr->addr, erase_buf_ofs, ++ &wrlen, erase_buf); ++ instr->addr += erase_buf_ofs; ++ } else { ++ instr->len -= erase_buf_ofs; ++ part->parent->_write(part->parent, ++ instr->addr + instr->len, ++ erase_buf_ofs, &wrlen, ++ erase_buf + ++ part->parent->erasesize - ++ erase_buf_ofs); ++ } ++ kfree(erase_buf); ++ } ++ + instr->addr -= part->offset; + + return ret; +@@ -525,19 +593,22 @@ static struct mtd_part *allocate_partiti + remainder = do_div(tmp, wr_alignment); + if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) { + /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of +- * _minor_ erase size though */ +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", +- part->name); ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ if (((u32)slave->mtd.size) > parent->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + + tmp = part_absolute_offset(parent) + slave->offset + slave->mtd.size; + remainder = do_div(tmp, wr_alignment); + if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) { +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", +- part->name); ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ ++ if ((u32)slave->mtd.size > parent->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; + } + + mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops); diff --git a/ipq806x/pending-5.4/412-mtd-partial_eraseblock_unlock.patch b/ipq806x/pending-5.4/412-mtd-partial_eraseblock_unlock.patch new file mode 100644 index 0000000..b23bc1b --- /dev/null +++ b/ipq806x/pending-5.4/412-mtd-partial_eraseblock_unlock.patch @@ -0,0 +1,40 @@ +From: Tim Harvey +Subject: mtd: allow partial block unlock + +This allows sysupgrade for devices such as the Gateworks Avila/Cambria +product families based on the ixp4xx using the redboot bootloader with +combined FIS directory and RedBoot config partitions on larger FLASH +devices with larger eraseblocks. + +This second iteration of this patch addresses previous issues: +- whitespace breakage fixed +- unlock in all scenarios +- simplification and fix logic bug + +[john@phrozen.org: this should be moved to the ixp4xx folder] + +Signed-off-by: Tim Harvey +--- + drivers/mtd/mtdpart.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -293,7 +293,16 @@ static int part_lock(struct mtd_info *mt + static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) + { + struct mtd_part *part = mtd_to_part(mtd); +- return part->parent->_unlock(part->parent, ofs + part->offset, len); ++ ++ ofs += part->offset; ++ ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ /* round up len to next erasesize and round down offset to prev block */ ++ len = (mtd_div_by_eb(len, part->parent) + 1) * part->parent->erasesize; ++ ofs &= ~(part->parent->erasesize - 1); ++ } ++ ++ return part->parent->_unlock(part->parent, ofs, len); + } + + static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) diff --git a/ipq806x/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch b/ipq806x/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch new file mode 100644 index 0000000..7692f48 --- /dev/null +++ b/ipq806x/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch @@ -0,0 +1,22 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: [PATCH] mtd: redboot: add of_match_table with DT binding +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows parsing RedBoot compatible partitions for properly described +flash device in DT. + +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/mtd/parsers/redboot.c ++++ b/drivers/mtd/parsers/redboot.c +@@ -305,6 +305,7 @@ static int parse_redboot_partitions(stru + + static const struct of_device_id mtd_parser_redboot_of_match_table[] = { + { .compatible = "redboot-fis" }, ++ { .compatible = "ecoscentric,redboot-fis-partitions" }, + {}, + }; + MODULE_DEVICE_TABLE(of, mtd_parser_redboot_of_match_table); diff --git a/ipq806x/pending-5.4/420-mtd-redboot_space.patch b/ipq806x/pending-5.4/420-mtd-redboot_space.patch new file mode 100644 index 0000000..a3cd4ec --- /dev/null +++ b/ipq806x/pending-5.4/420-mtd-redboot_space.patch @@ -0,0 +1,41 @@ +From: Felix Fietkau +Subject: add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable) + +[john@phrozen.org: used by ixp and others] + +lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00 +Signed-off-by: Felix Fietkau +--- + drivers/mtd/redboot.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +--- a/drivers/mtd/parsers/redboot.c ++++ b/drivers/mtd/parsers/redboot.c +@@ -279,14 +279,21 @@ static int parse_redboot_partitions(stru + #endif + names += strlen(names)+1; + +-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED + if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { +- i++; +- parts[i].offset = parts[i-1].size + parts[i-1].offset; +- parts[i].size = fl->next->img->flash_base - parts[i].offset; +- parts[i].name = nullname; +- } ++ if (!strcmp(parts[i].name, "rootfs")) { ++ parts[i].size = fl->next->img->flash_base; ++ parts[i].size &= ~(master->erasesize - 1); ++ parts[i].size -= parts[i].offset; ++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED ++ nrparts--; ++ } else { ++ i++; ++ parts[i].offset = parts[i-1].size + parts[i-1].offset; ++ parts[i].size = fl->next->img->flash_base - parts[i].offset; ++ parts[i].name = nullname; + #endif ++ } ++ } + tmp_fl = fl; + fl = fl->next; + kfree(tmp_fl); diff --git a/ipq806x/pending-5.4/430-mtd-add-myloader-partition-parser.patch b/ipq806x/pending-5.4/430-mtd-add-myloader-partition-parser.patch new file mode 100644 index 0000000..3319ed9 --- /dev/null +++ b/ipq806x/pending-5.4/430-mtd-add-myloader-partition-parser.patch @@ -0,0 +1,229 @@ +From: Florian Fainelli +Subject: Add myloader partition table parser + +[john@phozen.org: shoud be upstreamable] + +lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8 +Signed-off-by: Florian Fainelli +[adjust for kernel 5.4, add myloader.c to patch] +Signed-off-by: Adrian Schmutzler + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -57,6 +57,22 @@ config MTD_CMDLINE_PARTS + + If unsure, say 'N'. + ++config MTD_MYLOADER_PARTS ++ tristate "MyLoader partition parsing" ++ depends on ADM5120 || ATH25 || ATH79 ++ ---help--- ++ MyLoader is a bootloader which allows the user to define partitions ++ in flash devices, by putting a table in the second erase block ++ on the device, similar to a partition table. This table gives the ++ offsets and lengths of the user defined partitions. ++ ++ If you need code which can detect and parse these tables, and ++ register MTD 'partitions' corresponding to each image detected, ++ enable this option. ++ ++ You will still need the parsing functions to be called by the driver ++ for your particular device. It won't happen automatically. ++ + config MTD_OF_PARTS + tristate "OpenFirmware (device tree) partitioning parser" + default y +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -3,6 +3,7 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part. + obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o ++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + ofpart-y += ofpart_core.o + ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o +--- /dev/null ++++ b/drivers/mtd/parsers/myloader.c +@@ -0,0 +1,181 @@ ++/* ++ * Parse MyLoader-style flash partition tables and produce a Linux partition ++ * array to match. ++ * ++ * Copyright (C) 2007-2009 Gabor Juhos ++ * ++ * This file was based on drivers/mtd/redboot.c ++ * Author: Red Hat, Inc. - David Woodhouse ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define BLOCK_LEN_MIN 0x10000 ++#define PART_NAME_LEN 32 ++ ++struct part_data { ++ struct mylo_partition_table tab; ++ char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN]; ++}; ++ ++static int myloader_parse_partitions(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct part_data *buf; ++ struct mylo_partition_table *tab; ++ struct mylo_partition *part; ++ struct mtd_partition *mtd_parts; ++ struct mtd_partition *mtd_part; ++ int num_parts; ++ int ret, i; ++ size_t retlen; ++ char *names; ++ unsigned long offset; ++ unsigned long blocklen; ++ ++ buf = vmalloc(sizeof(*buf)); ++ if (!buf) { ++ return -ENOMEM; ++ goto out; ++ } ++ tab = &buf->tab; ++ ++ blocklen = master->erasesize; ++ if (blocklen < BLOCK_LEN_MIN) ++ blocklen = BLOCK_LEN_MIN; ++ ++ offset = blocklen; ++ ++ /* Find the partition table */ ++ for (i = 0; i < 4; i++, offset += blocklen) { ++ printk(KERN_DEBUG "%s: searching for MyLoader partition table" ++ " at offset 0x%lx\n", master->name, offset); ++ ++ ret = mtd_read(master, offset, sizeof(*buf), &retlen, ++ (void *)buf); ++ if (ret) ++ goto out_free_buf; ++ ++ if (retlen != sizeof(*buf)) { ++ ret = -EIO; ++ goto out_free_buf; ++ } ++ ++ /* Check for Partition Table magic number */ ++ if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS)) ++ break; ++ ++ } ++ ++ if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) { ++ printk(KERN_DEBUG "%s: no MyLoader partition table found\n", ++ master->name); ++ ret = 0; ++ goto out_free_buf; ++ } ++ ++ /* The MyLoader and the Partition Table is always present */ ++ num_parts = 2; ++ ++ /* Detect number of used partitions */ ++ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { ++ part = &tab->partitions[i]; ++ ++ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) ++ continue; ++ ++ num_parts++; ++ } ++ ++ mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) + ++ num_parts * PART_NAME_LEN), GFP_KERNEL); ++ ++ if (!mtd_parts) { ++ ret = -ENOMEM; ++ goto out_free_buf; ++ } ++ ++ mtd_part = mtd_parts; ++ names = (char *)&mtd_parts[num_parts]; ++ ++ strncpy(names, "myloader", PART_NAME_LEN); ++ mtd_part->name = names; ++ mtd_part->offset = 0; ++ mtd_part->size = offset; ++ mtd_part->mask_flags = MTD_WRITEABLE; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ ++ strncpy(names, "partition_table", PART_NAME_LEN); ++ mtd_part->name = names; ++ mtd_part->offset = offset; ++ mtd_part->size = blocklen; ++ mtd_part->mask_flags = MTD_WRITEABLE; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ ++ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { ++ part = &tab->partitions[i]; ++ ++ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) ++ continue; ++ ++ if ((buf->names[i][0]) && (buf->names[i][0] != '\xff')) ++ strncpy(names, buf->names[i], PART_NAME_LEN); ++ else ++ snprintf(names, PART_NAME_LEN, "partition%d", i); ++ ++ mtd_part->offset = le32_to_cpu(part->addr); ++ mtd_part->size = le32_to_cpu(part->size); ++ mtd_part->name = names; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ } ++ ++ *pparts = mtd_parts; ++ ret = num_parts; ++ ++ out_free_buf: ++ vfree(buf); ++ out: ++ return ret; ++} ++ ++static struct mtd_part_parser myloader_mtd_parser = { ++ .owner = THIS_MODULE, ++ .parse_fn = myloader_parse_partitions, ++ .name = "MyLoader", ++}; ++ ++static int __init myloader_mtd_parser_init(void) ++{ ++ register_mtd_parser(&myloader_mtd_parser); ++ ++ return 0; ++} ++ ++static void __exit myloader_mtd_parser_exit(void) ++{ ++ deregister_mtd_parser(&myloader_mtd_parser); ++} ++ ++module_init(myloader_mtd_parser_init); ++module_exit(myloader_mtd_parser_exit); ++ ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_DESCRIPTION("Parsing code for MyLoader partition tables"); ++MODULE_LICENSE("GPL v2"); diff --git a/ipq806x/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch b/ipq806x/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch new file mode 100644 index 0000000..2ea59cd --- /dev/null +++ b/ipq806x/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch @@ -0,0 +1,68 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating offsets + +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/mtd/parsers/parser_trx.c ++++ b/drivers/mtd/parsers/parser_trx.c +@@ -25,6 +25,33 @@ struct trx_header { + uint32_t offset[3]; + } __packed; + ++/* ++ * Calculate real end offset (address) for a given amount of data. It checks ++ * all blocks skipping bad ones. ++ */ ++static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes) ++{ ++ size_t real_offset = 0; ++ ++ if (mtd_block_isbad(mtd, real_offset)) ++ pr_warn("Base offset shouldn't be at bad block"); ++ ++ while (bytes >= mtd->erasesize) { ++ bytes -= mtd->erasesize; ++ real_offset += mtd->erasesize; ++ while (mtd_block_isbad(mtd, real_offset)) { ++ real_offset += mtd->erasesize; ++ ++ if (real_offset >= mtd->size) ++ return real_offset - mtd->erasesize; ++ } ++ } ++ ++ real_offset += bytes; ++ ++ return real_offset; ++} ++ + static const char *parser_trx_data_part_name(struct mtd_info *master, + size_t offset) + { +@@ -79,21 +106,21 @@ static int parser_trx_parse(struct mtd_i + if (trx.offset[2]) { + part = &parts[curr_part++]; + part->name = "loader"; +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); + i++; + } + + if (trx.offset[i]) { + part = &parts[curr_part++]; + part->name = "linux"; +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); + i++; + } + + if (trx.offset[i]) { + part = &parts[curr_part++]; +- part->name = parser_trx_data_part_name(mtd, trx.offset[i]); +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); ++ part->name = parser_trx_data_part_name(mtd, part->offset); + i++; + } + diff --git a/ipq806x/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/ipq806x/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch new file mode 100644 index 0000000..852654d --- /dev/null +++ b/ipq806x/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch @@ -0,0 +1,37 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: mtd: bcm47xxpart: detect T_Meter partition + +It can be found on many Netgear devices. It consists of many 0x30 blocks +starting with 4D 54. + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/parsers/bcm47xxpart.c ++++ b/drivers/mtd/parsers/bcm47xxpart.c +@@ -35,6 +35,7 @@ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ + #define POT_MAGIC1 0x54544f50 /* POTT */ + #define POT_MAGIC2 0x504f /* OP */ ++#define T_METER_MAGIC 0x4D540000 /* MT */ + #define ML_MAGIC1 0x39685a42 + #define ML_MAGIC2 0x26594131 + #define TRX_MAGIC 0x30524448 +@@ -178,6 +179,15 @@ static int bcm47xxpart_parse(struct mtd_ + MTD_WRITEABLE); + continue; + } ++ ++ /* T_Meter */ ++ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { ++ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, ++ MTD_WRITEABLE); ++ continue; ++ } + + /* TRX */ + if (buf[0x000 / 4] == TRX_MAGIC) { diff --git a/ipq806x/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch b/ipq806x/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch new file mode 100644 index 0000000..ab1e09a --- /dev/null +++ b/ipq806x/pending-5.4/435-mtd-add-routerbootpart-parser-config.patch @@ -0,0 +1,38 @@ +From 4437e01fb6bca63fccdba5d6c44888b0935885c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= +Date: Tue, 24 Mar 2020 11:45:07 +0100 +Subject: [PATCH] generic: routerboot partition build bits (5.4) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds routerbootpart kernel build bits + +Signed-off-by: Thibaut VARÈNE +--- + drivers/mtd/parsers/Kconfig | 9 +++++++++ + drivers/mtd/parsers/Makefile | 1 + + 2 files changed, 10 insertions(+) + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -195,3 +195,12 @@ config MTD_REDBOOT_PARTS_READONLY + 'FIS directory' images, enable this option. + + endif # MTD_REDBOOT_PARTS ++ ++config MTD_ROUTERBOOT_PARTS ++ tristate "RouterBoot flash partition parser" ++ depends on MTD && OF ++ help ++ MikroTik RouterBoot is implemented as a multi segment system on the ++ flash, some of which are fixed and some of which are located at ++ variable offsets. This parser handles both cases via properly ++ formatted DTS. +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -13,3 +13,4 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o ++obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o diff --git a/ipq806x/pending-5.4/447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch b/ipq806x/pending-5.4/447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch new file mode 100644 index 0000000..e1fcb15 --- /dev/null +++ b/ipq806x/pending-5.4/447-mtd-spinand-gigadevice-Add-support-for-GD5F4GQ4xC.patch @@ -0,0 +1,87 @@ +From 30521ccfb4597f91b9e5c7967acef9c7c85e58a8 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Wed, 12 Aug 2020 22:50:26 +0200 +Subject: [PATCH v2 447/447] mtd: spinand: gigadevice: Add support for + GD5F4GQ4xC + +This adds support for the following 4GiB chips: +GD5F4GQ4RCYIG 1.8V +GD5F4GQ4UCYIG 3.3V + +The datasheet can be found here: +https://www.novitronic.ch/sixcms/media.php/2/DS-00173-GD5F4GQ4xCxIG-Rev1.574695.pdf + +The GD5F4GQ4UCYIGT (3.3V) version is used on the Imagination +Technologies Creator Ci40 (Marduk), the 1.8V version was not tested. + +This device only works in single SPI mode and not in dual or quad mode +for me on this board. + +Signed-off-by: Hauke Mehrtens +--- + drivers/mtd/nand/spi/gigadevice.c | 49 +++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +--- a/drivers/mtd/nand/spi/gigadevice.c ++++ b/drivers/mtd/nand/spi/gigadevice.c +@@ -132,6 +132,35 @@ static const struct mtd_ooblayout_ops gd + .free = gd5fxgq4_variant2_ooblayout_free, + }; + ++static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 128; ++ oobregion->length = 128; ++ ++ return 0; ++} ++ ++static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 1; ++ oobregion->length = 127; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = { ++ .ecc = gd5fxgq4xc_ooblayout_256_ecc, ++ .free = gd5fxgq4xc_ooblayout_256_free, ++}; ++ + static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, + u8 status) + { +@@ -222,6 +251,24 @@ static const struct spinand_info gigadev + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, + gd5fxgq4xa_ecc_get_status)), ++ SPINAND_INFO("GD5F4GQ4RC", 0xa468, ++ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops, ++ gd5fxgq4ufxxg_ecc_get_status)), ++ SPINAND_INFO("GD5F4GQ4UC", 0xb468, ++ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops, ++ gd5fxgq4ufxxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ4UExxG", 0xd1, + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), diff --git a/ipq806x/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch b/ipq806x/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch new file mode 100644 index 0000000..fe2d7a6 --- /dev/null +++ b/ipq806x/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Date: Thu, 22 Feb 2018 11:11:57 +0100 +Subject: [PATCH] mtd: spi-nor: allow NOR driver to write fewer bytes than + requested + +The write size can be constrained by the maximum message/transfer size +of the SPI controller. Only check for ret = 0 to avoid an infinite loop. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -2706,7 +2706,7 @@ static int spi_nor_write(struct mtd_info + + write_enable(nor); + ret = spi_nor_write_data(nor, addr, page_remain, buf + i); +- if (ret < 0) ++ if (ret <= 0) + goto write_err; + written = ret; + diff --git a/ipq806x/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/ipq806x/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch new file mode 100644 index 0000000..659a638 --- /dev/null +++ b/ipq806x/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Subject: kernel: disable cfi cmdset 0002 erase suspend + +on some platforms, erase suspend leads to data corruption and lockups when write +ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh. +rather than play whack-a-mole with a hard to reproduce issue on a variety of devices, +simply disable erase suspend, as it will usually not produce any useful gain on +the small filesystems used on embedded hardware. + +Signed-off-by: Felix Fietkau +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -909,7 +909,7 @@ static int get_chip(struct map_info *map + return 0; + + case FL_ERASING: +- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || ++ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) + goto sleep; diff --git a/ipq806x/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/ipq806x/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch new file mode 100644 index 0000000..8d2195e --- /dev/null +++ b/ipq806x/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch @@ -0,0 +1,17 @@ +From: George Kashperko +Subject: Issue map read after Write Buffer Load command to ensure chip is ready to receive data. + +Signed-off-by: George Kashperko +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 1 + + 1 file changed, 1 insertion(+) +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -2054,6 +2054,7 @@ static int __xipram do_write_buffer(stru + + /* Write Buffer Load */ + map_write(map, CMD(0x25), cmd_adr); ++ (void) map_read(map, cmd_adr); + + chip->state = FL_WRITING_TO_BUFFER; + diff --git a/ipq806x/pending-5.4/465-m25p80-mx-disable-software-protection.patch b/ipq806x/pending-5.4/465-m25p80-mx-disable-software-protection.patch new file mode 100644 index 0000000..24d2d45 --- /dev/null +++ b/ipq806x/pending-5.4/465-m25p80-mx-disable-software-protection.patch @@ -0,0 +1,18 @@ +From: Felix Fietkau +Subject: Disable software protection bits for Macronix flashes. + +Signed-off-by: Felix Fietkau +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -4884,6 +4884,7 @@ int spi_nor_scan(struct spi_nor *nor, co + */ + if (JEDEC_MFR(nor->info) == SNOR_MFR_ATMEL || + JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || ++ JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX || + JEDEC_MFR(nor->info) == SNOR_MFR_SST || + nor->info->flags & SPI_NOR_HAS_LOCK) + nor->clear_sr_bp = spi_nor_clear_sr_bp; diff --git a/ipq806x/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch b/ipq806x/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch new file mode 100644 index 0000000..70f1e9f --- /dev/null +++ b/ipq806x/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch @@ -0,0 +1,35 @@ +From: Matthias Schiffer +Date: Tue, 9 Jan 2018 20:41:48 +0100 +Subject: [PATCH] Revert "mtd: spi-nor: fix Spansion regressions (aliased with + Winbond)" + +This reverts commit 67b9bcd36906e12a15ffec19463afbbd6a41660e. + +The underlying issue breaking Spansion flash has been fixed with "mtd: spi-nor: +wait until lock/unlock operations are ready" and "mtd: spi-nor: wait for SR_WIP +to clear on initial unlock", so we can support unlocking for Winbond flash +again. + +Signed-off-by: Matthias Schiffer +--- + drivers/mtd/spi-nor/spi-nor.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -4398,6 +4398,7 @@ static void st_micron_set_default_init(s + + static void winbond_set_default_init(struct spi_nor *nor) + { ++ nor->flags |= SNOR_F_HAS_LOCK; + nor->params.set_4byte = winbond_set_4byte; + } + +@@ -4886,6 +4887,7 @@ int spi_nor_scan(struct spi_nor *nor, co + JEDEC_MFR(nor->info) == SNOR_MFR_INTEL || + JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX || + JEDEC_MFR(nor->info) == SNOR_MFR_SST || ++ JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND || + nor->info->flags & SPI_NOR_HAS_LOCK) + nor->clear_sr_bp = spi_nor_clear_sr_bp; + diff --git a/ipq806x/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch b/ipq806x/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch new file mode 100644 index 0000000..d3e587f --- /dev/null +++ b/ipq806x/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch @@ -0,0 +1,79 @@ +From: Felix Fietkau +Date: Sat, 4 Nov 2017 07:40:23 +0100 +Subject: [PATCH] mtd: spi-nor: support limiting 4K sectors support based on + flash size + +Some devices need 4K sectors to be able to deal with small flash chips. +For instance, w25x05 is 64 KiB in size, and without 4K sectors, the +entire chip is just one erase block. +On bigger flash chip sizes, using 4K sectors can significantly slow down +many operations, including using a writable filesystem. There are several +platforms where it makes sense to use a single kernel on both kinds of +devices. + +To support this properly, allow configuring an upper flash chip size +limit for 4K sectors support. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/mtd/spi-nor/Kconfig ++++ b/drivers/mtd/spi-nor/Kconfig +@@ -34,6 +34,17 @@ config SPI_ASPEED_SMC + and support for the SPI flash memory controller (SPI) for + the host firmware. The implementation only supports SPI NOR. + ++config MTD_SPI_NOR_USE_4K_SECTORS_LIMIT ++ int "Maximum flash chip size to use 4K sectors on (in KiB)" ++ depends on MTD_SPI_NOR_USE_4K_SECTORS ++ default "4096" ++ help ++ There are many flash chips that support 4K sectors, but are so large ++ that using them significantly slows down writing large amounts of ++ data or using a writable filesystem. ++ Any flash chip larger than the size specified in this option will ++ not use 4K sectors. ++ + config SPI_CADENCE_QUADSPI + tristate "Cadence Quad SPI controller" + depends on OF && (ARM || ARM64 || COMPILE_TEST) +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -4464,6 +4464,7 @@ static void spi_nor_info_init_params(str + struct spi_nor_erase_map *map = ¶ms->erase_map; + const struct flash_info *info = nor->info; + struct device_node *np = spi_nor_get_flash_node(nor); ++ struct mtd_info *mtd = &nor->mtd; + u8 i, erase_mask; + + /* Initialize legacy flash parameters and settings. */ +@@ -4527,6 +4528,21 @@ static void spi_nor_info_init_params(str + */ + erase_mask = 0; + i = 0; ++#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS ++ if ((info->flags & SECT_4K_PMC) && (mtd->size <= ++ CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT * 1024)) { ++ erase_mask |= BIT(i); ++ spi_nor_set_erase_type(&map->erase_type[i], 4096u, ++ SPINOR_OP_BE_4K_PMC); ++ i++; ++ } else if ((info->flags & SECT_4K) && (mtd->size <= ++ CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT * 1024)) { ++ erase_mask |= BIT(i); ++ spi_nor_set_erase_type(&map->erase_type[i], 4096u, ++ SPINOR_OP_BE_4K); ++ i++; ++ } ++#else + if (info->flags & SECT_4K_PMC) { + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], 4096u, +@@ -4538,6 +4554,7 @@ static void spi_nor_info_init_params(str + SPINOR_OP_BE_4K); + i++; + } ++#endif + erase_mask |= BIT(i); + spi_nor_set_erase_type(&map->erase_type[i], info->sector_size, + SPINOR_OP_SE); diff --git a/ipq806x/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch b/ipq806x/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch new file mode 100644 index 0000000..b62dae5 --- /dev/null +++ b/ipq806x/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch @@ -0,0 +1,18 @@ +From: Piotr Dymacz +Subject: kernel/mtd: add support for EON EN25Q128 + +Signed-off-by: Piotr Dymacz +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -2179,6 +2179,7 @@ static const struct flash_info spi_nor_i + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, + { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, ++ { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) }, + { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ) }, + { "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) }, diff --git a/ipq806x/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch b/ipq806x/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch new file mode 100644 index 0000000..39e0260 --- /dev/null +++ b/ipq806x/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch @@ -0,0 +1,42 @@ +From patchwork Thu Feb 6 17:19:41 2020 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 1234465 +Date: Thu, 6 Feb 2020 19:19:41 +0200 +From: Daniel Golle +To: linux-mtd@lists.infradead.org +Subject: [PATCH v2] mtd: spi-nor: Add support for xt25f128b chip +Message-ID: <20200206171941.GA2398@makrotopia.org> +MIME-Version: 1.0 +Content-Disposition: inline +List-Subscribe: , + +Cc: Eitan Cohen , Piotr Dymacz , + Tudor Ambarus +Sender: "linux-mtd" +Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org + +Add XT25F128B made by XTX Technology (Shenzhen) Limited. +This chip supports dual and quad read and uniform 4K-byte erase. +Verified on Teltonika RUT955 which comes with XT25F128B in recent +versions of the device. + +Signed-off-by: Daniel Golle +--- + drivers/mtd/spi-nor/spi-nor.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -2506,6 +2506,9 @@ static const struct flash_info spi_nor_i + /* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */ + { "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ ++ /* XTX Technology (Shenzhen) Limited */ ++ { "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { }, + }; + diff --git a/ipq806x/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch b/ipq806x/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch new file mode 100644 index 0000000..95863d6 --- /dev/null +++ b/ipq806x/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch @@ -0,0 +1,38 @@ +From: Gabor Juhos +Subject: kernel/3.1[02]: move MTD root device setup code to mtdcore + +The current code only allows to automatically set +root device on MTD partitions. Move the code to MTD +core to allow to use it with all MTD devices. + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/mtdcore.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -699,6 +700,15 @@ int add_mtd_device(struct mtd_info *mtd) + of this try_ nonsense, and no bitching about it + either. :) */ + __module_get(THIS_MODULE); ++ ++ if (!strcmp(mtd->name, "rootfs") && ++ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("mtd: device %d (%s) set to be root filesystem\n", ++ mtd->index, mtd->name); ++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); ++ } ++ + return 0; + + fail_nvmem_add: diff --git a/ipq806x/pending-5.4/481-mtd-spi-nor-rework-broken-flash-reset-support.patch b/ipq806x/pending-5.4/481-mtd-spi-nor-rework-broken-flash-reset-support.patch new file mode 100644 index 0000000..81b4f19 --- /dev/null +++ b/ipq806x/pending-5.4/481-mtd-spi-nor-rework-broken-flash-reset-support.patch @@ -0,0 +1,167 @@ +From ea92cbb50a78404e29de2cc3999a240615ffb1c8 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Mon, 6 Apr 2020 17:58:48 +0800 +Subject: [PATCH] mtd: spi-nor: rework broken-flash-reset support + +Instead of resetting flash to 3B address on remove hook, this +implementation only enters 4B mode when needed, which prevents +more unexpected reboot stuck. This implementation makes it only +break when a kernel panic happens during flash operation on 16M+ +areas. +*OpenWrt only*: silent broken-flash-reset warning. We are not dealing +with vendors and it's unpleasant for users to se that unnecessary +and long WARN_ON print. + +Signed-off-by: Chuanhong Guo +--- + drivers/mtd/spi-nor/spi-nor.c | 52 +++++++++++++++++++++++++++++++++-- + 1 file changed, 49 insertions(+), 3 deletions(-) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -616,6 +616,22 @@ static void spi_nor_set_4byte_opcodes(st + } + } + ++static int spi_nor_check_set_addr_width(struct spi_nor *nor, loff_t addr) ++{ ++ u8 addr_width; ++ ++ if ((nor->flags & (SNOR_F_4B_OPCODES | SNOR_F_BROKEN_RESET)) != ++ SNOR_F_BROKEN_RESET) ++ return 0; ++ ++ addr_width = addr & 0xff000000 ? 4 : 3; ++ if (nor->addr_width == addr_width) ++ return 0; ++ ++ nor->addr_width = addr_width; ++ return nor->params.set_4byte(nor, addr_width == 4); ++} ++ + static int macronix_set_4byte(struct spi_nor *nor, bool enable) + { + if (nor->spimem) { +@@ -1261,6 +1277,10 @@ static int spi_nor_erase(struct mtd_info + if (ret) + return ret; + ++ ret = spi_nor_check_set_addr_width(nor, instr->addr + instr->len); ++ if (ret < 0) ++ return ret; ++ + /* whole-chip erase? */ + if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { + unsigned long timeout; +@@ -1317,6 +1337,7 @@ static int spi_nor_erase(struct mtd_info + write_disable(nor); + + erase_err: ++ spi_nor_check_set_addr_width(nor, 0); + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); + + return ret; +@@ -1623,7 +1644,9 @@ static int spi_nor_lock(struct mtd_info + if (ret) + return ret; + ++ spi_nor_check_set_addr_width(nor, ofs + len); + ret = nor->params.locking_ops->lock(nor, ofs, len); ++ spi_nor_check_set_addr_width(nor, 0); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); + return ret; +@@ -1638,7 +1661,9 @@ static int spi_nor_unlock(struct mtd_inf + if (ret) + return ret; + ++ spi_nor_check_set_addr_width(nor, ofs + len); + ret = nor->params.locking_ops->unlock(nor, ofs, len); ++ spi_nor_check_set_addr_width(nor, 0); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + return ret; +@@ -1653,7 +1678,9 @@ static int spi_nor_is_locked(struct mtd_ + if (ret) + return ret; + ++ spi_nor_check_set_addr_width(nor, ofs + len); + ret = nor->params.locking_ops->is_locked(nor, ofs, len); ++ spi_nor_check_set_addr_width(nor, 0); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + return ret; +@@ -2559,6 +2586,10 @@ static int spi_nor_read(struct mtd_info + if (ret) + return ret; + ++ ret = spi_nor_check_set_addr_width(nor, from + len); ++ if (ret < 0) ++ return ret; ++ + while (len) { + loff_t addr = from; + +@@ -2582,6 +2613,7 @@ static int spi_nor_read(struct mtd_info + ret = 0; + + read_err: ++ spi_nor_check_set_addr_width(nor, 0); + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); + return ret; + } +@@ -2599,6 +2631,10 @@ static int sst_write(struct mtd_info *mt + if (ret) + return ret; + ++ ret = spi_nor_check_set_addr_width(nor, to + len); ++ if (ret < 0) ++ return ret; ++ + write_enable(nor); + + nor->sst_write_second = false; +@@ -2661,6 +2697,7 @@ static int sst_write(struct mtd_info *mt + } + sst_write_err: + *retlen += actual; ++ spi_nor_check_set_addr_width(nor, 0); + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + return ret; + } +@@ -2683,6 +2720,10 @@ static int spi_nor_write(struct mtd_info + if (ret) + return ret; + ++ ret = spi_nor_check_set_addr_width(nor, to + len); ++ if (ret < 0) ++ return ret; ++ + for (i = 0; i < len; ) { + ssize_t written; + loff_t addr = to + i; +@@ -2722,6 +2763,7 @@ static int spi_nor_write(struct mtd_info + } + + write_err: ++ spi_nor_check_set_addr_width(nor, 0); + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); + return ret; + } +@@ -4726,9 +4768,13 @@ static int spi_nor_init(struct spi_nor * + * reboots (e.g., crashes). Warn the user (or hopefully, system + * designer) that this is bad. + */ +- WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, +- "enabling reset hack; may not recover from unexpected reboots\n"); +- nor->params.set_4byte(nor, true); ++ if (nor->flags & SNOR_F_BROKEN_RESET) { ++ dev_warn(nor->dev, ++ "enabling reset hack; may not recover from unexpected reboots\n"); ++ nor->addr_width = 3; ++ } else { ++ nor->params.set_4byte(nor, true); ++ } + } + + return 0; diff --git a/ipq806x/pending-5.4/482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch b/ipq806x/pending-5.4/482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch new file mode 100644 index 0000000..3a22133 --- /dev/null +++ b/ipq806x/pending-5.4/482-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch @@ -0,0 +1,24 @@ +From d68b4aa22e8c625685bfad642dd7337948dc0ad1 Mon Sep 17 00:00:00 2001 +From: Koen Vandeputte +Date: Mon, 6 Jan 2020 13:07:56 +0100 +Subject: [PATCH] mtd: spi-nor: add support for Gigadevice GD25D05 + +Signed-off-by: Koen Vandeputte +--- + drivers/mtd/spi-nor/spi-nor.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -2232,6 +2232,11 @@ static const struct flash_info spi_nor_i + + /* GigaDevice */ + { ++ "gd25d05", INFO(0xc84010, 0, 64 * 1024, 1, ++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | ++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) ++ }, ++ { + "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) diff --git a/ipq806x/pending-5.4/482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch b/ipq806x/pending-5.4/482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch new file mode 100644 index 0000000..63366e6 --- /dev/null +++ b/ipq806x/pending-5.4/482-mtd-spi-nor-fix-4-byte-opcode-support-for-w25q256.patch @@ -0,0 +1,60 @@ +From: Mantas Pucka +To: linux-mtd@lists.infradead.org +Subject: [PATCH] mtd: spi-nor: fix 4-byte opcode support for w25q256 +Date: Wed, 15 Apr 2020 16:48:30 +0300 +Message-ID: <1586958510-24012-1-git-send-email-mantas@8devices.com> + +There are 2 different chips (w25q256fv and w25q256jv) that share +the same JEDEC ID. Only w25q256jv fully supports 4-byte opcodes. +Use SFDP header version to differentiate between them. + +for OpenWRT only: rebased to linux-v5.4 + +Signed-off-by: Mantas Pucka +--- + +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -2172,6 +2172,32 @@ static struct spi_nor_fixups gd25q256_fi + .default_init = gd25q256_default_init, + }; + ++static int ++w25q256_post_bfpt_fixups(struct spi_nor *nor, ++ const struct sfdp_parameter_header *bfpt_header, ++ const struct sfdp_bfpt *bfpt, ++ struct spi_nor_flash_parameter *params) ++{ ++ /* ++ * W25Q256JV supports 4B opcodes but W25Q256FV does not. ++ * Unfortunately, Winbond has re-used the same JEDEC ID for both ++ * variants which prevents us from defining a new entry in the parts ++ * table. ++ * To differentiate between W25Q256JV and W25Q256FV check SFDP header ++ * version: only JV has JESD216A compliant structure (version 5) ++ */ ++ ++ if (bfpt_header->major == SFDP_JESD216_MAJOR && ++ bfpt_header->minor == SFDP_JESD216A_MINOR) ++ nor->flags |= SNOR_F_4B_OPCODES; ++ ++ return 0; ++} ++ ++static struct spi_nor_fixups w25q256_fixups = { ++ .post_bfpt = w25q256_post_bfpt_fixups, ++}; ++ + /* NOTE: double check command sets and memory organization when you add + * more nor chips. This current list focusses on newer chips, which + * have been converging on command sets which including JEDEC ID. +@@ -2515,7 +2541,8 @@ static const struct flash_info spi_nor_i + { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, +- { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) ++ .fixups = &w25q256_fixups }, + { "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024, diff --git a/ipq806x/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/ipq806x/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch new file mode 100644 index 0000000..b21daea --- /dev/null +++ b/ipq806x/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -0,0 +1,97 @@ +From: Daniel Golle +Subject: ubi: auto-attach mtd device named "ubi" or "data" on boot + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/mtd/ubi/build.c ++++ b/drivers/mtd/ubi/build.c +@@ -1168,6 +1168,73 @@ static struct mtd_info * __init open_mtd + return mtd; + } + ++/* ++ * This function tries attaching mtd partitions named either "ubi" or "data" ++ * during boot. ++ */ ++static void __init ubi_auto_attach(void) ++{ ++ int err; ++ struct mtd_info *mtd; ++ loff_t offset = 0; ++ size_t len; ++ char magic[4]; ++ ++ /* try attaching mtd device named "ubi" or "data" */ ++ mtd = open_mtd_device("ubi"); ++ if (IS_ERR(mtd)) ++ mtd = open_mtd_device("data"); ++ ++ if (IS_ERR(mtd)) ++ return; ++ ++ /* get the first not bad block */ ++ if (mtd_can_have_bb(mtd)) ++ while (mtd_block_isbad(mtd, offset)) { ++ offset += mtd->erasesize; ++ ++ if (offset > mtd->size) { ++ pr_err("UBI error: Failed to find a non-bad " ++ "block on mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ } ++ ++ /* check if the read from flash was successful */ ++ err = mtd_read(mtd, offset, 4, &len, (void *) magic); ++ if ((err && !mtd_is_bitflip(err)) || len != 4) { ++ pr_err("UBI error: unable to read from mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ /* check for a valid ubi magic */ ++ if (strncmp(magic, "UBI#", 4)) { ++ pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ /* don't auto-add media types where UBI doesn't makes sense */ ++ if (mtd->type != MTD_NANDFLASH && ++ mtd->type != MTD_NORFLASH && ++ mtd->type != MTD_DATAFLASH && ++ mtd->type != MTD_MLCNANDFLASH) ++ goto cleanup; ++ ++ mutex_lock(&ubi_devices_mutex); ++ pr_notice("UBI: auto-attach mtd%d\n", mtd->index); ++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0); ++ mutex_unlock(&ubi_devices_mutex); ++ if (err < 0) { ++ pr_err("UBI error: cannot attach mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ return; ++ ++cleanup: ++ put_mtd_device(mtd); ++} ++ + static int __init ubi_init(void) + { + int err, i, k; +@@ -1251,6 +1318,12 @@ static int __init ubi_init(void) + } + } + ++ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd ++ * parameter was given */ ++ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ !ubi_is_module() && !mtd_devs) ++ ubi_auto_attach(); ++ + err = ubiblock_init(); + if (err) { + pr_err("UBI error: block: cannot initialize, error %d\n", err); diff --git a/ipq806x/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/ipq806x/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch new file mode 100644 index 0000000..61fcbac --- /dev/null +++ b/ipq806x/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -0,0 +1,66 @@ +From: Daniel Golle +Subject: ubi: auto-create ubiblock device for rootfs + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -652,6 +652,44 @@ static void __init ubiblock_create_from_ + } + } + ++#define UBIFS_NODE_MAGIC 0x06101831 ++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) ++{ ++ int ret; ++ uint32_t magic_of, magic; ++ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); ++ if (ret) ++ return 0; ++ magic = le32_to_cpu(magic_of); ++ return magic == UBIFS_NODE_MAGIC; ++} ++ ++static void __init ubiblock_create_auto_rootfs(void) ++{ ++ int ubi_num, ret, is_ubifs; ++ struct ubi_volume_desc *desc; ++ struct ubi_volume_info vi; ++ ++ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) { ++ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY); ++ if (IS_ERR(desc)) ++ continue; ++ ++ ubi_get_volume_info(desc, &vi); ++ is_ubifs = ubi_vol_is_ubifs(desc); ++ ubi_close_volume(desc); ++ if (is_ubifs) ++ break; ++ ++ ret = ubiblock_create(&vi); ++ if (ret) ++ pr_err("UBI error: block: can't add '%s' volume, err=%d\n", ++ vi.name, ret); ++ /* always break if we get here */ ++ break; ++ } ++} ++ + static void ubiblock_remove_all(void) + { + struct ubiblock *next; +@@ -684,6 +722,10 @@ int __init ubiblock_init(void) + */ + ubiblock_create_from_param(); + ++ /* auto-attach "rootfs" volume if existing and non-ubifs */ ++ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV)) ++ ubiblock_create_auto_rootfs(); ++ + /* + * Block devices are only created upon user requests, so we ignore + * existing volumes. diff --git a/ipq806x/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/ipq806x/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch new file mode 100644 index 0000000..aa61f4a --- /dev/null +++ b/ipq806x/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch @@ -0,0 +1,51 @@ +From: Daniel Golle +Subject: try auto-mounting ubi0:rootfs in init/do_mounts.c + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -460,7 +460,28 @@ retry: + out: + put_page(page); + } +- ++ ++static int __init mount_ubi_rootfs(void) ++{ ++ int flags = MS_SILENT; ++ int err, tried = 0; ++ ++ while (tried < 2) { ++ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \ ++ root_mount_data); ++ switch (err) { ++ case -EACCES: ++ flags |= MS_RDONLY; ++ tried++; ++ break; ++ default: ++ return err; ++ } ++ } ++ ++ return -EINVAL; ++} ++ + #ifdef CONFIG_ROOT_NFS + + #define NFSROOT_TIMEOUT_MIN 5 +@@ -554,6 +575,10 @@ void __init mount_root(void) + change_floppy("root floppy"); + } + #endif ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (!mount_ubi_rootfs()) ++ return; ++#endif + #ifdef CONFIG_BLOCK + { + int err = create_dev("/dev/root", ROOT_DEV); diff --git a/ipq806x/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/ipq806x/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch new file mode 100644 index 0000000..2dff468 --- /dev/null +++ b/ipq806x/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch @@ -0,0 +1,34 @@ +From: Daniel Golle +Subject: ubi: set ROOT_DEV to ubiblock "rootfs" if unset + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #include "ubi-media.h" + #include "ubi.h" +@@ -458,6 +459,15 @@ int ubiblock_create(struct ubi_volume_in + dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", + dev->ubi_num, dev->vol_id, vi->name); + mutex_unlock(&devices_mutex); ++ ++ if (!strcmp(vi->name, "rootfs") && ++ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n", ++ dev->ubi_num, dev->vol_id, vi->name); ++ ROOT_DEV = MKDEV(gd->major, gd->first_minor); ++ } ++ + return 0; + + out_free_queue: diff --git a/ipq806x/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch b/ipq806x/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch new file mode 100644 index 0000000..fc48146 --- /dev/null +++ b/ipq806x/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch @@ -0,0 +1,60 @@ +From: Gabor Juhos +Subject: mtd: add EOF marker support to the UBI layer + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++--- + drivers/mtd/ubi/ubi.h | 1 + + 2 files changed, 23 insertions(+), 3 deletions(-) + +--- a/drivers/mtd/ubi/attach.c ++++ b/drivers/mtd/ubi/attach.c +@@ -926,6 +926,13 @@ static bool vol_ignored(int vol_id) + #endif + } + ++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech) ++{ ++ return ech->padding1[0] == 'E' && ++ ech->padding1[1] == 'O' && ++ ech->padding1[2] == 'F'; ++} ++ + /** + * scan_peb - scan and process UBI headers of a PEB. + * @ubi: UBI device description object +@@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *u + return 0; + } + +- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); +- if (err < 0) +- return err; ++ if (!ai->eof_found) { ++ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); ++ if (err < 0) ++ return err; ++ ++ if (ec_hdr_has_eof(ech)) { ++ pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n", ++ pnum); ++ ai->eof_found = true; ++ } ++ } ++ ++ if (ai->eof_found) ++ err = UBI_IO_FF_BITFLIPS; ++ + switch (err) { + case 0: + break; +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -780,6 +780,7 @@ struct ubi_attach_info { + int mean_ec; + uint64_t ec_sum; + int ec_count; ++ bool eof_found; + struct kmem_cache *aeb_slab_cache; + struct ubi_ec_hdr *ech; + struct ubi_vid_io_buf *vidb; diff --git a/ipq806x/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch b/ipq806x/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch new file mode 100644 index 0000000..a173381 --- /dev/null +++ b/ipq806x/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch @@ -0,0 +1,75 @@ +From 1bd1b740f208d1cf4071932cc51860d37266c402 Mon Sep 17 00:00:00 2001 +From: Bernhard Frauendienst +Date: Sat, 1 Sep 2018 00:30:11 +0200 +Subject: [PATCH 495/497] mtd: core: add get_mtd_device_by_node + +Add function to retrieve a mtd device by its OF node. Since drivers can +assign arbitrary names to mtd devices in the absence of a label +property, there is no other reliable way to retrieve a mtd device for a +given OF node. + +Signed-off-by: Bernhard Frauendienst +Reviewed-by: Miquel Raynal +--- + drivers/mtd/mtdcore.c | 38 ++++++++++++++++++++++++++++++++++++++ + include/linux/mtd/mtd.h | 2 ++ + 2 files changed, 40 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -1053,6 +1053,44 @@ out_unlock: + } + EXPORT_SYMBOL_GPL(get_mtd_device_nm); + ++/** ++ * get_mtd_device_by_node - obtain a validated handle for an MTD device ++ * by of_node ++ * @of_node: OF node of MTD device to open ++ * ++ * This function returns MTD device description structure in case of ++ * success and an error code in case of failure. ++ */ ++struct mtd_info *get_mtd_device_by_node(const struct device_node *of_node) ++{ ++ int err = -ENODEV; ++ struct mtd_info *mtd = NULL, *other; ++ ++ mutex_lock(&mtd_table_mutex); ++ ++ mtd_for_each_device(other) { ++ if (of_node == other->dev.of_node) { ++ mtd = other; ++ break; ++ } ++ } ++ ++ if (!mtd) ++ goto out_unlock; ++ ++ err = __get_mtd_device(mtd); ++ if (err) ++ goto out_unlock; ++ ++ mutex_unlock(&mtd_table_mutex); ++ return mtd; ++ ++out_unlock: ++ mutex_unlock(&mtd_table_mutex); ++ return ERR_PTR(err); ++} ++EXPORT_SYMBOL_GPL(get_mtd_device_by_node); ++ + void put_mtd_device(struct mtd_info *mtd) + { + mutex_lock(&mtd_table_mutex); +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -586,6 +586,8 @@ extern struct mtd_info *get_mtd_device(s + extern int __get_mtd_device(struct mtd_info *mtd); + extern void __put_mtd_device(struct mtd_info *mtd); + extern struct mtd_info *get_mtd_device_nm(const char *name); ++extern struct mtd_info *get_mtd_device_by_node( ++ const struct device_node *of_node); + extern void put_mtd_device(struct mtd_info *mtd); + + diff --git a/ipq806x/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch b/ipq806x/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch new file mode 100644 index 0000000..01f3b9e --- /dev/null +++ b/ipq806x/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch @@ -0,0 +1,52 @@ +From 5734c6669fba7ddb5ef491ccff7159d15dba0b59 Mon Sep 17 00:00:00 2001 +From: Bernhard Frauendienst +Date: Wed, 5 Sep 2018 01:32:51 +0200 +Subject: [PATCH 496/497] dt-bindings: add bindings for mtd-concat devices + +Document virtual mtd-concat device bindings. + +Signed-off-by: Bernhard Frauendienst +--- + .../devicetree/bindings/mtd/mtd-concat.txt | 36 +++++++++++++++++++ + 1 file changed, 36 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt +@@ -0,0 +1,36 @@ ++Virtual MTD concat device ++ ++Requires properties: ++- devices: list of phandles to mtd nodes that should be concatenated ++ ++Example: ++ ++&spi { ++ flash0: flash@0 { ++ ... ++ }; ++ flash1: flash@1 { ++ ... ++ }; ++}; ++ ++flash { ++ compatible = "mtd-concat"; ++ ++ devices = <&flash0 &flash1>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ ++ partition@0 { ++ label = "boot"; ++ reg = <0x0000000 0x0040000>; ++ read-only; ++ }; ++ ++ partition@40000 { ++ label = "firmware"; ++ reg = <0x0040000 0x1fc0000>; ++ }; ++ } ++} diff --git a/ipq806x/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch b/ipq806x/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch new file mode 100644 index 0000000..1c42ed7 --- /dev/null +++ b/ipq806x/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch @@ -0,0 +1,216 @@ +From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001 +From: Bernhard Frauendienst +Date: Sat, 25 Aug 2018 12:35:22 +0200 +Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices + +Some mtd drivers like physmap variants have support for concatenating +multiple mtd devices, but there is no generic way to define such a +concat device from within the device tree. + +This is useful for some SoC boards that use multiple flash chips as +memory banks of a single mtd device, with partitions spanning chip +borders. + +This commit adds a driver for creating virtual mtd-concat devices. They +must have a compatible = "mtd-concat" line, and define a list of devices +to concat in the 'devices' property, for example: + +flash { + compatible = "mtd-concat"; + + devices = <&flash0 &flash1>; + + partitions { + ... + }; +}; + +The driver is added to the very end of the mtd Makefile to increase the +likelyhood of all child devices already being loaded at the time of +probing, preventing unnecessary deferred probes. + +Signed-off-by: Bernhard Frauendienst +--- + drivers/mtd/Kconfig | 2 + + drivers/mtd/Makefile | 3 + + drivers/mtd/composite/Kconfig | 12 +++ + drivers/mtd/composite/Makefile | 6 ++ + drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++ + 5 files changed, 151 insertions(+) + create mode 100644 drivers/mtd/composite/Kconfig + create mode 100644 drivers/mtd/composite/Makefile + create mode 100644 drivers/mtd/composite/virt_concat.c + +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -228,4 +228,6 @@ source "drivers/mtd/ubi/Kconfig" + + source "drivers/mtd/hyperbus/Kconfig" + ++source "drivers/mtd/composite/Kconfig" ++ + endif # MTD +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -32,3 +32,6 @@ obj-y += chips/ lpddr/ maps/ devices/ n + obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ + obj-$(CONFIG_MTD_UBI) += ubi/ + obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/ ++ ++# Composite drivers must be loaded last ++obj-y += composite/ +--- /dev/null ++++ b/drivers/mtd/composite/Kconfig +@@ -0,0 +1,12 @@ ++menu "Composite MTD device drivers" ++ depends on MTD!=n ++ ++config MTD_VIRT_CONCAT ++ tristate "Virtual concat MTD device" ++ help ++ This driver allows creation of a virtual MTD concat device, which ++ concatenates multiple underlying MTD devices to a single device. ++ This is required by some SoC boards where multiple memory banks are ++ used as one device with partitions spanning across device boundaries. ++ ++endmenu +--- /dev/null ++++ b/drivers/mtd/composite/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# linux/drivers/mtd/composite/Makefile ++# ++ ++obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o +--- /dev/null ++++ b/drivers/mtd/composite/virt_concat.c +@@ -0,0 +1,128 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Virtual concat MTD device driver ++ * ++ * Copyright (C) 2018 Bernhard Frauendienst ++ * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * struct of_virt_concat - platform device driver data. ++ * @cmtd the final mtd_concat device ++ * @num_devices the number of devices in @devices ++ * @devices points to an array of devices already loaded ++ */ ++struct of_virt_concat { ++ struct mtd_info *cmtd; ++ int num_devices; ++ struct mtd_info **devices; ++}; ++ ++static int virt_concat_remove(struct platform_device *pdev) ++{ ++ struct of_virt_concat *info; ++ int i; ++ ++ info = platform_get_drvdata(pdev); ++ if (!info) ++ return 0; ++ ++ // unset data for when this is called after a probe error ++ platform_set_drvdata(pdev, NULL); ++ ++ if (info->cmtd) { ++ mtd_device_unregister(info->cmtd); ++ mtd_concat_destroy(info->cmtd); ++ } ++ ++ if (info->devices) { ++ for (i = 0; i < info->num_devices; i++) ++ put_mtd_device(info->devices[i]); ++ } ++ ++ return 0; ++} ++ ++static int virt_concat_probe(struct platform_device *pdev) ++{ ++ struct device_node *node = pdev->dev.of_node; ++ struct of_phandle_iterator it; ++ struct of_virt_concat *info; ++ struct mtd_info *mtd; ++ int err = 0, count; ++ ++ count = of_count_phandle_with_args(node, "devices", NULL); ++ if (count <= 0) ++ return -EINVAL; ++ ++ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ info->devices = devm_kcalloc(&pdev->dev, count, ++ sizeof(*(info->devices)), GFP_KERNEL); ++ if (!info->devices) { ++ err = -ENOMEM; ++ goto err_remove; ++ } ++ ++ platform_set_drvdata(pdev, info); ++ ++ of_for_each_phandle(&it, err, node, "devices", NULL, 0) { ++ mtd = get_mtd_device_by_node(it.node); ++ if (IS_ERR(mtd)) { ++ of_node_put(it.node); ++ err = -EPROBE_DEFER; ++ goto err_remove; ++ } ++ ++ info->devices[info->num_devices++] = mtd; ++ } ++ ++ info->cmtd = mtd_concat_create(info->devices, info->num_devices, ++ dev_name(&pdev->dev)); ++ if (!info->cmtd) { ++ err = -ENXIO; ++ goto err_remove; ++ } ++ ++ info->cmtd->dev.parent = &pdev->dev; ++ mtd_set_of_node(info->cmtd, node); ++ mtd_device_register(info->cmtd, NULL, 0); ++ ++ return 0; ++ ++err_remove: ++ virt_concat_remove(pdev); ++ ++ return err; ++} ++ ++static const struct of_device_id virt_concat_of_match[] = { ++ { .compatible = "mtd-concat", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, virt_concat_of_match); ++ ++static struct platform_driver virt_concat_driver = { ++ .probe = virt_concat_probe, ++ .remove = virt_concat_remove, ++ .driver = { ++ .name = "virt-mtdconcat", ++ .of_match_table = virt_concat_of_match, ++ }, ++}; ++ ++module_platform_driver(virt_concat_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Bernhard Frauendienst "); ++MODULE_DESCRIPTION("Virtual concat MTD device driver"); diff --git a/ipq806x/pending-5.4/498-mtd-mtdconcat-select-readwrite-function.patch b/ipq806x/pending-5.4/498-mtd-mtdconcat-select-readwrite-function.patch new file mode 100644 index 0000000..129bbff --- /dev/null +++ b/ipq806x/pending-5.4/498-mtd-mtdconcat-select-readwrite-function.patch @@ -0,0 +1,24 @@ +--- a/drivers/mtd/mtdconcat.c ++++ b/drivers/mtd/mtdconcat.c +@@ -642,8 +642,12 @@ struct mtd_info *mtd_concat_create(struc + concat->mtd._writev = concat_writev; + if (subdev[0]->_read_oob) + concat->mtd._read_oob = concat_read_oob; ++ else ++ concat->mtd._read = concat_read; + if (subdev[0]->_write_oob) + concat->mtd._write_oob = concat_write_oob; ++ else ++ concat->mtd._write = concat_write; + if (subdev[0]->_block_isbad) + concat->mtd._block_isbad = concat_block_isbad; + if (subdev[0]->_block_markbad) +@@ -701,8 +705,6 @@ struct mtd_info *mtd_concat_create(struc + concat->mtd.name = name; + + concat->mtd._erase = concat_erase; +- concat->mtd._read = concat_read; +- concat->mtd._write = concat_write; + concat->mtd._sync = concat_sync; + concat->mtd._lock = concat_lock; + concat->mtd._unlock = concat_unlock; diff --git a/ipq806x/pending-5.4/530-jffs2_make_lzma_available.patch b/ipq806x/pending-5.4/530-jffs2_make_lzma_available.patch new file mode 100644 index 0000000..052db7e --- /dev/null +++ b/ipq806x/pending-5.4/530-jffs2_make_lzma_available.patch @@ -0,0 +1,5180 @@ +From: Alexandros C. Couloumbis +Subject: fs: add jffs2/lzma support (not activated by default yet) + +lede-commit: c2c88d315fa0e881f8b19da07b62859b915b11b2 +Signed-off-by: Alexandros C. Couloumbis +--- + fs/jffs2/Kconfig | 9 + + fs/jffs2/Makefile | 3 + + fs/jffs2/compr.c | 6 + + fs/jffs2/compr.h | 10 +- + fs/jffs2/compr_lzma.c | 128 +++ + fs/jffs2/super.c | 33 +- + include/linux/lzma.h | 62 ++ + include/linux/lzma/LzFind.h | 115 +++ + include/linux/lzma/LzHash.h | 54 + + include/linux/lzma/LzmaDec.h | 231 +++++ + include/linux/lzma/LzmaEnc.h | 80 ++ + include/linux/lzma/Types.h | 226 +++++ + include/uapi/linux/jffs2.h | 1 + + lib/Kconfig | 6 + + lib/Makefile | 12 + + lib/lzma/LzFind.c | 761 ++++++++++++++ + lib/lzma/LzmaDec.c | 999 +++++++++++++++++++ + lib/lzma/LzmaEnc.c | 2271 ++++++++++++++++++++++++++++++++++++++++++ + lib/lzma/Makefile | 7 + + 19 files changed, 5008 insertions(+), 6 deletions(-) + create mode 100644 fs/jffs2/compr_lzma.c + create mode 100644 include/linux/lzma.h + create mode 100644 include/linux/lzma/LzFind.h + create mode 100644 include/linux/lzma/LzHash.h + create mode 100644 include/linux/lzma/LzmaDec.h + create mode 100644 include/linux/lzma/LzmaEnc.h + create mode 100644 include/linux/lzma/Types.h + create mode 100644 lib/lzma/LzFind.c + create mode 100644 lib/lzma/LzmaDec.c + create mode 100644 lib/lzma/LzmaEnc.c + create mode 100644 lib/lzma/Makefile + +--- a/fs/jffs2/Kconfig ++++ b/fs/jffs2/Kconfig +@@ -136,6 +136,15 @@ config JFFS2_LZO + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. + ++config JFFS2_LZMA ++ bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS ++ select LZMA_COMPRESS ++ select LZMA_DECOMPRESS ++ depends on JFFS2_FS ++ default n ++ help ++ JFFS2 wrapper to the LZMA C SDK ++ + config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS +--- a/fs/jffs2/Makefile ++++ b/fs/jffs2/Makefile +@@ -19,4 +19,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rub + jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o + jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o + jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o ++jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o + jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o ++ ++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma +--- a/fs/jffs2/compr.c ++++ b/fs/jffs2/compr.c +@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void) + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_init(); ++#endif + /* Setting default compression mode */ + #ifdef CONFIG_JFFS2_CMODE_NONE + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; +@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void) + int jffs2_compressors_exit(void) + { + /* Unregistering compressors */ ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_exit(); ++#endif + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); + #endif +--- a/fs/jffs2/compr.h ++++ b/fs/jffs2/compr.h +@@ -29,9 +29,9 @@ + #define JFFS2_DYNRUBIN_PRIORITY 20 + #define JFFS2_LZARI_PRIORITY 30 + #define JFFS2_RTIME_PRIORITY 50 +-#define JFFS2_ZLIB_PRIORITY 60 +-#define JFFS2_LZO_PRIORITY 80 +- ++#define JFFS2_LZMA_PRIORITY 70 ++#define JFFS2_ZLIB_PRIORITY 80 ++#define JFFS2_LZO_PRIORITY 90 + + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ + #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void); + int jffs2_lzo_init(void); + void jffs2_lzo_exit(void); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++int jffs2_lzma_init(void); ++void jffs2_lzma_exit(void); ++#endif + + #endif /* __JFFS2_COMPR_H__ */ +--- /dev/null ++++ b/fs/jffs2/compr_lzma.c +@@ -0,0 +1,128 @@ ++/* ++ * JFFS2 -- Journalling Flash File System, Version 2. ++ * ++ * For licensing information, see the file 'LICENCE' in this directory. ++ * ++ * JFFS2 wrapper to the LZMA C SDK ++ * ++ */ ++ ++#include ++#include "compr.h" ++ ++#ifdef __KERNEL__ ++ static DEFINE_MUTEX(deflate_mutex); ++#endif ++ ++CLzmaEncHandle *p; ++Byte propsEncoded[LZMA_PROPS_SIZE]; ++SizeT propsSize = sizeof(propsEncoded); ++ ++STATIC void lzma_free_workspace(void) ++{ ++ LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); ++} ++ ++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props) ++{ ++ if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) ++ { ++ PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); ++ return -ENOMEM; ++ } ++ ++ if (LzmaEnc_SetProps(p, props) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t *sourcelen, uint32_t *dstlen) ++{ ++ SizeT compress_size = (SizeT)(*dstlen); ++ int ret; ++ ++ #ifdef __KERNEL__ ++ mutex_lock(&deflate_mutex); ++ #endif ++ ++ ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen, ++ 0, NULL, &lzma_alloc, &lzma_alloc); ++ ++ #ifdef __KERNEL__ ++ mutex_unlock(&deflate_mutex); ++ #endif ++ ++ if (ret != SZ_OK) ++ return -1; ++ ++ *dstlen = (uint32_t)compress_size; ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t srclen, uint32_t destlen) ++{ ++ int ret; ++ SizeT dl = (SizeT)destlen; ++ SizeT sl = (SizeT)srclen; ++ ELzmaStatus status; ++ ++ ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, ++ propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); ++ ++ if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen) ++ return -1; ++ ++ return 0; ++} ++ ++static struct jffs2_compressor jffs2_lzma_comp = { ++ .priority = JFFS2_LZMA_PRIORITY, ++ .name = "lzma", ++ .compr = JFFS2_COMPR_LZMA, ++ .compress = &jffs2_lzma_compress, ++ .decompress = &jffs2_lzma_decompress, ++ .disabled = 0, ++}; ++ ++int INIT jffs2_lzma_init(void) ++{ ++ int ret; ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ ++ props.dictSize = LZMA_BEST_DICT(0x2000); ++ props.level = LZMA_BEST_LEVEL; ++ props.lc = LZMA_BEST_LC; ++ props.lp = LZMA_BEST_LP; ++ props.pb = LZMA_BEST_PB; ++ props.fb = LZMA_BEST_FB; ++ ++ ret = lzma_alloc_workspace(&props); ++ if (ret < 0) ++ return ret; ++ ++ ret = jffs2_register_compressor(&jffs2_lzma_comp); ++ if (ret) ++ lzma_free_workspace(); ++ ++ return ret; ++} ++ ++void jffs2_lzma_exit(void) ++{ ++ jffs2_unregister_compressor(&jffs2_lzma_comp); ++ lzma_free_workspace(); ++} +--- a/fs/jffs2/super.c ++++ b/fs/jffs2/super.c +@@ -380,14 +380,41 @@ static int __init init_jffs2_fs(void) + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + +- pr_info("version 2.2." ++ pr_info("version 2.2" + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER + " (NAND)" + #endif + #ifdef CONFIG_JFFS2_SUMMARY +- " (SUMMARY) " ++ " (SUMMARY)" + #endif +- " © 2001-2006 Red Hat, Inc.\n"); ++#ifdef CONFIG_JFFS2_ZLIB ++ " (ZLIB)" ++#endif ++#ifdef CONFIG_JFFS2_LZO ++ " (LZO)" ++#endif ++#ifdef CONFIG_JFFS2_LZMA ++ " (LZMA)" ++#endif ++#ifdef CONFIG_JFFS2_RTIME ++ " (RTIME)" ++#endif ++#ifdef CONFIG_JFFS2_RUBIN ++ " (RUBIN)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_NONE ++ " (CMODE_NONE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_PRIORITY ++ " (CMODE_PRIORITY)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_SIZE ++ " (CMODE_SIZE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO ++ " (CMODE_FAVOURLZO)" ++#endif ++ " (c) 2001-2006 Red Hat, Inc.\n"); + + jffs2_inode_cachep = kmem_cache_create("jffs2_i", + sizeof(struct jffs2_inode_info), +--- /dev/null ++++ b/include/linux/lzma.h +@@ -0,0 +1,62 @@ ++#ifndef __LZMA_H__ ++#define __LZMA_H__ ++ ++#ifdef __KERNEL__ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #define LZMA_MALLOC vmalloc ++ #define LZMA_FREE vfree ++ #define PRINT_ERROR(msg) printk(KERN_WARNING #msg) ++ #define INIT __init ++ #define STATIC static ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #ifndef PAGE_SIZE ++ extern int page_size; ++ #define PAGE_SIZE page_size ++ #endif ++ #define LZMA_MALLOC malloc ++ #define LZMA_FREE free ++ #define PRINT_ERROR(msg) fprintf(stderr, msg) ++ #define INIT ++ #define STATIC ++#endif ++ ++#include "lzma/LzmaDec.h" ++#include "lzma/LzmaEnc.h" ++ ++#define LZMA_BEST_LEVEL (9) ++#define LZMA_BEST_LC (0) ++#define LZMA_BEST_LP (0) ++#define LZMA_BEST_PB (0) ++#define LZMA_BEST_FB (273) ++ ++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) ++ ++static void *p_lzma_malloc(void *p, size_t size) ++{ ++ if (size == 0) ++ return NULL; ++ ++ return LZMA_MALLOC(size); ++} ++ ++static void p_lzma_free(void *p, void *address) ++{ ++ if (address != NULL) ++ LZMA_FREE(address); ++} ++ ++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free}; ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzFind.h +@@ -0,0 +1,115 @@ ++/* LzFind.h -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_FIND_H ++#define __LZ_FIND_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef UInt32 CLzRef; ++ ++typedef struct _CMatchFinder ++{ ++ Byte *buffer; ++ UInt32 pos; ++ UInt32 posLimit; ++ UInt32 streamPos; ++ UInt32 lenLimit; ++ ++ UInt32 cyclicBufferPos; ++ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ ++ ++ UInt32 matchMaxLen; ++ CLzRef *hash; ++ CLzRef *son; ++ UInt32 hashMask; ++ UInt32 cutValue; ++ ++ Byte *bufferBase; ++ ISeqInStream *stream; ++ int streamEndWasReached; ++ ++ UInt32 blockSize; ++ UInt32 keepSizeBefore; ++ UInt32 keepSizeAfter; ++ ++ UInt32 numHashBytes; ++ int directInput; ++ size_t directInputRem; ++ int btMode; ++ int bigHash; ++ UInt32 historySize; ++ UInt32 fixedHashSize; ++ UInt32 hashSizeSum; ++ UInt32 numSons; ++ SRes result; ++ UInt32 crc[256]; ++} CMatchFinder; ++ ++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) ++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) ++ ++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) ++ ++int MatchFinder_NeedMove(CMatchFinder *p); ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); ++void MatchFinder_MoveBlock(CMatchFinder *p); ++void MatchFinder_ReadIfRequired(CMatchFinder *p); ++ ++void MatchFinder_Construct(CMatchFinder *p); ++ ++/* Conditions: ++ historySize <= 3 GB ++ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB ++*/ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc); ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, ++ UInt32 *distances, UInt32 maxLen); ++ ++/* ++Conditions: ++ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. ++ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function ++*/ ++ ++typedef void (*Mf_Init_Func)(void *object); ++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); ++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); ++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); ++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); ++typedef void (*Mf_Skip_Func)(void *object, UInt32); ++ ++typedef struct _IMatchFinder ++{ ++ Mf_Init_Func Init; ++ Mf_GetIndexByte_Func GetIndexByte; ++ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; ++ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; ++ Mf_GetMatches_Func GetMatches; ++ Mf_Skip_Func Skip; ++} IMatchFinder; ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); ++ ++void MatchFinder_Init(CMatchFinder *p); ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzHash.h +@@ -0,0 +1,54 @@ ++/* LzHash.h -- HASH functions for LZ algorithms ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_HASH_H ++#define __LZ_HASH_H ++ ++#define kHash2Size (1 << 10) ++#define kHash3Size (1 << 16) ++#define kHash4Size (1 << 20) ++ ++#define kFix3HashSize (kHash2Size) ++#define kFix4HashSize (kHash2Size + kHash3Size) ++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) ++ ++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); ++ ++#define HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } ++ ++#define HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } ++ ++#define HASH5_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ ++ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ ++ hash4Value &= (kHash4Size - 1); } ++ ++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ ++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; ++ ++ ++#define MT_HASH2_CALC \ ++ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); ++ ++#define MT_HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } ++ ++#define MT_HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaDec.h +@@ -0,0 +1,231 @@ ++/* LzmaDec.h -- LZMA Decoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_DEC_H ++#define __LZMA_DEC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* #define _LZMA_PROB32 */ ++/* _LZMA_PROB32 can increase the speed on some CPUs, ++ but memory usage for CLzmaDec::probs will be doubled in that case */ ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++ ++/* ---------- LZMA Properties ---------- */ ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaProps ++{ ++ unsigned lc, lp, pb; ++ UInt32 dicSize; ++} CLzmaProps; ++ ++/* LzmaProps_Decode - decodes properties ++Returns: ++ SZ_OK ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); ++ ++ ++/* ---------- LZMA Decoder state ---------- */ ++ ++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. ++ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ ++ ++#define LZMA_REQUIRED_INPUT_MAX 20 ++ ++typedef struct ++{ ++ CLzmaProps prop; ++ CLzmaProb *probs; ++ Byte *dic; ++ const Byte *buf; ++ UInt32 range, code; ++ SizeT dicPos; ++ SizeT dicBufSize; ++ UInt32 processedPos; ++ UInt32 checkDicSize; ++ unsigned state; ++ UInt32 reps[4]; ++ unsigned remainLen; ++ int needFlush; ++ int needInitState; ++ UInt32 numProbs; ++ unsigned tempBufSize; ++ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; ++} CLzmaDec; ++ ++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } ++ ++void LzmaDec_Init(CLzmaDec *p); ++ ++/* There are two types of LZMA streams: ++ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. ++ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ ++ ++typedef enum ++{ ++ LZMA_FINISH_ANY, /* finish at any point */ ++ LZMA_FINISH_END /* block must be finished at the end */ ++} ELzmaFinishMode; ++ ++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! ++ ++ You must use LZMA_FINISH_END, when you know that current output buffer ++ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. ++ ++ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, ++ and output value of destLen will be less than output buffer size limit. ++ You can check status result also. ++ ++ You can use multiple checks to test data integrity after full decompression: ++ 1) Check Result and "status" variable. ++ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. ++ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. ++ You must use correct finish mode in that case. */ ++ ++typedef enum ++{ ++ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ ++ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ ++ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ ++ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ ++} ELzmaStatus; ++ ++/* ELzmaStatus is used only as output value for function call */ ++ ++ ++/* ---------- Interfaces ---------- */ ++ ++/* There are 3 levels of interfaces: ++ 1) Dictionary Interface ++ 2) Buffer Interface ++ 3) One Call Interface ++ You can select any of these interfaces, but don't mix functions from different ++ groups for same object. */ ++ ++ ++/* There are two variants to allocate state for Dictionary Interface: ++ 1) LzmaDec_Allocate / LzmaDec_Free ++ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs ++ You can use variant 2, if you set dictionary buffer manually. ++ For Buffer Interface you must always use variant 1. ++ ++LzmaDec_Allocate* can return: ++ SZ_OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); ++ ++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); ++ ++/* ---------- Dictionary Interface ---------- */ ++ ++/* You can use it, if you want to eliminate the overhead for data copying from ++ dictionary to some other external buffer. ++ You must work with CLzmaDec variables directly in this interface. ++ ++ STEPS: ++ LzmaDec_Constr() ++ LzmaDec_Allocate() ++ for (each new stream) ++ { ++ LzmaDec_Init() ++ while (it needs more decompression) ++ { ++ LzmaDec_DecodeToDic() ++ use data from CLzmaDec::dic and update CLzmaDec::dicPos ++ } ++ } ++ LzmaDec_Free() ++*/ ++ ++/* LzmaDec_DecodeToDic ++ ++ The decoding to internal dictionary buffer (CLzmaDec::dic). ++ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (dicLimit). ++ LZMA_FINISH_ANY - Decode just dicLimit bytes. ++ LZMA_FINISH_END - Stream must be finished after dicLimit. ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_NEEDS_MORE_INPUT ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++*/ ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- Buffer Interface ---------- */ ++ ++/* It's zlib-like interface. ++ See LzmaDec_DecodeToDic description for information about STEPS and return results, ++ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need ++ to work with CLzmaDec variables manually. ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++*/ ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaDecode ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). ++*/ ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaEnc.h +@@ -0,0 +1,80 @@ ++/* LzmaEnc.h -- LZMA Encoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_ENC_H ++#define __LZMA_ENC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaEncProps ++{ ++ int level; /* 0 <= level <= 9 */ ++ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version ++ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version ++ default = (1 << 24) */ ++ int lc; /* 0 <= lc <= 8, default = 3 */ ++ int lp; /* 0 <= lp <= 4, default = 0 */ ++ int pb; /* 0 <= pb <= 4, default = 2 */ ++ int algo; /* 0 - fast, 1 - normal, default = 1 */ ++ int fb; /* 5 <= fb <= 273, default = 32 */ ++ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ ++ int numHashBytes; /* 2, 3 or 4, default = 4 */ ++ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ ++ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ ++ int numThreads; /* 1 or 2, default = 2 */ ++} CLzmaEncProps; ++ ++void LzmaEncProps_Init(CLzmaEncProps *p); ++void LzmaEncProps_Normalize(CLzmaEncProps *p); ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); ++ ++ ++/* ---------- CLzmaEncHandle Interface ---------- */ ++ ++/* LzmaEnc_* functions can return the following exit codes: ++Returns: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater in props ++ SZ_ERROR_WRITE - Write callback error. ++ SZ_ERROR_PROGRESS - some break from progress callback ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++typedef void * CLzmaEncHandle; ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); ++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaEncode ++Return code: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater ++ SZ_ERROR_OUTPUT_EOF - output buffer overflow ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/Types.h +@@ -0,0 +1,226 @@ ++/* Types.h -- Basic types ++2009-11-23 : Igor Pavlov : Public domain */ ++ ++#ifndef __7Z_TYPES_H ++#define __7Z_TYPES_H ++ ++#include ++ ++#ifdef _WIN32 ++#include ++#endif ++ ++#ifndef EXTERN_C_BEGIN ++#ifdef __cplusplus ++#define EXTERN_C_BEGIN extern "C" { ++#define EXTERN_C_END } ++#else ++#define EXTERN_C_BEGIN ++#define EXTERN_C_END ++#endif ++#endif ++ ++EXTERN_C_BEGIN ++ ++#define SZ_OK 0 ++ ++#define SZ_ERROR_DATA 1 ++#define SZ_ERROR_MEM 2 ++#define SZ_ERROR_CRC 3 ++#define SZ_ERROR_UNSUPPORTED 4 ++#define SZ_ERROR_PARAM 5 ++#define SZ_ERROR_INPUT_EOF 6 ++#define SZ_ERROR_OUTPUT_EOF 7 ++#define SZ_ERROR_READ 8 ++#define SZ_ERROR_WRITE 9 ++#define SZ_ERROR_PROGRESS 10 ++#define SZ_ERROR_FAIL 11 ++#define SZ_ERROR_THREAD 12 ++ ++#define SZ_ERROR_ARCHIVE 16 ++#define SZ_ERROR_NO_ARCHIVE 17 ++ ++typedef int SRes; ++ ++#ifdef _WIN32 ++typedef DWORD WRes; ++#else ++typedef int WRes; ++#endif ++ ++#ifndef RINOK ++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } ++#endif ++ ++typedef unsigned char Byte; ++typedef short Int16; ++typedef unsigned short UInt16; ++ ++#ifdef _LZMA_UINT32_IS_ULONG ++typedef long Int32; ++typedef unsigned long UInt32; ++#else ++typedef int Int32; ++typedef unsigned int UInt32; ++#endif ++ ++#ifdef _SZ_NO_INT_64 ++ ++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. ++ NOTES: Some code will work incorrectly in that case! */ ++ ++typedef long Int64; ++typedef unsigned long UInt64; ++ ++#else ++ ++#if defined(_MSC_VER) || defined(__BORLANDC__) ++typedef __int64 Int64; ++typedef unsigned __int64 UInt64; ++#else ++typedef long long int Int64; ++typedef unsigned long long int UInt64; ++#endif ++ ++#endif ++ ++#ifdef _LZMA_NO_SYSTEM_SIZE_T ++typedef UInt32 SizeT; ++#else ++typedef size_t SizeT; ++#endif ++ ++typedef int Bool; ++#define True 1 ++#define False 0 ++ ++ ++#ifdef _WIN32 ++#define MY_STD_CALL __stdcall ++#else ++#define MY_STD_CALL ++#endif ++ ++#ifdef _MSC_VER ++ ++#if _MSC_VER >= 1300 ++#define MY_NO_INLINE __declspec(noinline) ++#else ++#define MY_NO_INLINE ++#endif ++ ++#define MY_CDECL __cdecl ++#define MY_FAST_CALL __fastcall ++ ++#else ++ ++#define MY_CDECL ++#define MY_FAST_CALL ++ ++#endif ++ ++ ++/* The following interfaces use first parameter as pointer to structure */ ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) < input(*size)) is allowed */ ++} ISeqInStream; ++ ++/* it can return SZ_ERROR_INPUT_EOF */ ++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); ++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); ++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); ++ ++typedef struct ++{ ++ size_t (*Write)(void *p, const void *buf, size_t size); ++ /* Returns: result - the number of actually written bytes. ++ (result < size) means error */ ++} ISeqOutStream; ++ ++typedef enum ++{ ++ SZ_SEEK_SET = 0, ++ SZ_SEEK_CUR = 1, ++ SZ_SEEK_END = 2 ++} ESzSeek; ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ISeekInStream; ++ ++typedef struct ++{ ++ SRes (*Look)(void *p, void **buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) > input(*size)) is not allowed ++ (output(*size) < input(*size)) is allowed */ ++ SRes (*Skip)(void *p, size_t offset); ++ /* offset must be <= output(*size) of Look */ ++ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* reads directly (without buffer). It's same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ILookInStream; ++ ++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); ++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); ++ ++/* reads via ILookInStream::Read */ ++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); ++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); ++ ++#define LookToRead_BUF_SIZE (1 << 14) ++ ++typedef struct ++{ ++ ILookInStream s; ++ ISeekInStream *realStream; ++ size_t pos; ++ size_t size; ++ Byte buf[LookToRead_BUF_SIZE]; ++} CLookToRead; ++ ++void LookToRead_CreateVTable(CLookToRead *p, int lookahead); ++void LookToRead_Init(CLookToRead *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToLook; ++ ++void SecToLook_CreateVTable(CSecToLook *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToRead; ++ ++void SecToRead_CreateVTable(CSecToRead *p); ++ ++typedef struct ++{ ++ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); ++ /* Returns: result. (result != SZ_OK) means break. ++ Value (UInt64)(Int64)-1 for size means unknown value. */ ++} ICompressProgress; ++ ++typedef struct ++{ ++ void *(*Alloc)(void *p, size_t size); ++ void (*Free)(void *p, void *address); /* address can be 0 */ ++} ISzAlloc; ++ ++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) ++#define IAlloc_Free(p, a) (p)->Free((p), a) ++ ++EXTERN_C_END ++ ++#endif +--- a/include/uapi/linux/jffs2.h ++++ b/include/uapi/linux/jffs2.h +@@ -46,6 +46,7 @@ + #define JFFS2_COMPR_DYNRUBIN 0x05 + #define JFFS2_COMPR_ZLIB 0x06 + #define JFFS2_COMPR_LZO 0x07 ++#define JFFS2_COMPR_LZMA 0x08 + /* Compatibility flags. */ + #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ + #define JFFS2_NODE_ACCURATE 0x2000 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -303,6 +303,12 @@ config ZSTD_DECOMPRESS + + source "lib/xz/Kconfig" + ++config LZMA_COMPRESS ++ tristate ++ ++config LZMA_DECOMPRESS ++ tristate ++ + # + # These all provide a common interface (hence the apparent duplication with + # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -3,6 +3,16 @@ + # Makefile for some libs needed in the kernel. + # + ++ifdef CONFIG_JFFS2_ZLIB ++ CONFIG_ZLIB_INFLATE:=y ++ CONFIG_ZLIB_DEFLATE:=y ++endif ++ ++ifdef CONFIG_JFFS2_LZMA ++ CONFIG_LZMA_DECOMPRESS:=y ++ CONFIG_LZMA_COMPRESS:=y ++endif ++ + ifdef CONFIG_FUNCTION_TRACER + ORIG_CFLAGS := $(KBUILD_CFLAGS) + KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS)) +@@ -149,6 +159,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/ + obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/ + obj-$(CONFIG_XZ_DEC) += xz/ + obj-$(CONFIG_RAID6_PQ) += raid6/ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma/ ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/ + + lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o + lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o +--- /dev/null ++++ b/lib/lzma/LzFind.c +@@ -0,0 +1,761 @@ ++/* LzFind.c -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#include ++ ++#include "LzFind.h" ++#include "LzHash.h" ++ ++#define kEmptyHashValue 0 ++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) ++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ ++#define kNormalizeMask (~(kNormalizeStepMin - 1)) ++#define kMaxHistorySize ((UInt32)3 << 30) ++ ++#define kStartMaxLen 3 ++ ++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ if (!p->directInput) ++ { ++ alloc->Free(alloc, p->bufferBase); ++ p->bufferBase = 0; ++ } ++} ++ ++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ ++ ++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) ++{ ++ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; ++ if (p->directInput) ++ { ++ p->blockSize = blockSize; ++ return 1; ++ } ++ if (p->bufferBase == 0 || p->blockSize != blockSize) ++ { ++ LzInWindow_Free(p, alloc); ++ p->blockSize = blockSize; ++ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); ++ } ++ return (p->bufferBase != 0); ++} ++ ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++ ++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++ ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++{ ++ p->posLimit -= subValue; ++ p->pos -= subValue; ++ p->streamPos -= subValue; ++} ++ ++static void MatchFinder_ReadBlock(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached || p->result != SZ_OK) ++ return; ++ if (p->directInput) ++ { ++ UInt32 curSize = 0xFFFFFFFF - p->streamPos; ++ if (curSize > p->directInputRem) ++ curSize = (UInt32)p->directInputRem; ++ p->directInputRem -= curSize; ++ p->streamPos += curSize; ++ if (p->directInputRem == 0) ++ p->streamEndWasReached = 1; ++ return; ++ } ++ for (;;) ++ { ++ Byte *dest = p->buffer + (p->streamPos - p->pos); ++ size_t size = (p->bufferBase + p->blockSize - dest); ++ if (size == 0) ++ return; ++ p->result = p->stream->Read(p->stream, dest, &size); ++ if (p->result != SZ_OK) ++ return; ++ if (size == 0) ++ { ++ p->streamEndWasReached = 1; ++ return; ++ } ++ p->streamPos += (UInt32)size; ++ if (p->streamPos - p->pos > p->keepSizeAfter) ++ return; ++ } ++} ++ ++void MatchFinder_MoveBlock(CMatchFinder *p) ++{ ++ memmove(p->bufferBase, ++ p->buffer - p->keepSizeBefore, ++ (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); ++ p->buffer = p->bufferBase + p->keepSizeBefore; ++} ++ ++int MatchFinder_NeedMove(CMatchFinder *p) ++{ ++ if (p->directInput) ++ return 0; ++ /* if (p->streamEndWasReached) return 0; */ ++ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); ++} ++ ++void MatchFinder_ReadIfRequired(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached) ++ return; ++ if (p->keepSizeAfter >= p->streamPos - p->pos) ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) ++{ ++ if (MatchFinder_NeedMove(p)) ++ MatchFinder_MoveBlock(p); ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_SetDefaultSettings(CMatchFinder *p) ++{ ++ p->cutValue = 32; ++ p->btMode = 1; ++ p->numHashBytes = 4; ++ p->bigHash = 0; ++} ++ ++#define kCrcPoly 0xEDB88320 ++ ++void MatchFinder_Construct(CMatchFinder *p) ++{ ++ UInt32 i; ++ p->bufferBase = 0; ++ p->directInput = 0; ++ p->hash = 0; ++ MatchFinder_SetDefaultSettings(p); ++ ++ for (i = 0; i < 256; i++) ++ { ++ UInt32 r = i; ++ int j; ++ for (j = 0; j < 8; j++) ++ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); ++ p->crc[i] = r; ++ } ++} ++ ++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->hash); ++ p->hash = 0; ++} ++ ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ LzInWindow_Free(p, alloc); ++} ++ ++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) ++{ ++ size_t sizeInBytes = (size_t)num * sizeof(CLzRef); ++ if (sizeInBytes / sizeof(CLzRef) != num) ++ return 0; ++ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); ++} ++ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc) ++{ ++ UInt32 sizeReserv; ++ if (historySize > kMaxHistorySize) ++ { ++ MatchFinder_Free(p, alloc); ++ return 0; ++ } ++ sizeReserv = historySize >> 1; ++ if (historySize > ((UInt32)2 << 30)) ++ sizeReserv = historySize >> 2; ++ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); ++ ++ p->keepSizeBefore = historySize + keepAddBufferBefore + 1; ++ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; ++ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ ++ if (LzInWindow_Create(p, sizeReserv, alloc)) ++ { ++ UInt32 newCyclicBufferSize = historySize + 1; ++ UInt32 hs; ++ p->matchMaxLen = matchMaxLen; ++ { ++ p->fixedHashSize = 0; ++ if (p->numHashBytes == 2) ++ hs = (1 << 16) - 1; ++ else ++ { ++ hs = historySize - 1; ++ hs |= (hs >> 1); ++ hs |= (hs >> 2); ++ hs |= (hs >> 4); ++ hs |= (hs >> 8); ++ hs >>= 1; ++ hs |= 0xFFFF; /* don't change it! It's required for Deflate */ ++ if (hs > (1 << 24)) ++ { ++ if (p->numHashBytes == 3) ++ hs = (1 << 24) - 1; ++ else ++ hs >>= 1; ++ } ++ } ++ p->hashMask = hs; ++ hs++; ++ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; ++ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; ++ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; ++ hs += p->fixedHashSize; ++ } ++ ++ { ++ UInt32 prevSize = p->hashSizeSum + p->numSons; ++ UInt32 newSize; ++ p->historySize = historySize; ++ p->hashSizeSum = hs; ++ p->cyclicBufferSize = newCyclicBufferSize; ++ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); ++ newSize = p->hashSizeSum + p->numSons; ++ if (p->hash != 0 && prevSize == newSize) ++ return 1; ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ p->hash = AllocRefs(newSize, alloc); ++ if (p->hash != 0) ++ { ++ p->son = p->hash + p->hashSizeSum; ++ return 1; ++ } ++ } ++ } ++ MatchFinder_Free(p, alloc); ++ return 0; ++} ++ ++static void MatchFinder_SetLimits(CMatchFinder *p) ++{ ++ UInt32 limit = kMaxValForNormalize - p->pos; ++ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; ++ if (limit2 < limit) ++ limit = limit2; ++ limit2 = p->streamPos - p->pos; ++ if (limit2 <= p->keepSizeAfter) ++ { ++ if (limit2 > 0) ++ limit2 = 1; ++ } ++ else ++ limit2 -= p->keepSizeAfter; ++ if (limit2 < limit) ++ limit = limit2; ++ { ++ UInt32 lenLimit = p->streamPos - p->pos; ++ if (lenLimit > p->matchMaxLen) ++ lenLimit = p->matchMaxLen; ++ p->lenLimit = lenLimit; ++ } ++ p->posLimit = p->pos + limit; ++} ++ ++void MatchFinder_Init(CMatchFinder *p) ++{ ++ UInt32 i; ++ for (i = 0; i < p->hashSizeSum; i++) ++ p->hash[i] = kEmptyHashValue; ++ p->cyclicBufferPos = 0; ++ p->buffer = p->bufferBase; ++ p->pos = p->streamPos = p->cyclicBufferSize; ++ p->result = SZ_OK; ++ p->streamEndWasReached = 0; ++ MatchFinder_ReadBlock(p); ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) ++{ ++ return (p->pos - p->historySize - 1) & kNormalizeMask; ++} ++ ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++{ ++ UInt32 i; ++ for (i = 0; i < numItems; i++) ++ { ++ UInt32 value = items[i]; ++ if (value <= subValue) ++ value = kEmptyHashValue; ++ else ++ value -= subValue; ++ items[i] = value; ++ } ++} ++ ++static void MatchFinder_Normalize(CMatchFinder *p) ++{ ++ UInt32 subValue = MatchFinder_GetSubValue(p); ++ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); ++ MatchFinder_ReduceOffsets(p, subValue); ++} ++ ++static void MatchFinder_CheckLimits(CMatchFinder *p) ++{ ++ if (p->pos == kMaxValForNormalize) ++ MatchFinder_Normalize(p); ++ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) ++ MatchFinder_CheckAndMoveAndRead(p); ++ if (p->cyclicBufferPos == p->cyclicBufferSize) ++ p->cyclicBufferPos = 0; ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ son[_cyclicBufferPos] = curMatch; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ return distances; ++ { ++ const Byte *pb = cur - delta; ++ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; ++ if (pb[maxLen] == cur[maxLen] && *pb == *cur) ++ { ++ UInt32 len = 0; ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ return distances; ++ } ++ } ++ } ++ } ++} ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return distances; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ if (++len != lenLimit && pb[len] == cur[len]) ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return distances; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ { ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++#define MOVE_POS \ ++ ++p->cyclicBufferPos; \ ++ p->buffer++; \ ++ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); ++ ++#define MOVE_POS_RET MOVE_POS return offset; ++ ++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } ++ ++#define GET_MATCHES_HEADER2(minLen, ret_op) \ ++ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ ++ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ ++ cur = p->buffer; ++ ++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) ++#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) ++ ++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue ++ ++#define GET_MATCHES_FOOTER(offset, maxLen) \ ++ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ ++ distances + offset, maxLen) - distances); MOVE_POS_RET; ++ ++#define SKIP_FOOTER \ ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; ++ ++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 1) ++} ++ ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 2) ++} ++ ++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, delta2, maxLen, offset; ++ GET_MATCHES_HEADER(3) ++ ++ HASH3_CALC; ++ ++ delta2 = p->pos - p->hash[hash2Value]; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ ++ ++ maxLen = 2; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[0] = maxLen; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances + offset, maxLen) - (distances)); ++ MOVE_POS_RET ++} ++ ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances, 2) - (distances)); ++ MOVE_POS_RET ++} ++ ++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value; ++ SKIP_HEADER(3) ++ HASH3_CALC; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = p->pos; ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) ++{ ++ vTable->Init = (Mf_Init_Func)MatchFinder_Init; ++ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; ++ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; ++ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; ++ if (!p->btMode) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 2) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 3) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; ++ } ++ else ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++ } ++} +--- /dev/null ++++ b/lib/lzma/LzmaDec.c +@@ -0,0 +1,999 @@ ++/* LzmaDec.c -- LZMA Decoder ++2009-09-20 : Igor Pavlov : Public domain */ ++ ++#include "LzmaDec.h" ++ ++#include ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_INIT_SIZE 5 ++ ++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); ++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); ++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ ++ { UPDATE_0(p); i = (i + i); A0; } else \ ++ { UPDATE_1(p); i = (i + i) + 1; A1; } ++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) ++ ++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } ++#define TREE_DECODE(probs, limit, i) \ ++ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } ++ ++/* #define _LZMA_SIZE_OPT */ ++ ++#ifdef _LZMA_SIZE_OPT ++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) ++#else ++#define TREE_6_DECODE(probs, i) \ ++ { i = 1; \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ i -= 0x40; } ++#endif ++ ++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0_CHECK range = bound; ++#define UPDATE_1_CHECK range -= bound; code -= bound; ++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ ++ { UPDATE_0_CHECK; i = (i + i); A0; } else \ ++ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } ++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) ++#define TREE_DECODE_CHECK(probs, limit, i) \ ++ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++#define LZMA_DIC_MIN (1 << 12) ++ ++/* First LZMA-symbol is always decoded. ++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization ++Out: ++ Result: ++ SZ_OK - OK ++ SZ_ERROR_DATA - Error ++ p->remainLen: ++ < kMatchSpecLenStart : normal remain ++ = kMatchSpecLenStart : finished ++ = kMatchSpecLenStart + 1 : Flush marker ++ = kMatchSpecLenStart + 2 : State Init Marker ++*/ ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ CLzmaProb *probs = p->probs; ++ ++ unsigned state = p->state; ++ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; ++ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; ++ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; ++ unsigned lc = p->prop.lc; ++ ++ Byte *dic = p->dic; ++ SizeT dicBufSize = p->dicBufSize; ++ SizeT dicPos = p->dicPos; ++ ++ UInt32 processedPos = p->processedPos; ++ UInt32 checkDicSize = p->checkDicSize; ++ unsigned len = 0; ++ ++ const Byte *buf = p->buf; ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ ++ do ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = processedPos & pbMask; ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ unsigned symbol; ++ UPDATE_0(prob); ++ prob = probs + Literal; ++ if (checkDicSize != 0 || processedPos != 0) ++ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + ++ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ state -= (state < 4) ? state : 3; ++ symbol = 1; ++ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ state -= (state < 10) ? 3 : 6; ++ symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ dic[dicPos++] = (Byte)symbol; ++ processedPos++; ++ continue; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRep + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ state += kNumStates; ++ prob = probs + LenCoder; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ if (checkDicSize == 0 && processedPos == 0) ++ return SZ_ERROR_DATA; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ processedPos++; ++ state = state < kNumLitStates ? 9 : 11; ++ continue; ++ } ++ UPDATE_1(prob); ++ } ++ else ++ { ++ UInt32 distance; ++ UPDATE_1(prob); ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = (1 << kLenNumLowBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenChoice2; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = (1 << kLenNumMidBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = (1 << kLenNumHighBits); ++ } ++ } ++ TREE_DECODE(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state >= kNumStates) ++ { ++ UInt32 distance; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); ++ TREE_6_DECODE(prob, distance); ++ if (distance >= kStartPosModelIndex) ++ { ++ unsigned posSlot = (unsigned)distance; ++ int numDirectBits = (int)(((distance >> 1) - 1)); ++ distance = (2 | (distance & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ distance <<= numDirectBits; ++ prob = probs + SpecPos + distance - posSlot - 1; ++ { ++ UInt32 mask = 1; ++ unsigned i = 1; ++ do ++ { ++ GET_BIT2(prob + i, i, ; , distance |= mask); ++ mask <<= 1; ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE ++ range >>= 1; ++ ++ { ++ UInt32 t; ++ code -= range; ++ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ ++ distance = (distance << 1) + (t + 1); ++ code += range & t; ++ } ++ /* ++ distance <<= 1; ++ if (code >= range) ++ { ++ code -= range; ++ distance |= 1; ++ } ++ */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ distance <<= kNumAlignBits; ++ { ++ unsigned i = 1; ++ GET_BIT2(prob + i, i, ; , distance |= 1); ++ GET_BIT2(prob + i, i, ; , distance |= 2); ++ GET_BIT2(prob + i, i, ; , distance |= 4); ++ GET_BIT2(prob + i, i, ; , distance |= 8); ++ } ++ if (distance == (UInt32)0xFFFFFFFF) ++ { ++ len += kMatchSpecLenStart; ++ state -= kNumStates; ++ break; ++ } ++ } ++ } ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ rep0 = distance + 1; ++ if (checkDicSize == 0) ++ { ++ if (distance >= processedPos) ++ return SZ_ERROR_DATA; ++ } ++ else if (distance >= checkDicSize) ++ return SZ_ERROR_DATA; ++ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; ++ } ++ ++ len += kMatchMinLen; ++ ++ if (limit == dicPos) ++ return SZ_ERROR_DATA; ++ { ++ SizeT rem = limit - dicPos; ++ unsigned curLen = ((rem < len) ? (unsigned)rem : len); ++ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); ++ ++ processedPos += curLen; ++ ++ len -= curLen; ++ if (pos + curLen <= dicBufSize) ++ { ++ Byte *dest = dic + dicPos; ++ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; ++ const Byte *lim = dest + curLen; ++ dicPos += curLen; ++ do ++ *(dest) = (Byte)*(dest + src); ++ while (++dest != lim); ++ } ++ else ++ { ++ do ++ { ++ dic[dicPos++] = dic[pos]; ++ if (++pos == dicBufSize) ++ pos = 0; ++ } ++ while (--curLen != 0); ++ } ++ } ++ } ++ } ++ while (dicPos < limit && buf < bufLimit); ++ NORMALIZE; ++ p->buf = buf; ++ p->range = range; ++ p->code = code; ++ p->remainLen = len; ++ p->dicPos = dicPos; ++ p->processedPos = processedPos; ++ p->reps[0] = rep0; ++ p->reps[1] = rep1; ++ p->reps[2] = rep2; ++ p->reps[3] = rep3; ++ p->state = state; ++ ++ return SZ_OK; ++} ++ ++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) ++{ ++ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) ++ { ++ Byte *dic = p->dic; ++ SizeT dicPos = p->dicPos; ++ SizeT dicBufSize = p->dicBufSize; ++ unsigned len = p->remainLen; ++ UInt32 rep0 = p->reps[0]; ++ if (limit - dicPos < len) ++ len = (unsigned)(limit - dicPos); ++ ++ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) ++ p->checkDicSize = p->prop.dicSize; ++ ++ p->processedPos += len; ++ p->remainLen -= len; ++ while (len-- != 0) ++ { ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ } ++ p->dicPos = dicPos; ++ } ++} ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ do ++ { ++ SizeT limit2 = limit; ++ if (p->checkDicSize == 0) ++ { ++ UInt32 rem = p->prop.dicSize - p->processedPos; ++ if (limit - p->dicPos > rem) ++ limit2 = p->dicPos + rem; ++ } ++ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); ++ if (p->processedPos >= p->prop.dicSize) ++ p->checkDicSize = p->prop.dicSize; ++ LzmaDec_WriteRem(p, limit); ++ } ++ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); ++ ++ if (p->remainLen > kMatchSpecLenStart) ++ { ++ p->remainLen = kMatchSpecLenStart; ++ } ++ return 0; ++} ++ ++typedef enum ++{ ++ DUMMY_ERROR, /* unexpected end of input stream */ ++ DUMMY_LIT, ++ DUMMY_MATCH, ++ DUMMY_REP ++} ELzmaDummy; ++ ++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) ++{ ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ const Byte *bufLimit = buf + inSize; ++ CLzmaProb *probs = p->probs; ++ unsigned state = p->state; ++ ELzmaDummy res; ++ ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK ++ ++ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ ++ ++ prob = probs + Literal; ++ if (p->checkDicSize != 0 || p->processedPos != 0) ++ prob += (LZMA_LIT_SIZE * ++ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + ++ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ unsigned symbol = 1; ++ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ++ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ unsigned symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ res = DUMMY_LIT; ++ } ++ else ++ { ++ unsigned len; ++ UPDATE_1_CHECK; ++ ++ prob = probs + IsRep + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ state = 0; ++ prob = probs + LenCoder; ++ res = DUMMY_MATCH; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ res = DUMMY_REP; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ NORMALIZE_CHECK; ++ return DUMMY_REP; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ } ++ state = kNumStates; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = 1 << kLenNumLowBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenChoice2; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = 1 << kLenNumMidBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = 1 << kLenNumHighBits; ++ } ++ } ++ TREE_DECODE_CHECK(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ unsigned posSlot; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ ++ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ ++ ++ if (posSlot < kEndPosModelIndex) ++ { ++ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE_CHECK ++ range >>= 1; ++ code -= range & (((code - range) >> 31) - 1); ++ /* if (code >= range) code -= range; */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ unsigned i = 1; ++ do ++ { ++ GET_BIT_CHECK(prob + i, i); ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ } ++ } ++ } ++ NORMALIZE_CHECK; ++ return res; ++} ++ ++ ++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) ++{ ++ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); ++ p->range = 0xFFFFFFFF; ++ p->needFlush = 0; ++} ++ ++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++{ ++ p->needFlush = 1; ++ p->remainLen = 0; ++ p->tempBufSize = 0; ++ ++ if (initDic) ++ { ++ p->processedPos = 0; ++ p->checkDicSize = 0; ++ p->needInitState = 1; ++ } ++ if (initState) ++ p->needInitState = 1; ++} ++ ++void LzmaDec_Init(CLzmaDec *p) ++{ ++ p->dicPos = 0; ++ LzmaDec_InitDicAndState(p, True, True); ++} ++ ++static void LzmaDec_InitStateReal(CLzmaDec *p) ++{ ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); ++ UInt32 i; ++ CLzmaProb *probs = p->probs; ++ for (i = 0; i < numProbs; i++) ++ probs[i] = kBitModelTotal >> 1; ++ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; ++ p->state = 0; ++ p->needInitState = 0; ++} ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++ ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT inSize = *srcLen; ++ (*srcLen) = 0; ++ LzmaDec_WriteRem(p, dicLimit); ++ ++ *status = LZMA_STATUS_NOT_SPECIFIED; ++ ++ while (p->remainLen != kMatchSpecLenStart) ++ { ++ int checkEndMarkNow; ++ ++ if (p->needFlush != 0) ++ { ++ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) ++ p->tempBuf[p->tempBufSize++] = *src++; ++ if (p->tempBufSize < RC_INIT_SIZE) ++ { ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (p->tempBuf[0] != 0) ++ return SZ_ERROR_DATA; ++ ++ LzmaDec_InitRc(p, p->tempBuf); ++ p->tempBufSize = 0; ++ } ++ ++ checkEndMarkNow = 0; ++ if (p->dicPos >= dicLimit) ++ { ++ if (p->remainLen == 0 && p->code == 0) ++ { ++ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; ++ return SZ_OK; ++ } ++ if (finishMode == LZMA_FINISH_ANY) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_OK; ++ } ++ if (p->remainLen != 0) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ checkEndMarkNow = 1; ++ } ++ ++ if (p->needInitState) ++ LzmaDec_InitStateReal(p); ++ ++ if (p->tempBufSize == 0) ++ { ++ SizeT processed; ++ const Byte *bufLimit; ++ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, src, inSize); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ memcpy(p->tempBuf, src, inSize); ++ p->tempBufSize = (unsigned)inSize; ++ (*srcLen) += inSize; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ bufLimit = src; ++ } ++ else ++ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; ++ p->buf = src; ++ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) ++ return SZ_ERROR_DATA; ++ processed = (SizeT)(p->buf - src); ++ (*srcLen) += processed; ++ src += processed; ++ inSize -= processed; ++ } ++ else ++ { ++ unsigned rem = p->tempBufSize, lookAhead = 0; ++ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) ++ p->tempBuf[rem++] = src[lookAhead++]; ++ p->tempBufSize = rem; ++ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ (*srcLen) += lookAhead; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ } ++ p->buf = p->tempBuf; ++ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) ++ return SZ_ERROR_DATA; ++ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); ++ (*srcLen) += lookAhead; ++ src += lookAhead; ++ inSize -= lookAhead; ++ p->tempBufSize = 0; ++ } ++ } ++ if (p->code == 0) ++ *status = LZMA_STATUS_FINISHED_WITH_MARK; ++ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; ++} ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT outSize = *destLen; ++ SizeT inSize = *srcLen; ++ *srcLen = *destLen = 0; ++ for (;;) ++ { ++ SizeT inSizeCur = inSize, outSizeCur, dicPos; ++ ELzmaFinishMode curFinishMode; ++ SRes res; ++ if (p->dicPos == p->dicBufSize) ++ p->dicPos = 0; ++ dicPos = p->dicPos; ++ if (outSize > p->dicBufSize - dicPos) ++ { ++ outSizeCur = p->dicBufSize; ++ curFinishMode = LZMA_FINISH_ANY; ++ } ++ else ++ { ++ outSizeCur = dicPos + outSize; ++ curFinishMode = finishMode; ++ } ++ ++ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); ++ src += inSizeCur; ++ inSize -= inSizeCur; ++ *srcLen += inSizeCur; ++ outSizeCur = p->dicPos - dicPos; ++ memcpy(dest, p->dic + dicPos, outSizeCur); ++ dest += outSizeCur; ++ outSize -= outSizeCur; ++ *destLen += outSizeCur; ++ if (res != 0) ++ return res; ++ if (outSizeCur == 0 || outSize == 0) ++ return SZ_OK; ++ } ++} ++ ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->probs); ++ p->probs = 0; ++} ++ ++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->dic); ++ p->dic = 0; ++} ++ ++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ LzmaDec_FreeProbs(p, alloc); ++ LzmaDec_FreeDict(p, alloc); ++} ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++{ ++ UInt32 dicSize; ++ Byte d; ++ ++ if (size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_UNSUPPORTED; ++ else ++ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); ++ ++ if (dicSize < LZMA_DIC_MIN) ++ dicSize = LZMA_DIC_MIN; ++ p->dicSize = dicSize; ++ ++ d = data[0]; ++ if (d >= (9 * 5 * 5)) ++ return SZ_ERROR_UNSUPPORTED; ++ ++ p->lc = d % 9; ++ d /= 9; ++ p->pb = d / 5; ++ p->lp = d % 5; ++ ++ return SZ_OK; ++} ++ ++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) ++{ ++ UInt32 numProbs = LzmaProps_GetNumProbs(propNew); ++ if (p->probs == 0 || numProbs != p->numProbs) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); ++ p->numProbs = numProbs; ++ if (p->probs == 0) ++ return SZ_ERROR_MEM; ++ } ++ return SZ_OK; ++} ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ SizeT dicBufSize; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ dicBufSize = propNew.dicSize; ++ if (p->dic == 0 || dicBufSize != p->dicBufSize) ++ { ++ LzmaDec_FreeDict(p, alloc); ++ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); ++ if (p->dic == 0) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ } ++ p->dicBufSize = dicBufSize; ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc) ++{ ++ CLzmaDec p; ++ SRes res; ++ SizeT inSize = *srcLen; ++ SizeT outSize = *destLen; ++ *srcLen = *destLen = 0; ++ if (inSize < RC_INIT_SIZE) ++ return SZ_ERROR_INPUT_EOF; ++ ++ LzmaDec_Construct(&p); ++ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); ++ if (res != 0) ++ return res; ++ p.dic = dest; ++ p.dicBufSize = outSize; ++ ++ LzmaDec_Init(&p); ++ ++ *srcLen = inSize; ++ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); ++ ++ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) ++ res = SZ_ERROR_INPUT_EOF; ++ ++ (*destLen) = p.dicPos; ++ LzmaDec_FreeProbs(&p, alloc); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/LzmaEnc.c +@@ -0,0 +1,2271 @@ ++/* LzmaEnc.c -- LZMA Encoder ++2009-11-24 : Igor Pavlov : Public domain */ ++ ++#include ++ ++/* #define SHOW_STAT */ ++/* #define SHOW_STAT2 */ ++ ++#if defined(SHOW_STAT) || defined(SHOW_STAT2) ++#include ++#endif ++ ++#include "LzmaEnc.h" ++ ++/* disable MT */ ++#define _7ZIP_ST ++ ++#include "LzFind.h" ++#ifndef _7ZIP_ST ++#include "LzFindMt.h" ++#endif ++ ++#ifdef SHOW_STAT ++static int ttt = 0; ++#endif ++ ++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) ++ ++#define kBlockSize (9 << 10) ++#define kUnpackBlockSize (1 << 18) ++#define kMatchArraySize (1 << 21) ++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) ++ ++#define kNumMaxDirectBits (31) ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++#define kProbInitValue (kBitModelTotal >> 1) ++ ++#define kNumMoveReducingBits 4 ++#define kNumBitPriceShiftBits 4 ++#define kBitPrice (1 << kNumBitPriceShiftBits) ++ ++void LzmaEncProps_Init(CLzmaEncProps *p) ++{ ++ p->level = 5; ++ p->dictSize = p->mc = 0; ++ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; ++ p->writeEndMark = 0; ++} ++ ++void LzmaEncProps_Normalize(CLzmaEncProps *p) ++{ ++ int level = p->level; ++ if (level < 0) level = 5; ++ p->level = level; ++ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); ++ if (p->lc < 0) p->lc = 3; ++ if (p->lp < 0) p->lp = 0; ++ if (p->pb < 0) p->pb = 2; ++ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); ++ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); ++ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); ++ if (p->numHashBytes < 0) p->numHashBytes = 4; ++ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); ++ if (p->numThreads < 0) ++ p->numThreads = ++ #ifndef _7ZIP_ST ++ ((p->btMode && p->algo) ? 2 : 1); ++ #else ++ 1; ++ #endif ++} ++ ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++{ ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ return props.dictSize; ++} ++ ++/* #define LZMA_LOG_BSR */ ++/* Define it for Intel's CPU */ ++ ++ ++#ifdef LZMA_LOG_BSR ++ ++#define kDicLogSizeMaxCompress 30 ++ ++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } ++ ++UInt32 GetPosSlot1(UInt32 pos) ++{ ++ UInt32 res; ++ BSR2_RET(pos, res); ++ return res; ++} ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } ++ ++#else ++ ++#define kNumLogBits (9 + (int)sizeof(size_t) / 2) ++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) ++ ++void LzmaEnc_FastPosInit(Byte *g_FastPos) ++{ ++ int c = 2, slotFast; ++ g_FastPos[0] = 0; ++ g_FastPos[1] = 1; ++ ++ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) ++ { ++ UInt32 k = (1 << ((slotFast >> 1) - 1)); ++ UInt32 j; ++ for (j = 0; j < k; j++, c++) ++ g_FastPos[c] = (Byte)slotFast; ++ } ++} ++ ++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ ++ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ ++ res = p->g_FastPos[pos >> i] + (i * 2); } ++/* ++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ ++ p->g_FastPos[pos >> 6] + 12 : \ ++ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } ++*/ ++ ++#define GetPosSlot1(pos) p->g_FastPos[pos] ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } ++ ++#endif ++ ++ ++#define LZMA_NUM_REPS 4 ++ ++typedef unsigned CState; ++ ++typedef struct ++{ ++ UInt32 price; ++ ++ CState state; ++ int prev1IsChar; ++ int prev2; ++ ++ UInt32 posPrev2; ++ UInt32 backPrev2; ++ ++ UInt32 posPrev; ++ UInt32 backPrev; ++ UInt32 backs[LZMA_NUM_REPS]; ++} COptimal; ++ ++#define kNumOpts (1 << 12) ++ ++#define kNumLenToPosStates 4 ++#define kNumPosSlotBits 6 ++#define kDicLogSizeMin 0 ++#define kDicLogSizeMax 32 ++#define kDistTableSizeMax (kDicLogSizeMax * 2) ++ ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++#define kAlignMask (kAlignTableSize - 1) ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) ++ ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++#define LZMA_PB_MAX 4 ++#define LZMA_LC_MAX 8 ++#define LZMA_LP_MAX 4 ++ ++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) ++ ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define LZMA_MATCH_LEN_MIN 2 ++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) ++ ++#define kNumStates 12 ++ ++typedef struct ++{ ++ CLzmaProb choice; ++ CLzmaProb choice2; ++ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; ++ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; ++ CLzmaProb high[kLenNumHighSymbols]; ++} CLenEnc; ++ ++typedef struct ++{ ++ CLenEnc p; ++ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; ++ UInt32 tableSize; ++ UInt32 counters[LZMA_NUM_PB_STATES_MAX]; ++} CLenPriceEnc; ++ ++typedef struct ++{ ++ UInt32 range; ++ Byte cache; ++ UInt64 low; ++ UInt64 cacheSize; ++ Byte *buf; ++ Byte *bufLim; ++ Byte *bufBase; ++ ISeqOutStream *outStream; ++ UInt64 processed; ++ SRes res; ++} CRangeEnc; ++ ++typedef struct ++{ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++} CSaveState; ++ ++typedef struct ++{ ++ IMatchFinder matchFinder; ++ void *matchFinderObj; ++ ++ #ifndef _7ZIP_ST ++ Bool mtMode; ++ CMatchFinderMt matchFinderMt; ++ #endif ++ ++ CMatchFinder matchFinderBase; ++ ++ #ifndef _7ZIP_ST ++ Byte pad[128]; ++ #endif ++ ++ UInt32 optimumEndIndex; ++ UInt32 optimumCurrentIndex; ++ ++ UInt32 longestMatchLength; ++ UInt32 numPairs; ++ UInt32 numAvail; ++ COptimal opt[kNumOpts]; ++ ++ #ifndef LZMA_LOG_BSR ++ Byte g_FastPos[1 << kNumLogBits]; ++ #endif ++ ++ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; ++ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; ++ UInt32 numFastBytes; ++ UInt32 additionalOffset; ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++ ++ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; ++ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; ++ UInt32 alignPrices[kAlignTableSize]; ++ UInt32 alignPriceCount; ++ ++ UInt32 distTableSize; ++ ++ unsigned lc, lp, pb; ++ unsigned lpMask, pbMask; ++ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ unsigned lclp; ++ ++ Bool fastMode; ++ ++ CRangeEnc rc; ++ ++ Bool writeEndMark; ++ UInt64 nowPos64; ++ UInt32 matchPriceCount; ++ Bool finished; ++ Bool multiThread; ++ ++ SRes result; ++ UInt32 dictSize; ++ UInt32 matchFinderCycles; ++ ++ int needInit; ++ ++ CSaveState saveState; ++} CLzmaEnc; ++ ++void LzmaEnc_SaveState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CSaveState *dest = &p->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); ++} ++ ++void LzmaEnc_RestoreState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *dest = (CLzmaEnc *)pp; ++ const CSaveState *p = &dest->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); ++} ++ ++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ ++ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || ++ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) ++ return SZ_ERROR_PARAM; ++ p->dictSize = props.dictSize; ++ p->matchFinderCycles = props.mc; ++ { ++ unsigned fb = props.fb; ++ if (fb < 5) ++ fb = 5; ++ if (fb > LZMA_MATCH_LEN_MAX) ++ fb = LZMA_MATCH_LEN_MAX; ++ p->numFastBytes = fb; ++ } ++ p->lc = props.lc; ++ p->lp = props.lp; ++ p->pb = props.pb; ++ p->fastMode = (props.algo == 0); ++ p->matchFinderBase.btMode = props.btMode; ++ { ++ UInt32 numHashBytes = 4; ++ if (props.btMode) ++ { ++ if (props.numHashBytes < 2) ++ numHashBytes = 2; ++ else if (props.numHashBytes < 4) ++ numHashBytes = props.numHashBytes; ++ } ++ p->matchFinderBase.numHashBytes = numHashBytes; ++ } ++ ++ p->matchFinderBase.cutValue = props.mc; ++ ++ p->writeEndMark = props.writeEndMark; ++ ++ #ifndef _7ZIP_ST ++ /* ++ if (newMultiThread != _multiThread) ++ { ++ ReleaseMatchFinder(); ++ _multiThread = newMultiThread; ++ } ++ */ ++ p->multiThread = (props.numThreads > 1); ++ #endif ++ ++ return SZ_OK; ++} ++ ++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; ++static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; ++static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; ++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; ++ ++#define IsCharState(s) ((s) < 7) ++ ++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) ++ ++#define kInfinityPrice (1 << 30) ++ ++static void RangeEnc_Construct(CRangeEnc *p) ++{ ++ p->outStream = 0; ++ p->bufBase = 0; ++} ++ ++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) ++ ++#define RC_BUF_SIZE (1 << 16) ++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ if (p->bufBase == 0) ++ { ++ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); ++ if (p->bufBase == 0) ++ return 0; ++ p->bufLim = p->bufBase + RC_BUF_SIZE; ++ } ++ return 1; ++} ++ ++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->bufBase); ++ p->bufBase = 0; ++} ++ ++static void RangeEnc_Init(CRangeEnc *p) ++{ ++ /* Stream.Init(); */ ++ p->low = 0; ++ p->range = 0xFFFFFFFF; ++ p->cacheSize = 1; ++ p->cache = 0; ++ ++ p->buf = p->bufBase; ++ ++ p->processed = 0; ++ p->res = SZ_OK; ++} ++ ++static void RangeEnc_FlushStream(CRangeEnc *p) ++{ ++ size_t num; ++ if (p->res != SZ_OK) ++ return; ++ num = p->buf - p->bufBase; ++ if (num != p->outStream->Write(p->outStream, p->bufBase, num)) ++ p->res = SZ_ERROR_WRITE; ++ p->processed += num; ++ p->buf = p->bufBase; ++} ++ ++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) ++{ ++ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) ++ { ++ Byte temp = p->cache; ++ do ++ { ++ Byte *buf = p->buf; ++ *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); ++ p->buf = buf; ++ if (buf == p->bufLim) ++ RangeEnc_FlushStream(p); ++ temp = 0xFF; ++ } ++ while (--p->cacheSize != 0); ++ p->cache = (Byte)((UInt32)p->low >> 24); ++ } ++ p->cacheSize++; ++ p->low = (UInt32)p->low << 8; ++} ++ ++static void RangeEnc_FlushData(CRangeEnc *p) ++{ ++ int i; ++ for (i = 0; i < 5; i++) ++ RangeEnc_ShiftLow(p); ++} ++ ++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) ++{ ++ do ++ { ++ p->range >>= 1; ++ p->low += p->range & (0 - ((value >> --numBits) & 1)); ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++ } ++ while (numBits != 0); ++} ++ ++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) ++{ ++ UInt32 ttt = *prob; ++ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; ++ if (symbol == 0) ++ { ++ p->range = newBound; ++ ttt += (kBitModelTotal - ttt) >> kNumMoveBits; ++ } ++ else ++ { ++ p->low += newBound; ++ p->range -= newBound; ++ ttt -= ttt >> kNumMoveBits; ++ } ++ *prob = (CLzmaProb)ttt; ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++} ++ ++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) ++{ ++ symbol |= 0x100; ++ do ++ { ++ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) ++{ ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++} ++ ++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++{ ++ UInt32 i; ++ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) ++ { ++ const int kCyclesBits = kNumBitPriceShiftBits; ++ UInt32 w = i; ++ UInt32 bitCount = 0; ++ int j; ++ for (j = 0; j < kCyclesBits; j++) ++ { ++ w = w * w; ++ bitCount <<= 1; ++ while (w >= ((UInt32)1 << 16)) ++ { ++ w >>= 1; ++ bitCount++; ++ } ++ } ++ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); ++ } ++} ++ ++ ++#define GET_PRICE(prob, symbol) \ ++ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICEa(prob, symbol) \ ++ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= 0x100; ++ do ++ { ++ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++ ++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0;) ++ { ++ UInt32 bit; ++ i--; ++ bit = (symbol >> i) & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ } ++} ++ ++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = 0; i < numBitLevels; i++) ++ { ++ UInt32 bit = symbol & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ symbol >>= 1; ++ } ++} ++ ++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= (1 << numBitLevels); ++ while (symbol != 1) ++ { ++ price += GET_PRICEa(probs[symbol >> 1], symbol & 1); ++ symbol >>= 1; ++ } ++ return price; ++} ++ ++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0; i--) ++ { ++ UInt32 bit = symbol & 1; ++ symbol >>= 1; ++ price += GET_PRICEa(probs[m], bit); ++ m = (m << 1) | bit; ++ } ++ return price; ++} ++ ++ ++static void LenEnc_Init(CLenEnc *p) ++{ ++ unsigned i; ++ p->choice = p->choice2 = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) ++ p->low[i] = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) ++ p->mid[i] = kProbInitValue; ++ for (i = 0; i < kLenNumHighSymbols; i++) ++ p->high[i] = kProbInitValue; ++} ++ ++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) ++{ ++ if (symbol < kLenNumLowSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 0); ++ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 1); ++ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 0); ++ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 1); ++ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); ++ } ++ } ++} ++ ++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) ++{ ++ UInt32 a0 = GET_PRICE_0a(p->choice); ++ UInt32 a1 = GET_PRICE_1a(p->choice); ++ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); ++ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); ++ UInt32 i = 0; ++ for (i = 0; i < kLenNumLowSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); ++ } ++ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); ++ } ++ for (; i < numSymbols; i++) ++ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); ++} ++ ++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) ++{ ++ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); ++ p->counters[posState] = p->tableSize; ++} ++ ++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) ++{ ++ UInt32 posState; ++ for (posState = 0; posState < numPosStates; posState++) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) ++{ ++ LenEnc_Encode(&p->p, rc, symbol, posState); ++ if (updatePrice) ++ if (--p->counters[posState] == 0) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++ ++ ++ ++static void MovePos(CLzmaEnc *p, UInt32 num) ++{ ++ #ifdef SHOW_STAT ++ ttt += num; ++ printf("\n MovePos %d", num); ++ #endif ++ if (num != 0) ++ { ++ p->additionalOffset += num; ++ p->matchFinder.Skip(p->matchFinderObj, num); ++ } ++} ++ ++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) ++{ ++ UInt32 lenRes = 0, numPairs; ++ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); ++ #ifdef SHOW_STAT ++ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); ++ ttt++; ++ { ++ UInt32 i; ++ for (i = 0; i < numPairs; i += 2) ++ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); ++ } ++ #endif ++ if (numPairs > 0) ++ { ++ lenRes = p->matches[numPairs - 2]; ++ if (lenRes == p->numFastBytes) ++ { ++ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ UInt32 distance = p->matches[numPairs - 1] + 1; ++ UInt32 numAvail = p->numAvail; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ { ++ const Byte *pby2 = pby - distance; ++ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); ++ } ++ } ++ } ++ p->additionalOffset++; ++ *numDistancePairsRes = numPairs; ++ return lenRes; ++} ++ ++ ++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; ++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; ++#define IsShortRep(p) ((p)->backPrev == 0) ++ ++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) ++{ ++ return ++ GET_PRICE_0(p->isRepG0[state]) + ++ GET_PRICE_0(p->isRep0Long[state][posState]); ++} ++ ++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) ++{ ++ UInt32 price; ++ if (repIndex == 0) ++ { ++ price = GET_PRICE_0(p->isRepG0[state]); ++ price += GET_PRICE_1(p->isRep0Long[state][posState]); ++ } ++ else ++ { ++ price = GET_PRICE_1(p->isRepG0[state]); ++ if (repIndex == 1) ++ price += GET_PRICE_0(p->isRepG1[state]); ++ else ++ { ++ price += GET_PRICE_1(p->isRepG1[state]); ++ price += GET_PRICE(p->isRepG2[state], repIndex - 2); ++ } ++ } ++ return price; ++} ++ ++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) ++{ ++ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + ++ GetPureRepPrice(p, repIndex, state, posState); ++} ++ ++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) ++{ ++ UInt32 posMem = p->opt[cur].posPrev; ++ UInt32 backMem = p->opt[cur].backPrev; ++ p->optimumEndIndex = cur; ++ do ++ { ++ if (p->opt[cur].prev1IsChar) ++ { ++ MakeAsChar(&p->opt[posMem]) ++ p->opt[posMem].posPrev = posMem - 1; ++ if (p->opt[cur].prev2) ++ { ++ p->opt[posMem - 1].prev1IsChar = False; ++ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; ++ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; ++ } ++ } ++ { ++ UInt32 posPrev = posMem; ++ UInt32 backCur = backMem; ++ ++ backMem = p->opt[posPrev].backPrev; ++ posMem = p->opt[posPrev].posPrev; ++ ++ p->opt[posPrev].backPrev = backCur; ++ p->opt[posPrev].posPrev = cur; ++ cur = posPrev; ++ } ++ } ++ while (cur != 0); ++ *backRes = p->opt[0].backPrev; ++ p->optimumCurrentIndex = p->opt[0].posPrev; ++ return p->optimumCurrentIndex; ++} ++ ++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) ++ ++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; ++ UInt32 matchPrice, repMatchPrice, normalMatchPrice; ++ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; ++ UInt32 *matches; ++ const Byte *data; ++ Byte curByte, matchByte; ++ if (p->optimumEndIndex != p->optimumCurrentIndex) ++ { ++ const COptimal *opt = &p->opt[p->optimumCurrentIndex]; ++ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; ++ *backRes = opt->backPrev; ++ p->optimumCurrentIndex = opt->posPrev; ++ return lenRes; ++ } ++ p->optimumCurrentIndex = p->optimumEndIndex = 0; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ if (numAvail < 2) ++ { ++ *backRes = (UInt32)(-1); ++ return 1; ++ } ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ repMaxIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 lenTest; ++ const Byte *data2; ++ reps[i] = p->reps[i]; ++ data2 = data - (reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ { ++ repLens[i] = 0; ++ continue; ++ } ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ repLens[i] = lenTest; ++ if (lenTest > repLens[repMaxIndex]) ++ repMaxIndex = i; ++ } ++ if (repLens[repMaxIndex] >= p->numFastBytes) ++ { ++ UInt32 lenRes; ++ *backRes = repMaxIndex; ++ lenRes = repLens[repMaxIndex]; ++ MovePos(p, lenRes - 1); ++ return lenRes; ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) ++ { ++ *backRes = (UInt32)-1; ++ return 1; ++ } ++ ++ p->opt[0].state = (CState)p->state; ++ ++ posState = (position & p->pbMask); ++ ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + ++ (!IsCharState(p->state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ MakeAsChar(&p->opt[1]); ++ ++ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); ++ ++ if (matchByte == curByte) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); ++ if (shortRepPrice < p->opt[1].price) ++ { ++ p->opt[1].price = shortRepPrice; ++ MakeAsShortRep(&p->opt[1]); ++ } ++ } ++ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); ++ ++ if (lenEnd < 2) ++ { ++ *backRes = p->opt[1].backPrev; ++ return 1; ++ } ++ ++ p->opt[1].posPrev = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ p->opt[0].backs[i] = reps[i]; ++ ++ len = lenEnd; ++ do ++ p->opt[len--].price = kInfinityPrice; ++ while (len >= 2); ++ ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 repLen = repLens[i]; ++ UInt32 price; ++ if (repLen < 2) ++ continue; ++ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; ++ COptimal *opt = &p->opt[repLen]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = i; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--repLen >= 2); ++ } ++ ++ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); ++ ++ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); ++ if (len <= mainLen) ++ { ++ UInt32 offs = 0; ++ while (len > matches[offs]) ++ offs += 2; ++ for (; ; len++) ++ { ++ COptimal *opt; ++ UInt32 distance = matches[offs + 1]; ++ ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(len); ++ if (distance < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][distance]; ++ else ++ { ++ UInt32 slot; ++ GetPosSlot2(distance, slot); ++ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; ++ } ++ opt = &p->opt[len]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = distance + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ if (len == matches[offs]) ++ { ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ } ++ } ++ } ++ ++ cur = 0; ++ ++ #ifdef SHOW_STAT2 ++ if (position >= 0) ++ { ++ unsigned i; ++ printf("\n pos = %4X", position); ++ for (i = cur; i <= lenEnd; i++) ++ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); ++ } ++ #endif ++ ++ for (;;) ++ { ++ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; ++ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; ++ Bool nextIsChar; ++ Byte curByte, matchByte; ++ const Byte *data; ++ COptimal *curOpt; ++ COptimal *nextOpt; ++ ++ cur++; ++ if (cur == lenEnd) ++ return Backward(p, backRes, cur); ++ ++ newLen = ReadMatchDistances(p, &numPairs); ++ if (newLen >= p->numFastBytes) ++ { ++ p->numPairs = numPairs; ++ p->longestMatchLength = newLen; ++ return Backward(p, backRes, cur); ++ } ++ position++; ++ curOpt = &p->opt[cur]; ++ posPrev = curOpt->posPrev; ++ if (curOpt->prev1IsChar) ++ { ++ posPrev--; ++ if (curOpt->prev2) ++ { ++ state = p->opt[curOpt->posPrev2].state; ++ if (curOpt->backPrev2 < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ state = kLiteralNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ if (posPrev == cur - 1) ++ { ++ if (IsShortRep(curOpt)) ++ state = kShortRepNextStates[state]; ++ else ++ state = kLiteralNextStates[state]; ++ } ++ else ++ { ++ UInt32 pos; ++ const COptimal *prevOpt; ++ if (curOpt->prev1IsChar && curOpt->prev2) ++ { ++ posPrev = curOpt->posPrev2; ++ pos = curOpt->backPrev2; ++ state = kRepNextStates[state]; ++ } ++ else ++ { ++ pos = curOpt->backPrev; ++ if (pos < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ prevOpt = &p->opt[posPrev]; ++ if (pos < LZMA_NUM_REPS) ++ { ++ UInt32 i; ++ reps[0] = prevOpt->backs[pos]; ++ for (i = 1; i <= pos; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ for (; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i]; ++ } ++ else ++ { ++ UInt32 i; ++ reps[0] = (pos - LZMA_NUM_REPS); ++ for (i = 1; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ } ++ } ++ curOpt->state = (CState)state; ++ ++ curOpt->backs[0] = reps[0]; ++ curOpt->backs[1] = reps[1]; ++ curOpt->backs[2] = reps[2]; ++ curOpt->backs[3] = reps[3]; ++ ++ curPrice = curOpt->price; ++ nextIsChar = False; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ posState = (position & p->pbMask); ++ ++ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ curAnd1Price += ++ (!IsCharState(state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ nextOpt = &p->opt[cur + 1]; ++ ++ if (curAnd1Price < nextOpt->price) ++ { ++ nextOpt->price = curAnd1Price; ++ nextOpt->posPrev = cur; ++ MakeAsChar(nextOpt); ++ nextIsChar = True; ++ } ++ ++ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); ++ ++ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); ++ if (shortRepPrice <= nextOpt->price) ++ { ++ nextOpt->price = shortRepPrice; ++ nextOpt->posPrev = cur; ++ MakeAsShortRep(nextOpt); ++ nextIsChar = True; ++ } ++ } ++ numAvailFull = p->numAvail; ++ { ++ UInt32 temp = kNumOpts - 1 - cur; ++ if (temp < numAvailFull) ++ numAvailFull = temp; ++ } ++ ++ if (numAvailFull < 2) ++ continue; ++ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); ++ ++ if (!nextIsChar && matchByte != curByte) /* speed optimization */ ++ { ++ /* try Literal + rep0 */ ++ UInt32 temp; ++ UInt32 lenTest2; ++ const Byte *data2 = data - (reps[0] + 1); ++ UInt32 limit = p->numFastBytes + 1; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ ++ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); ++ lenTest2 = temp - 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kLiteralNextStates[state]; ++ UInt32 posStateNext = (position + 1) & p->pbMask; ++ UInt32 nextRepMatchPrice = curAnd1Price + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = False; ++ } ++ } ++ } ++ } ++ ++ startLen = 2; /* speed optimization */ ++ { ++ UInt32 repIndex; ++ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) ++ { ++ UInt32 lenTest; ++ UInt32 lenTestTemp; ++ UInt32 price; ++ const Byte *data2 = data - (reps[repIndex] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ while (lenEnd < cur + lenTest) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ lenTestTemp = lenTest; ++ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; ++ COptimal *opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = repIndex; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--lenTest >= 2); ++ lenTest = lenTestTemp; ++ ++ if (repIndex == 0) ++ startLen = lenTest + 1; ++ ++ /* if (_maxMode) */ ++ { ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kRepNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = ++ price + p->repLenEnc.prices[posState][lenTest - 2] + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (position + lenTest + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = repIndex; ++ } ++ } ++ } ++ } ++ } ++ } ++ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ ++ if (newLen > numAvail) ++ { ++ newLen = numAvail; ++ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); ++ matches[numPairs] = newLen; ++ numPairs += 2; ++ } ++ if (newLen >= startLen) ++ { ++ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); ++ UInt32 offs, curBack, posSlot; ++ UInt32 lenTest; ++ while (lenEnd < cur + newLen) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ ++ offs = 0; ++ while (startLen > matches[offs]) ++ offs += 2; ++ curBack = matches[offs + 1]; ++ GetPosSlot2(curBack, posSlot); ++ for (lenTest = /*2*/ startLen; ; lenTest++) ++ { ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(lenTest); ++ COptimal *opt; ++ if (curBack < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; ++ else ++ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; ++ ++ opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = curBack + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ ++ if (/*_maxMode && */lenTest == matches[offs]) ++ { ++ /* Try Match + Literal + Rep0 */ ++ const Byte *data2 = data - (curBack + 1); ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kMatchNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = curAndLenPrice + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (posStateNext + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = curBack + LZMA_NUM_REPS; ++ } ++ } ++ } ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ curBack = matches[offs + 1]; ++ if (curBack >= kNumFullDistances) ++ GetPosSlot2(curBack, posSlot); ++ } ++ } ++ } ++ } ++} ++ ++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) ++ ++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; ++ const Byte *data; ++ const UInt32 *matches; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ *backRes = (UInt32)-1; ++ if (numAvail < 2) ++ return 1; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ ++ repLen = repIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (len = 2; len < numAvail && data[len] == data2[len]; len++); ++ if (len >= p->numFastBytes) ++ { ++ *backRes = i; ++ MovePos(p, len - 1); ++ return len; ++ } ++ if (len > repLen) ++ { ++ repIndex = i; ++ repLen = len; ++ } ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ ++ mainDist = 0; /* for GCC */ ++ if (mainLen >= 2) ++ { ++ mainDist = matches[numPairs - 1]; ++ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) ++ { ++ if (!ChangePair(matches[numPairs - 3], mainDist)) ++ break; ++ numPairs -= 2; ++ mainLen = matches[numPairs - 2]; ++ mainDist = matches[numPairs - 1]; ++ } ++ if (mainLen == 2 && mainDist >= 0x80) ++ mainLen = 1; ++ } ++ ++ if (repLen >= 2 && ( ++ (repLen + 1 >= mainLen) || ++ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || ++ (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) ++ { ++ *backRes = repIndex; ++ MovePos(p, repLen - 1); ++ return repLen; ++ } ++ ++ if (mainLen < 2 || numAvail <= 2) ++ return 1; ++ ++ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); ++ if (p->longestMatchLength >= 2) ++ { ++ UInt32 newDistance = matches[p->numPairs - 1]; ++ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || ++ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || ++ (p->longestMatchLength > mainLen + 1) || ++ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) ++ return 1; ++ } ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len, limit; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ limit = mainLen - 1; ++ for (len = 2; len < limit && data[len] == data2[len]; len++); ++ if (len >= limit) ++ return 1; ++ } ++ *backRes = mainDist + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 2); ++ return mainLen; ++} ++ ++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) ++{ ++ UInt32 len; ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ len = LZMA_MATCH_LEN_MIN; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); ++ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); ++} ++ ++static SRes CheckErrors(CLzmaEnc *p) ++{ ++ if (p->result != SZ_OK) ++ return p->result; ++ if (p->rc.res != SZ_OK) ++ p->result = SZ_ERROR_WRITE; ++ if (p->matchFinderBase.result != SZ_OK) ++ p->result = SZ_ERROR_READ; ++ if (p->result != SZ_OK) ++ p->finished = True; ++ return p->result; ++} ++ ++static SRes Flush(CLzmaEnc *p, UInt32 nowPos) ++{ ++ /* ReleaseMFStream(); */ ++ p->finished = True; ++ if (p->writeEndMark) ++ WriteEndMarker(p, nowPos & p->pbMask); ++ RangeEnc_FlushData(&p->rc); ++ RangeEnc_FlushStream(&p->rc); ++ return CheckErrors(p); ++} ++ ++static void FillAlignPrices(CLzmaEnc *p) ++{ ++ UInt32 i; ++ for (i = 0; i < kAlignTableSize; i++) ++ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); ++ p->alignPriceCount = 0; ++} ++ ++static void FillDistancesPrices(CLzmaEnc *p) ++{ ++ UInt32 tempPrices[kNumFullDistances]; ++ UInt32 i, lenToPosState; ++ for (i = kStartPosModelIndex; i < kNumFullDistances; i++) ++ { ++ UInt32 posSlot = GetPosSlot1(i); ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); ++ } ++ ++ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) ++ { ++ UInt32 posSlot; ++ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; ++ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; ++ for (posSlot = 0; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); ++ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); ++ ++ { ++ UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; ++ UInt32 i; ++ for (i = 0; i < kStartPosModelIndex; i++) ++ distancesPrices[i] = posSlotPrices[i]; ++ for (; i < kNumFullDistances; i++) ++ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; ++ } ++ } ++ p->matchPriceCount = 0; ++} ++ ++void LzmaEnc_Construct(CLzmaEnc *p) ++{ ++ RangeEnc_Construct(&p->rc); ++ MatchFinder_Construct(&p->matchFinderBase); ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Construct(&p->matchFinderMt); ++ p->matchFinderMt.MatchFinder = &p->matchFinderBase; ++ #endif ++ ++ { ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ LzmaEnc_SetProps(p, &props); ++ } ++ ++ #ifndef LZMA_LOG_BSR ++ LzmaEnc_FastPosInit(p->g_FastPos); ++ #endif ++ ++ LzmaEnc_InitPriceTables(p->ProbPrices); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) ++{ ++ void *p; ++ p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); ++ if (p != 0) ++ LzmaEnc_Construct((CLzmaEnc *)p); ++ return p; ++} ++ ++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->litProbs); ++ alloc->Free(alloc, p->saveState.litProbs); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); ++ #endif ++ MatchFinder_Free(&p->matchFinderBase, allocBig); ++ LzmaEnc_FreeLits(p, alloc); ++ RangeEnc_Free(&p->rc, alloc); ++} ++ ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); ++ alloc->Free(alloc, p); ++} ++ ++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) ++{ ++ UInt32 nowPos32, startPos32; ++ if (p->needInit) ++ { ++ p->matchFinder.Init(p->matchFinderObj); ++ p->needInit = 0; ++ } ++ ++ if (p->finished) ++ return p->result; ++ RINOK(CheckErrors(p)); ++ ++ nowPos32 = (UInt32)p->nowPos64; ++ startPos32 = nowPos32; ++ ++ if (p->nowPos64 == 0) ++ { ++ UInt32 numPairs; ++ Byte curByte; ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ return Flush(p, nowPos32); ++ ReadMatchDistances(p, &numPairs); ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); ++ p->state = kLiteralNextStates[p->state]; ++ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); ++ LitEnc_Encode(&p->rc, p->litProbs, curByte); ++ p->additionalOffset--; ++ nowPos32++; ++ } ++ ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) ++ for (;;) ++ { ++ UInt32 pos, len, posState; ++ ++ if (p->fastMode) ++ len = GetOptimumFast(p, &pos); ++ else ++ len = GetOptimum(p, nowPos32, &pos); ++ ++ #ifdef SHOW_STAT2 ++ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); ++ #endif ++ ++ posState = nowPos32 & p->pbMask; ++ if (len == 1 && pos == (UInt32)-1) ++ { ++ Byte curByte; ++ CLzmaProb *probs; ++ const Byte *data; ++ ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++ curByte = *data; ++ probs = LIT_PROBS(nowPos32, *(data - 1)); ++ if (IsCharState(p->state)) ++ LitEnc_Encode(&p->rc, probs, curByte); ++ else ++ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); ++ p->state = kLiteralNextStates[p->state]; ++ } ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ if (pos < LZMA_NUM_REPS) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); ++ if (pos == 0) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); ++ } ++ else ++ { ++ UInt32 distance = p->reps[pos]; ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); ++ if (pos == 1) ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); ++ if (pos == 3) ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ } ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = distance; ++ } ++ if (len == 1) ++ p->state = kShortRepNextStates[p->state]; ++ else ++ { ++ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ p->state = kRepNextStates[p->state]; ++ } ++ } ++ else ++ { ++ UInt32 posSlot; ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ pos -= LZMA_NUM_REPS; ++ GetPosSlot(pos, posSlot); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); ++ ++ if (posSlot >= kStartPosModelIndex) ++ { ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ UInt32 posReduced = pos - base; ++ ++ if (posSlot < kEndPosModelIndex) ++ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); ++ else ++ { ++ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); ++ p->alignPriceCount++; ++ } ++ } ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = pos; ++ p->matchPriceCount++; ++ } ++ } ++ p->additionalOffset -= len; ++ nowPos32 += len; ++ if (p->additionalOffset == 0) ++ { ++ UInt32 processed; ++ if (!p->fastMode) ++ { ++ if (p->matchPriceCount >= (1 << 7)) ++ FillDistancesPrices(p); ++ if (p->alignPriceCount >= kAlignTableSize) ++ FillAlignPrices(p); ++ } ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ break; ++ processed = nowPos32 - startPos32; ++ if (useLimits) ++ { ++ if (processed + kNumOpts + 300 >= maxUnpackSize || ++ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) ++ break; ++ } ++ else if (processed >= (1 << 15)) ++ { ++ p->nowPos64 += nowPos32 - startPos32; ++ return CheckErrors(p); ++ } ++ } ++ } ++ p->nowPos64 += nowPos32 - startPos32; ++ return Flush(p, nowPos32); ++} ++ ++#define kBigHashDicLimit ((UInt32)1 << 24) ++ ++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 beforeSize = kNumOpts; ++ Bool btMode; ++ if (!RangeEnc_Alloc(&p->rc, alloc)) ++ return SZ_ERROR_MEM; ++ btMode = (p->matchFinderBase.btMode != 0); ++ #ifndef _7ZIP_ST ++ p->mtMode = (p->multiThread && !p->fastMode && btMode); ++ #endif ++ ++ { ++ unsigned lclp = p->lc + p->lp; ++ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ if (p->litProbs == 0 || p->saveState.litProbs == 0) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ p->lclp = lclp; ++ } ++ } ++ ++ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); ++ ++ if (beforeSize + p->dictSize < keepWindowSize) ++ beforeSize = keepWindowSize - p->dictSize; ++ ++ #ifndef _7ZIP_ST ++ if (p->mtMode) ++ { ++ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); ++ p->matchFinderObj = &p->matchFinderMt; ++ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); ++ } ++ else ++ #endif ++ { ++ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) ++ return SZ_ERROR_MEM; ++ p->matchFinderObj = &p->matchFinderBase; ++ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); ++ } ++ return SZ_OK; ++} ++ ++void LzmaEnc_Init(CLzmaEnc *p) ++{ ++ UInt32 i; ++ p->state = 0; ++ for (i = 0 ; i < LZMA_NUM_REPS; i++) ++ p->reps[i] = 0; ++ ++ RangeEnc_Init(&p->rc); ++ ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ UInt32 j; ++ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) ++ { ++ p->isMatch[i][j] = kProbInitValue; ++ p->isRep0Long[i][j] = kProbInitValue; ++ } ++ p->isRep[i] = kProbInitValue; ++ p->isRepG0[i] = kProbInitValue; ++ p->isRepG1[i] = kProbInitValue; ++ p->isRepG2[i] = kProbInitValue; ++ } ++ ++ { ++ UInt32 num = 0x300 << (p->lp + p->lc); ++ for (i = 0; i < num; i++) ++ p->litProbs[i] = kProbInitValue; ++ } ++ ++ { ++ for (i = 0; i < kNumLenToPosStates; i++) ++ { ++ CLzmaProb *probs = p->posSlotEncoder[i]; ++ UInt32 j; ++ for (j = 0; j < (1 << kNumPosSlotBits); j++) ++ probs[j] = kProbInitValue; ++ } ++ } ++ { ++ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) ++ p->posEncoders[i] = kProbInitValue; ++ } ++ ++ LenEnc_Init(&p->lenEnc.p); ++ LenEnc_Init(&p->repLenEnc.p); ++ ++ for (i = 0; i < (1 << kNumAlignBits); i++) ++ p->posAlignEncoder[i] = kProbInitValue; ++ ++ p->optimumEndIndex = 0; ++ p->optimumCurrentIndex = 0; ++ p->additionalOffset = 0; ++ ++ p->pbMask = (1 << p->pb) - 1; ++ p->lpMask = (1 << p->lp) - 1; ++} ++ ++void LzmaEnc_InitPrices(CLzmaEnc *p) ++{ ++ if (!p->fastMode) ++ { ++ FillDistancesPrices(p); ++ FillAlignPrices(p); ++ } ++ ++ p->lenEnc.tableSize = ++ p->repLenEnc.tableSize = ++ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; ++ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); ++ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); ++} ++ ++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 i; ++ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) ++ if (p->dictSize <= ((UInt32)1 << i)) ++ break; ++ p->distTableSize = i * 2; ++ ++ p->finished = False; ++ p->result = SZ_OK; ++ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ p->nowPos64 = 0; ++ return SZ_OK; ++} ++ ++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ p->rc.outStream = outStream; ++ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); ++} ++ ++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ++ ISeqInStream *inStream, UInt32 keepWindowSize, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) ++{ ++ p->matchFinderBase.directInput = 1; ++ p->matchFinderBase.bufferBase = (Byte *)src; ++ p->matchFinderBase.directInputRem = srcLen; ++} ++ ++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ p->needInit = 1; ++ ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++void LzmaEnc_Finish(CLzmaEncHandle pp) ++{ ++ #ifndef _7ZIP_ST ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ if (p->mtMode) ++ MatchFinderMt_ReleaseStream(&p->matchFinderMt); ++ #else ++ pp = pp; ++ #endif ++} ++ ++typedef struct ++{ ++ ISeqOutStream funcTable; ++ Byte *data; ++ SizeT rem; ++ Bool overflow; ++} CSeqOutStreamBuf; ++ ++static size_t MyWrite(void *pp, const void *data, size_t size) ++{ ++ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; ++ if (p->rem < size) ++ { ++ size = p->rem; ++ p->overflow = True; ++ } ++ memcpy(p->data, data, size); ++ p->rem -= size; ++ p->data += size; ++ return size; ++} ++ ++ ++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++} ++ ++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++} ++ ++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, ++ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ UInt64 nowPos64; ++ SRes res; ++ CSeqOutStreamBuf outStream; ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = False; ++ p->finished = False; ++ p->result = SZ_OK; ++ ++ if (reInit) ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ nowPos64 = p->nowPos64; ++ RangeEnc_Init(&p->rc); ++ p->rc.outStream = &outStream.funcTable; ++ ++ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); ++ ++ *unpackSize = (UInt32)(p->nowPos64 - nowPos64); ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ ++ return res; ++} ++ ++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) ++{ ++ SRes res = SZ_OK; ++ ++ #ifndef _7ZIP_ST ++ Byte allocaDummy[0x300]; ++ int i = 0; ++ for (i = 0; i < 16; i++) ++ allocaDummy[i] = (Byte)i; ++ #endif ++ ++ for (;;) ++ { ++ res = LzmaEnc_CodeOneBlock(p, False, 0, 0); ++ if (res != SZ_OK || p->finished != 0) ++ break; ++ if (progress != 0) ++ { ++ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); ++ if (res != SZ_OK) ++ { ++ res = SZ_ERROR_PROGRESS; ++ break; ++ } ++ } ++ } ++ LzmaEnc_Finish(p); ++ return res; ++} ++ ++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); ++ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); ++} ++ ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ int i; ++ UInt32 dictSize = p->dictSize; ++ if (*size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_PARAM; ++ *size = LZMA_PROPS_SIZE; ++ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); ++ ++ for (i = 11; i <= 30; i++) ++ { ++ if (dictSize <= ((UInt32)2 << i)) ++ { ++ dictSize = (2 << i); ++ break; ++ } ++ if (dictSize <= ((UInt32)3 << i)) ++ { ++ dictSize = (3 << i); ++ break; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) ++ props[1 + i] = (Byte)(dictSize >> (8 * i)); ++ return SZ_OK; ++} ++ ++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ SRes res; ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ ++ CSeqOutStreamBuf outStream; ++ ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = writeEndMark; ++ ++ p->rc.outStream = &outStream.funcTable; ++ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); ++ if (res == SZ_OK) ++ res = LzmaEnc_Encode2(p, progress); ++ ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ return res; ++} ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); ++ SRes res; ++ if (p == 0) ++ return SZ_ERROR_MEM; ++ ++ res = LzmaEnc_SetProps(p, props); ++ if (res == SZ_OK) ++ { ++ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); ++ if (res == SZ_OK) ++ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, ++ writeEndMark, progress, alloc, allocBig); ++ } ++ ++ LzmaEnc_Destroy(p, alloc, allocBig); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/Makefile +@@ -0,0 +1,7 @@ ++lzma_compress-objs := LzFind.o LzmaEnc.o ++lzma_decompress-objs := LzmaDec.o ++ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o ++ ++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h diff --git a/ipq806x/pending-5.4/532-jffs2_eofdetect.patch b/ipq806x/pending-5.4/532-jffs2_eofdetect.patch new file mode 100644 index 0000000..df4ab9b --- /dev/null +++ b/ipq806x/pending-5.4/532-jffs2_eofdetect.patch @@ -0,0 +1,65 @@ +From: Felix Fietkau +Subject: fs: jffs2: EOF marker + +Signed-off-by: Felix Fietkau +--- + fs/jffs2/build.c | 10 ++++++++++ + fs/jffs2/scan.c | 21 +++++++++++++++++++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct + dbg_fsbuild("scanned flash completely\n"); + jffs2_dbg_dump_block_lists_nolock(c); + ++ if (c->flags & (1 << 7)) { ++ printk("%s(): unlocking the mtd device... ", __func__); ++ mtd_unlock(c->mtd, 0, c->mtd->size); ++ printk("done.\n"); ++ ++ printk("%s(): erasing all blocks after the end marker... ", __func__); ++ jffs2_erase_pending_blocks(c, -1); ++ printk("done.\n"); ++ } ++ + dbg_fsbuild("pass 1 starting\n"); + c->flags |= JFFS2_SB_FLAG_BUILDING; + /* Now scan the directory tree, increasing nlink according to every dirent found. */ +--- a/fs/jffs2/scan.c ++++ b/fs/jffs2/scan.c +@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in + /* reset summary info for next eraseblock scan */ + jffs2_sum_reset_collected(s); + +- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), +- buf_size, s); ++ if (c->flags & (1 << 7)) { ++ if (mtd_block_isbad(c->mtd, jeb->offset)) ++ ret = BLK_STATE_BADBLOCK; ++ else ++ ret = BLK_STATE_ALLFF; ++ } else ++ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), ++ buf_size, s); + + if (ret < 0) + goto out; +@@ -564,6 +570,17 @@ full_scan: + return err; + } + ++ if ((buf[0] == 0xde) && ++ (buf[1] == 0xad) && ++ (buf[2] == 0xc0) && ++ (buf[3] == 0xde)) { ++ /* end of filesystem. erase everything after this point */ ++ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset); ++ c->flags |= (1 << 7); ++ ++ return BLK_STATE_ALLFF; ++ } ++ + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ + ofs = 0; + max_ofs = EMPTY_SCAN_SIZE(c->sector_size); diff --git a/ipq806x/pending-5.4/600-netfilter_conntrack_flush.patch b/ipq806x/pending-5.4/600-netfilter_conntrack_flush.patch new file mode 100644 index 0000000..eaf8c78 --- /dev/null +++ b/ipq806x/pending-5.4/600-netfilter_conntrack_flush.patch @@ -0,0 +1,88 @@ +From: Felix Fietkau +Subject: netfilter: add support for flushing conntrack via /proc + +lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314 +Signed-off-by: Felix Fietkau +--- + net/netfilter/nf_conntrack_standalone.c | 59 ++++++++++++++++++++++++++++++++- + 1 file changed, 58 insertions(+), 1 deletion(-) + +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_SYSCTL + #include +@@ -455,6 +456,56 @@ static int ct_cpu_seq_show(struct seq_fi + return 0; + } + ++struct kill_request { ++ u16 family; ++ union nf_inet_addr addr; ++}; ++ ++static int kill_matching(struct nf_conn *i, void *data) ++{ ++ struct kill_request *kr = data; ++ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (!kr->family) ++ return 1; ++ ++ if (t1->src.l3num != kr->family) ++ return 0; ++ ++ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3)); ++} ++ ++static int ct_file_write(struct file *file, char *buf, size_t count) ++{ ++ struct seq_file *seq = file->private_data; ++ struct net *net = seq_file_net(seq); ++ struct kill_request kr = { }; ++ ++ if (count == 0) ++ return 0; ++ ++ if (count >= INET6_ADDRSTRLEN) ++ count = INET6_ADDRSTRLEN - 1; ++ ++ if (strnchr(buf, count, ':')) { ++ kr.family = AF_INET6; ++ if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } else if (strnchr(buf, count, '.')) { ++ kr.family = AF_INET; ++ if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } ++ ++ nf_ct_iterate_cleanup_net(net, kill_matching, &kr, 0, 0); ++ ++ return 0; ++} ++ + static const struct seq_operations ct_cpu_seq_ops = { + .start = ct_cpu_seq_start, + .next = ct_cpu_seq_next, +@@ -468,8 +519,9 @@ static int nf_conntrack_standalone_init_ + kuid_t root_uid; + kgid_t root_gid; + +- pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops, +- sizeof(struct ct_iter_state)); ++ pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net, ++ &ct_seq_ops, &ct_file_write, ++ sizeof(struct ct_iter_state), NULL); + if (!pde) + goto out_nf_conntrack; + diff --git a/ipq806x/pending-5.4/610-netfilter_match_bypass_default_checks.patch b/ipq806x/pending-5.4/610-netfilter_match_bypass_default_checks.patch new file mode 100644 index 0000000..703ac82 --- /dev/null +++ b/ipq806x/pending-5.4/610-netfilter_match_bypass_default_checks.patch @@ -0,0 +1,110 @@ +From: Felix Fietkau +Subject: kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0 + +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/netfilter_ipv4/ip_tables.h | 1 + + net/ipv4/netfilter/ip_tables.c | 37 +++++++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h ++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h +@@ -89,6 +89,7 @@ struct ipt_ip { + #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ + #define IPT_F_GOTO 0x02 /* Set if jump is a goto */ + #define IPT_F_MASK 0x03 /* All possible flag bits mask. */ ++#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */ + + /* Values for "inv" field in struct ipt_ip. */ + #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -50,6 +50,9 @@ ip_packet_match(const struct iphdr *ip, + { + unsigned long ret; + ++ if (ipinfo->flags & IPT_F_NO_DEF_MATCH) ++ return true; ++ + if (NF_INVF(ipinfo, IPT_INV_SRCIP, + (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || + NF_INVF(ipinfo, IPT_INV_DSTIP, +@@ -80,6 +83,29 @@ ip_packet_match(const struct iphdr *ip, + return true; + } + ++static void ++ip_checkdefault(struct ipt_ip *ip) ++{ ++ static const char iface_mask[IFNAMSIZ] = {}; ++ ++ if (ip->invflags || ip->flags & IPT_F_FRAG) ++ return; ++ ++ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (ip->smsk.s_addr || ip->dmsk.s_addr) ++ return; ++ ++ if (ip->proto) ++ return; ++ ++ ip->flags |= IPT_F_NO_DEF_MATCH; ++} ++ + static bool + ip_checkentry(const struct ipt_ip *ip) + { +@@ -524,6 +550,8 @@ find_check_entry(struct ipt_entry *e, st + struct xt_mtchk_param mtpar; + struct xt_entry_match *ematch; + ++ ip_checkdefault(&e->ip); ++ + if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) + return -ENOMEM; + +@@ -818,6 +846,7 @@ copy_entries_to_user(unsigned int total_ + const struct xt_table_info *private = table->private; + int ret = 0; + const void *loc_cpu_entry; ++ u8 flags; + + counters = alloc_counters(table); + if (IS_ERR(counters)) +@@ -845,6 +874,14 @@ copy_entries_to_user(unsigned int total_ + goto free_counters; + } + ++ flags = e->ip.flags & IPT_F_MASK; ++ if (copy_to_user(userptr + off ++ + offsetof(struct ipt_entry, ip.flags), ++ &flags, sizeof(flags)) != 0) { ++ ret = -EFAULT; ++ goto free_counters; ++ } ++ + for (i = sizeof(struct ipt_entry); + i < e->target_offset; + i += m->u.match_size) { +@@ -1225,12 +1262,15 @@ compat_copy_entry_to_user(struct ipt_ent + compat_uint_t origsize; + const struct xt_entry_match *ematch; + int ret = 0; ++ u8 flags = e->ip.flags & IPT_F_MASK; + + origsize = *size; + ce = *dstptr; + if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || + copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ sizeof(counters[i])) != 0 || ++ copy_to_user(&ce->ip.flags, &flags, ++ sizeof(flags)) != 0) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); diff --git a/ipq806x/pending-5.4/611-netfilter_match_bypass_default_table.patch b/ipq806x/pending-5.4/611-netfilter_match_bypass_default_table.patch new file mode 100644 index 0000000..baf738a --- /dev/null +++ b/ipq806x/pending-5.4/611-netfilter_match_bypass_default_table.patch @@ -0,0 +1,106 @@ +From: Felix Fietkau +Subject: netfilter: match bypass default table + +Signed-off-by: Felix Fietkau +--- + net/ipv4/netfilter/ip_tables.c | 79 +++++++++++++++++++++++++++++++----------- + 1 file changed, 58 insertions(+), 21 deletions(-) + +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -246,6 +246,33 @@ struct ipt_entry *ipt_next_entry(const s + return (void *)entry + entry->next_offset; + } + ++static bool ++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict) ++{ ++ struct xt_entry_target *t; ++ struct xt_standard_target *st; ++ ++ if (e->target_offset != sizeof(struct ipt_entry)) ++ return false; ++ ++ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH)) ++ return false; ++ ++ t = ipt_get_target(e); ++ if (t->u.kernel.target->target) ++ return false; ++ ++ st = (struct xt_standard_target *) t; ++ if (st->verdict == XT_RETURN) ++ return false; ++ ++ if (st->verdict >= 0) ++ return false; ++ ++ *verdict = (unsigned)(-st->verdict) - 1; ++ return true; ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ipt_do_table(struct sk_buff *skb, +@@ -266,27 +293,28 @@ ipt_do_table(struct sk_buff *skb, + unsigned int addend; + + /* Initialization */ ++ WARN_ON(!(table->valid_hooks & (1 << hook))); ++ local_bh_disable(); ++ private = READ_ONCE(table->private); /* Address dependency. */ ++ cpu = smp_processor_id(); ++ table_base = private->entries; ++ ++ e = get_entry(table_base, private->hook_entry[hook]); ++ if (ipt_handle_default_rule(e, &verdict)) { ++ struct xt_counters *counter; ++ ++ counter = xt_get_this_cpu_counter(&e->counters); ++ ADD_COUNTER(*counter, skb->len, 1); ++ local_bh_enable(); ++ return verdict; ++ } ++ + stackidx = 0; + ip = ip_hdr(skb); + indev = state->in ? state->in->name : nulldevname; + outdev = state->out ? state->out->name : nulldevname; +- /* We handle fragments by dealing with the first fragment as +- * if it was a normal packet. All other fragments are treated +- * normally, except that they will NEVER match rules that ask +- * things we don't know, ie. tcp syn flag or ports). If the +- * rule is also a fragment-specific rule, non-fragments won't +- * match it. */ +- acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; +- acpar.thoff = ip_hdrlen(skb); +- acpar.hotdrop = false; +- acpar.state = state; + +- WARN_ON(!(table->valid_hooks & (1 << hook))); +- local_bh_disable(); + addend = xt_write_recseq_begin(); +- private = READ_ONCE(table->private); /* Address dependency. */ +- cpu = smp_processor_id(); +- table_base = private->entries; + jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; + + /* Switch to alternate jumpstack if we're being invoked via TEE. +@@ -299,7 +327,16 @@ ipt_do_table(struct sk_buff *skb, + if (static_key_false(&xt_tee_enabled)) + jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); + +- e = get_entry(table_base, private->hook_entry[hook]); ++ /* We handle fragments by dealing with the first fragment as ++ * if it was a normal packet. All other fragments are treated ++ * normally, except that they will NEVER match rules that ask ++ * things we don't know, ie. tcp syn flag or ports). If the ++ * rule is also a fragment-specific rule, non-fragments won't ++ * match it. */ ++ acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; ++ acpar.thoff = ip_hdrlen(skb); ++ acpar.hotdrop = false; ++ acpar.state = state; + + do { + const struct xt_entry_target *t; diff --git a/ipq806x/pending-5.4/612-netfilter_match_reduce_memory_access.patch b/ipq806x/pending-5.4/612-netfilter_match_reduce_memory_access.patch new file mode 100644 index 0000000..79da677 --- /dev/null +++ b/ipq806x/pending-5.4/612-netfilter_match_reduce_memory_access.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: netfilter: reduce match memory access + +Signed-off-by: Felix Fietkau +--- + net/ipv4/netfilter/ip_tables.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -53,9 +53,9 @@ ip_packet_match(const struct iphdr *ip, + if (ipinfo->flags & IPT_F_NO_DEF_MATCH) + return true; + +- if (NF_INVF(ipinfo, IPT_INV_SRCIP, ++ if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr && + (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || +- NF_INVF(ipinfo, IPT_INV_DSTIP, ++ NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr && + (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr)) + return false; + diff --git a/ipq806x/pending-5.4/613-netfilter_optional_tcp_window_check.patch b/ipq806x/pending-5.4/613-netfilter_optional_tcp_window_check.patch new file mode 100644 index 0000000..0735f8d --- /dev/null +++ b/ipq806x/pending-5.4/613-netfilter_optional_tcp_window_check.patch @@ -0,0 +1,73 @@ +From: Felix Fietkau +Subject: netfilter: optional tcp window check + +Signed-off-by: Felix Fietkau +--- + net/netfilter/nf_conntrack_proto_tcp.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -31,6 +31,9 @@ + #include + #include + ++/* Do not check the TCP window for incoming packets */ ++static int nf_ct_tcp_no_window_check __read_mostly = 1; ++ + /* "Be conservative in what you do, + be liberal in what you accept from others." + If it's non-zero, we mark only out of window RST segments as INVALID. */ +@@ -476,6 +479,9 @@ static bool tcp_in_window(const struct n + s32 receiver_offset; + bool res, in_recv_win; + ++ if (nf_ct_tcp_no_window_check) ++ return true; ++ + /* + * Get the required data from the packet. + */ +@@ -1130,7 +1136,7 @@ int nf_conntrack_tcp_packet(struct nf_co + IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && + timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK]) + timeout = timeouts[TCP_CONNTRACK_UNACK]; +- else if (ct->proto.tcp.last_win == 0 && ++ else if (!nf_ct_tcp_no_window_check && ct->proto.tcp.last_win == 0 && + timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) + timeout = timeouts[TCP_CONNTRACK_RETRANS]; + else +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -25,6 +25,9 @@ + #include + #include + ++/* Do not check the TCP window for incoming packets */ ++static int nf_ct_tcp_no_window_check __read_mostly = 1; ++ + static bool enable_hooks __read_mostly; + MODULE_PARM_DESC(enable_hooks, "Always enable conntrack hooks"); + module_param(enable_hooks, bool, 0000); +@@ -650,6 +653,7 @@ enum nf_ct_sysctl_index { + NF_SYSCTL_CT_PROTO_TIMEOUT_GRE_STREAM, + #endif + ++ NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK, + __NF_SYSCTL_CT_LAST_SYSCTL, + }; + +@@ -976,6 +980,13 @@ static struct ctl_table nf_ct_sysctl_tab + .proc_handler = proc_dointvec_jiffies, + }, + #endif ++ [NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK] = { ++ .procname = "nf_conntrack_tcp_no_window_check", ++ .data = &nf_ct_tcp_no_window_check, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec, ++ }, + {} + }; + diff --git a/ipq806x/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch b/ipq806x/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch new file mode 100644 index 0000000..ca85b8a --- /dev/null +++ b/ipq806x/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch @@ -0,0 +1,86 @@ +From: Konstantin Khlebnikov +Date: Mon, 21 Aug 2017 11:14:14 +0300 +Subject: [PATCH] net_sched/codel: do not defer queue length update + +When codel wants to drop last packet in ->dequeue() it cannot call +qdisc_tree_reduce_backlog() right away - it will notify parent qdisc +about zero qlen and HTB/HFSC will deactivate class. The same class will +be deactivated second time by caller of ->dequeue(). Currently codel and +fq_codel defer update. This triggers warning in HFSC when it's qlen != 0 +but there is no active classes. + +This patch update parent queue length immediately: just temporary increase +qlen around qdisc_tree_reduce_backlog() to prevent first class deactivation +if we have skb to return. + +This might open another problem in HFSC - now operation peek could fail and +deactivate parent class. + +Signed-off-by: Konstantin Khlebnikov +Link: https://bugzilla.kernel.org/show_bug.cgi?id=109581 +--- + +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -95,11 +95,17 @@ static struct sk_buff *codel_qdisc_deque + &q->stats, qdisc_pkt_len, codel_get_enqueue_time, + drop_func, dequeue_func); + +- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, +- * or HTB crashes. Defer it for next round. ++ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate ++ * parent class, dequeue in parent qdisc will do the same if we ++ * return skb. Temporary increment qlen if we have skb. + */ +- if (q->stats.drop_count && sch->q.qlen) { +- qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len); ++ if (q->stats.drop_count) { ++ if (skb) ++ sch->q.qlen++; ++ qdisc_tree_reduce_backlog(sch, q->stats.drop_count, ++ q->stats.drop_len); ++ if (skb) ++ sch->q.qlen--; + q->stats.drop_count = 0; + q->stats.drop_len = 0; + } +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -305,6 +305,21 @@ begin: + &flow->cvars, &q->cstats, qdisc_pkt_len, + codel_get_enqueue_time, drop_func, dequeue_func); + ++ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate ++ * parent class, dequeue in parent qdisc will do the same if we ++ * return skb. Temporary increment qlen if we have skb. ++ */ ++ if (q->cstats.drop_count) { ++ if (skb) ++ sch->q.qlen++; ++ qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, ++ q->cstats.drop_len); ++ if (skb) ++ sch->q.qlen--; ++ q->cstats.drop_count = 0; ++ q->cstats.drop_len = 0; ++ } ++ + if (!skb) { + /* force a pass through old_flows to prevent starvation */ + if ((head == &q->new_flows) && !list_empty(&q->old_flows)) +@@ -315,15 +330,6 @@ begin: + } + qdisc_bstats_update(sch, skb); + flow->deficit -= qdisc_pkt_len(skb); +- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, +- * or HTB crashes. Defer it for next round. +- */ +- if (q->cstats.drop_count && sch->q.qlen) { +- qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, +- q->cstats.drop_len); +- q->cstats.drop_count = 0; +- q->cstats.drop_len = 0; +- } + return skb; + } + diff --git a/ipq806x/pending-5.4/630-packet_socket_type.patch b/ipq806x/pending-5.4/630-packet_socket_type.patch new file mode 100644 index 0000000..d9bfda1 --- /dev/null +++ b/ipq806x/pending-5.4/630-packet_socket_type.patch @@ -0,0 +1,138 @@ +From: Felix Fietkau +Subject: net: add an optimization for dealing with raw sockets + +lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6 +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/if_packet.h | 3 +++ + net/packet/af_packet.c | 34 +++++++++++++++++++++++++++------- + net/packet/internal.h | 1 + + 3 files changed, 31 insertions(+), 7 deletions(-) + +--- a/include/uapi/linux/if_packet.h ++++ b/include/uapi/linux/if_packet.h +@@ -32,6 +32,8 @@ struct sockaddr_ll { + #define PACKET_KERNEL 7 /* To kernel space */ + /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ + #define PACKET_FASTROUTE 6 /* Fastrouted frame */ ++#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ ++ + + /* Packet socket options */ + +@@ -58,6 +60,7 @@ struct sockaddr_ll { + #define PACKET_ROLLOVER_STATS 21 + #define PACKET_FANOUT_DATA 22 + #define PACKET_IGNORE_OUTGOING 23 ++#define PACKET_RECV_TYPE 24 + + #define PACKET_FANOUT_HASH 0 + #define PACKET_FANOUT_LB 1 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1797,6 +1797,7 @@ static int packet_rcv_spkt(struct sk_buf + { + struct sock *sk; + struct sockaddr_pkt *spkt; ++ struct packet_sock *po; + + /* + * When we registered the protocol we saved the socket in the data +@@ -1804,6 +1805,7 @@ static int packet_rcv_spkt(struct sk_buf + */ + + sk = pt->af_packet_priv; ++ po = pkt_sk(sk); + + /* + * Yank back the headers [hope the device set this +@@ -1816,7 +1818,7 @@ static int packet_rcv_spkt(struct sk_buf + * so that this procedure is noop. + */ + +- if (skb->pkt_type == PACKET_LOOPBACK) ++ if (!(po->pkt_type & (1 << skb->pkt_type))) + goto out; + + if (!net_eq(dev_net(dev), sock_net(sk))) +@@ -2054,12 +2056,12 @@ static int packet_rcv(struct sk_buff *sk + unsigned int snaplen, res; + bool is_drop_n_account = false; + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -2185,12 +2187,12 @@ static int tpacket_rcv(struct sk_buff *s + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -3289,6 +3291,7 @@ static int packet_create(struct net *net + mutex_init(&po->pg_vec_lock); + po->rollover = NULL; + po->prot_hook.func = packet_rcv; ++ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK); + + if (sock->type == SOCK_PACKET) + po->prot_hook.func = packet_rcv_spkt; +@@ -3924,6 +3927,16 @@ packet_setsockopt(struct socket *sock, i + po->xmit = val ? packet_direct_xmit : dev_queue_xmit; + return 0; + } ++ case PACKET_RECV_TYPE: ++ { ++ unsigned int val; ++ if (optlen != sizeof(val)) ++ return -EINVAL; ++ if (copy_from_user(&val, optval, sizeof(val))) ++ return -EFAULT; ++ po->pkt_type = val & ~BIT(PACKET_LOOPBACK); ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -3980,6 +3993,13 @@ static int packet_getsockopt(struct sock + case PACKET_VNET_HDR: + val = po->has_vnet_hdr; + break; ++ case PACKET_RECV_TYPE: ++ if (len > sizeof(unsigned int)) ++ len = sizeof(unsigned int); ++ val = po->pkt_type; ++ ++ data = &val; ++ break; + case PACKET_VERSION: + val = po->tp_version; + break; +--- a/net/packet/internal.h ++++ b/net/packet/internal.h +@@ -136,6 +136,7 @@ struct packet_sock { + int (*xmit)(struct sk_buff *skb); + struct packet_type prot_hook ____cacheline_aligned_in_smp; + atomic_t tp_drops ____cacheline_aligned_in_smp; ++ unsigned int pkt_type; + }; + + static struct packet_sock *pkt_sk(struct sock *sk) diff --git a/ipq806x/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch b/ipq806x/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch new file mode 100644 index 0000000..02600eb --- /dev/null +++ b/ipq806x/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch @@ -0,0 +1,564 @@ +From: Pablo Neira Ayuso +Date: Thu, 11 Jan 2018 16:32:00 +0100 +Subject: [PATCH] netfilter: nf_flow_table: add hardware offload support + +This patch adds the infrastructure to offload flows to hardware, in case +the nic/switch comes with built-in flow tables capabilities. + +If the hardware comes with no hardware flow tables or they have +limitations in terms of features, the existing infrastructure falls back +to the software flow table implementation. + +The software flow table garbage collector skips entries that resides in +the hardware, so the hardware will be responsible for releasing this +flow table entry too via flow_offload_dead(). + +Hardware configuration, either to add or to delete entries, is done from +the hardware offload workqueue, to ensure this is done from user context +given that we may sleep when grabbing the mdio mutex. + +Signed-off-by: Pablo Neira Ayuso +--- + create mode 100644 net/netfilter/nf_flow_table_hw.c + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -928,6 +928,13 @@ struct devlink; + struct tlsdev_ops; + + ++struct flow_offload; ++ ++enum flow_offload_type { ++ FLOW_OFFLOAD_ADD = 0, ++ FLOW_OFFLOAD_DEL, ++}; ++ + /* + * This structure defines the management hooks for network devices. + * The following hooks can be defined; unless noted otherwise, they are +@@ -1160,6 +1167,10 @@ struct tlsdev_ops; + * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh, + * u16 flags); + * ++ * int (*ndo_flow_offload)(enum flow_offload_type type, ++ * struct flow_offload *flow); ++ * Adds/deletes flow entry to/from net device flowtable. ++ * + * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier); + * Called to change device carrier. Soft-devices (like dummy, team, etc) + * which do not represent real hardware may define this to allow their +@@ -1407,6 +1418,8 @@ struct net_device_ops { + int (*ndo_bridge_dellink)(struct net_device *dev, + struct nlmsghdr *nlh, + u16 flags); ++ int (*ndo_flow_offload)(enum flow_offload_type type, ++ struct flow_offload *flow); + int (*ndo_change_carrier)(struct net_device *dev, + bool new_carrier); + int (*ndo_get_phys_port_id)(struct net_device *dev, +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -21,11 +21,17 @@ struct nf_flowtable_type { + struct module *owner; + }; + ++enum nf_flowtable_flags { ++ NF_FLOWTABLE_F_HW = 0x1, ++}; ++ + struct nf_flowtable { + struct list_head list; + struct rhashtable rhashtable; + const struct nf_flowtable_type *type; ++ u32 flags; + struct delayed_work gc_work; ++ possible_net_t ft_net; + }; + + enum flow_offload_tuple_dir { +@@ -68,6 +74,7 @@ struct flow_offload_tuple_rhash { + #define FLOW_OFFLOAD_DNAT 0x2 + #define FLOW_OFFLOAD_DYING 0x4 + #define FLOW_OFFLOAD_TEARDOWN 0x8 ++#define FLOW_OFFLOAD_HW 0x10 + + struct flow_offload { + struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX]; +@@ -120,6 +127,22 @@ unsigned int nf_flow_offload_ip_hook(voi + unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state); + ++void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow, ++ struct nf_conn *ct); ++void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow); ++ ++struct nf_flow_table_hw { ++ struct module *owner; ++ void (*add)(struct net *net, struct flow_offload *flow, ++ struct nf_conn *ct); ++ void (*del)(struct net *net, struct flow_offload *flow); ++}; ++ ++int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload); ++void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload); ++ ++extern struct work_struct nf_flow_offload_hw_work; ++ + #define MODULE_ALIAS_NF_FLOWTABLE(family) \ + MODULE_ALIAS("nf-flowtable-" __stringify(family)) + +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1516,6 +1516,7 @@ enum nft_object_attributes { + * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32) + * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32) + * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64) ++ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32) + */ + enum nft_flowtable_attributes { + NFTA_FLOWTABLE_UNSPEC, +@@ -1525,6 +1526,7 @@ enum nft_flowtable_attributes { + NFTA_FLOWTABLE_USE, + NFTA_FLOWTABLE_HANDLE, + NFTA_FLOWTABLE_PAD, ++ NFTA_FLOWTABLE_FLAGS, + __NFTA_FLOWTABLE_MAX + }; + #define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1) +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -711,6 +711,15 @@ config NF_FLOW_TABLE + + To compile it as a module, choose M here. + ++config NF_FLOW_TABLE_HW ++ tristate "Netfilter flow table hardware offload module" ++ depends on NF_FLOW_TABLE ++ help ++ This option adds hardware offload support for the flow table core ++ infrastructure. ++ ++ To compile it as a module, choose M here. ++ + config NETFILTER_XTABLES + tristate "Netfilter Xtables support (required for ip_tables)" + default m if NETFILTER_ADVANCED=n +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -123,6 +123,7 @@ obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_t + nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o + + obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o ++obj-$(CONFIG_NF_FLOW_TABLE_HW) += nf_flow_table_hw.o + + # generic X tables + obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -248,10 +248,16 @@ static inline bool nf_flow_has_expired(c + return nf_flow_timeout_delta(flow->timeout) <= 0; + } + ++static inline bool nf_flow_in_hw(const struct flow_offload *flow) ++{ ++ return flow->flags & FLOW_OFFLOAD_HW; ++} ++ + static void flow_offload_del(struct nf_flowtable *flow_table, + struct flow_offload *flow) + { + struct flow_offload_entry *e; ++ struct net *net = read_pnet(&flow_table->ft_net); + + rhashtable_remove_fast(&flow_table->rhashtable, + &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node, +@@ -271,6 +277,9 @@ static void flow_offload_del(struct nf_f + if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN)) + flow_offload_fixup_ct_state(e->ct); + ++ if (nf_flow_in_hw(flow)) ++ nf_flow_offload_hw_del(net, flow); ++ + flow_offload_free(flow); + } + +@@ -361,6 +370,9 @@ static void nf_flow_offload_gc_step(stru + if (!teardown) + nf_ct_offload_timeout(flow); + ++ if (nf_flow_in_hw(flow) && !teardown) ++ return; ++ + if (nf_flow_has_expired(flow) || teardown) + flow_offload_del(flow_table, flow); + } +@@ -490,10 +502,43 @@ int nf_flow_dnat_port(const struct flow_ + } + EXPORT_SYMBOL_GPL(nf_flow_dnat_port); + ++static const struct nf_flow_table_hw __rcu *nf_flow_table_hw_hook __read_mostly; ++ ++static int nf_flow_offload_hw_init(struct nf_flowtable *flow_table) ++{ ++ const struct nf_flow_table_hw *offload; ++ ++ if (!rcu_access_pointer(nf_flow_table_hw_hook)) ++ request_module("nf-flow-table-hw"); ++ ++ rcu_read_lock(); ++ offload = rcu_dereference(nf_flow_table_hw_hook); ++ if (!offload) ++ goto err_no_hw_offload; ++ ++ if (!try_module_get(offload->owner)) ++ goto err_no_hw_offload; ++ ++ rcu_read_unlock(); ++ ++ return 0; ++ ++err_no_hw_offload: ++ rcu_read_unlock(); ++ ++ return -EOPNOTSUPP; ++} ++ + int nf_flow_table_init(struct nf_flowtable *flowtable) + { + int err; + ++ if (flowtable->flags & NF_FLOWTABLE_F_HW) { ++ err = nf_flow_offload_hw_init(flowtable); ++ if (err) ++ return err; ++ } ++ + INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc); + + err = rhashtable_init(&flowtable->rhashtable, +@@ -534,6 +579,8 @@ static void nf_flow_table_iterate_cleanu + { + nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev); + flush_delayed_work(&flowtable->gc_work); ++ if (flowtable->flags & NF_FLOWTABLE_F_HW) ++ flush_work(&nf_flow_offload_hw_work); + } + + void nf_flow_table_cleanup(struct net_device *dev) +@@ -547,6 +594,26 @@ void nf_flow_table_cleanup(struct net_de + } + EXPORT_SYMBOL_GPL(nf_flow_table_cleanup); + ++struct work_struct nf_flow_offload_hw_work; ++EXPORT_SYMBOL_GPL(nf_flow_offload_hw_work); ++ ++/* Give the hardware workqueue the chance to remove entries from hardware.*/ ++static void nf_flow_offload_hw_free(struct nf_flowtable *flowtable) ++{ ++ const struct nf_flow_table_hw *offload; ++ ++ flush_work(&nf_flow_offload_hw_work); ++ ++ rcu_read_lock(); ++ offload = rcu_dereference(nf_flow_table_hw_hook); ++ if (!offload) { ++ rcu_read_unlock(); ++ return; ++ } ++ module_put(offload->owner); ++ rcu_read_unlock(); ++} ++ + void nf_flow_table_free(struct nf_flowtable *flow_table) + { + mutex_lock(&flowtable_lock); +@@ -556,9 +623,58 @@ void nf_flow_table_free(struct nf_flowta + nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL); + nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, flow_table); + rhashtable_destroy(&flow_table->rhashtable); ++ if (flow_table->flags & NF_FLOWTABLE_F_HW) ++ nf_flow_offload_hw_free(flow_table); + } + EXPORT_SYMBOL_GPL(nf_flow_table_free); + ++/* Must be called from user context. */ ++void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow, ++ struct nf_conn *ct) ++{ ++ const struct nf_flow_table_hw *offload; ++ ++ rcu_read_lock(); ++ offload = rcu_dereference(nf_flow_table_hw_hook); ++ if (offload) ++ offload->add(net, flow, ct); ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL_GPL(nf_flow_offload_hw_add); ++ ++/* Must be called from user context. */ ++void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow) ++{ ++ const struct nf_flow_table_hw *offload; ++ ++ rcu_read_lock(); ++ offload = rcu_dereference(nf_flow_table_hw_hook); ++ if (offload) ++ offload->del(net, flow); ++ rcu_read_unlock(); ++} ++EXPORT_SYMBOL_GPL(nf_flow_offload_hw_del); ++ ++int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload) ++{ ++ if (rcu_access_pointer(nf_flow_table_hw_hook)) ++ return -EBUSY; ++ ++ rcu_assign_pointer(nf_flow_table_hw_hook, offload); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nf_flow_table_hw_register); ++ ++void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload) ++{ ++ WARN_ON(rcu_access_pointer(nf_flow_table_hw_hook) != offload); ++ rcu_assign_pointer(nf_flow_table_hw_hook, NULL); ++ ++ synchronize_rcu(); ++} ++EXPORT_SYMBOL_GPL(nf_flow_table_hw_unregister); ++ + static int nf_flow_table_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) + { +--- /dev/null ++++ b/net/netfilter/nf_flow_table_hw.c +@@ -0,0 +1,169 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static DEFINE_SPINLOCK(flow_offload_hw_pending_list_lock); ++static LIST_HEAD(flow_offload_hw_pending_list); ++ ++static DEFINE_MUTEX(nf_flow_offload_hw_mutex); ++ ++struct flow_offload_hw { ++ struct list_head list; ++ enum flow_offload_type type; ++ struct flow_offload *flow; ++ struct nf_conn *ct; ++ possible_net_t flow_hw_net; ++}; ++ ++static int do_flow_offload_hw(struct net *net, struct flow_offload *flow, ++ int type) ++{ ++ struct net_device *indev; ++ int ret, ifindex; ++ ++ ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx; ++ indev = dev_get_by_index(net, ifindex); ++ if (WARN_ON(!indev)) ++ return 0; ++ ++ mutex_lock(&nf_flow_offload_hw_mutex); ++ ret = indev->netdev_ops->ndo_flow_offload(type, flow); ++ mutex_unlock(&nf_flow_offload_hw_mutex); ++ ++ dev_put(indev); ++ ++ return ret; ++} ++ ++static void flow_offload_hw_work_add(struct flow_offload_hw *offload) ++{ ++ struct net *net; ++ int ret; ++ ++ if (nf_ct_is_dying(offload->ct)) ++ return; ++ ++ net = read_pnet(&offload->flow_hw_net); ++ ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD); ++ if (ret >= 0) ++ offload->flow->flags |= FLOW_OFFLOAD_HW; ++} ++ ++static void flow_offload_hw_work_del(struct flow_offload_hw *offload) ++{ ++ struct net *net = read_pnet(&offload->flow_hw_net); ++ ++ do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL); ++} ++ ++static void flow_offload_hw_work(struct work_struct *work) ++{ ++ struct flow_offload_hw *offload, *next; ++ LIST_HEAD(hw_offload_pending); ++ ++ spin_lock_bh(&flow_offload_hw_pending_list_lock); ++ list_replace_init(&flow_offload_hw_pending_list, &hw_offload_pending); ++ spin_unlock_bh(&flow_offload_hw_pending_list_lock); ++ ++ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) { ++ switch (offload->type) { ++ case FLOW_OFFLOAD_ADD: ++ flow_offload_hw_work_add(offload); ++ break; ++ case FLOW_OFFLOAD_DEL: ++ flow_offload_hw_work_del(offload); ++ break; ++ } ++ if (offload->ct) ++ nf_conntrack_put(&offload->ct->ct_general); ++ list_del(&offload->list); ++ kfree(offload); ++ } ++} ++ ++static void flow_offload_queue_work(struct flow_offload_hw *offload) ++{ ++ spin_lock_bh(&flow_offload_hw_pending_list_lock); ++ list_add_tail(&offload->list, &flow_offload_hw_pending_list); ++ spin_unlock_bh(&flow_offload_hw_pending_list_lock); ++ ++ schedule_work(&nf_flow_offload_hw_work); ++} ++ ++static void flow_offload_hw_add(struct net *net, struct flow_offload *flow, ++ struct nf_conn *ct) ++{ ++ struct flow_offload_hw *offload; ++ ++ offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); ++ if (!offload) ++ return; ++ ++ nf_conntrack_get(&ct->ct_general); ++ offload->type = FLOW_OFFLOAD_ADD; ++ offload->ct = ct; ++ offload->flow = flow; ++ write_pnet(&offload->flow_hw_net, net); ++ ++ flow_offload_queue_work(offload); ++} ++ ++static void flow_offload_hw_del(struct net *net, struct flow_offload *flow) ++{ ++ struct flow_offload_hw *offload; ++ ++ offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); ++ if (!offload) ++ return; ++ ++ offload->type = FLOW_OFFLOAD_DEL; ++ offload->ct = NULL; ++ offload->flow = flow; ++ write_pnet(&offload->flow_hw_net, net); ++ ++ flow_offload_queue_work(offload); ++} ++ ++static const struct nf_flow_table_hw flow_offload_hw = { ++ .add = flow_offload_hw_add, ++ .del = flow_offload_hw_del, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init nf_flow_table_hw_module_init(void) ++{ ++ INIT_WORK(&nf_flow_offload_hw_work, flow_offload_hw_work); ++ nf_flow_table_hw_register(&flow_offload_hw); ++ ++ return 0; ++} ++ ++static void __exit nf_flow_table_hw_module_exit(void) ++{ ++ struct flow_offload_hw *offload, *next; ++ LIST_HEAD(hw_offload_pending); ++ ++ nf_flow_table_hw_unregister(&flow_offload_hw); ++ cancel_work_sync(&nf_flow_offload_hw_work); ++ ++ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) { ++ if (offload->ct) ++ nf_conntrack_put(&offload->ct->ct_general); ++ list_del(&offload->list); ++ kfree(offload); ++ } ++} ++ ++module_init(nf_flow_table_hw_module_init); ++module_exit(nf_flow_table_hw_module_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Pablo Neira Ayuso "); ++MODULE_ALIAS("nf-flow-table-hw"); +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -5743,6 +5743,13 @@ static int nf_tables_flowtable_parse_hoo + if (err < 0) + return err; + ++ for (i = 0; i < n; i++) { ++ if (flowtable->data.flags & NF_FLOWTABLE_F_HW && ++ !dev_array[i]->netdev_ops->ndo_flow_offload) { ++ return -EOPNOTSUPP; ++ } ++ } ++ + ops = kcalloc(n, sizeof(struct nf_hook_ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; +@@ -5873,10 +5880,19 @@ static int nf_tables_newflowtable(struct + } + + flowtable->data.type = type; ++ write_pnet(&flowtable->data.ft_net, net); ++ + err = type->init(&flowtable->data); + if (err < 0) + goto err3; + ++ if (nla[NFTA_FLOWTABLE_FLAGS]) { ++ flowtable->data.flags = ++ ntohl(nla_get_be32(nla[NFTA_FLOWTABLE_FLAGS])); ++ if (flowtable->data.flags & ~NF_FLOWTABLE_F_HW) ++ goto err4; ++ } ++ + err = nf_tables_flowtable_parse_hook(&ctx, nla[NFTA_FLOWTABLE_HOOK], + flowtable); + if (err < 0) +@@ -6002,7 +6018,8 @@ static int nf_tables_fill_flowtable_info + nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) || + nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) || + nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle), +- NFTA_FLOWTABLE_PAD)) ++ NFTA_FLOWTABLE_PAD) || ++ nla_put_be32(skb, NFTA_FLOWTABLE_FLAGS, htonl(flowtable->data.flags))) + goto nla_put_failure; + + nest = nla_nest_start_noflag(skb, NFTA_FLOWTABLE_HOOK); +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -128,6 +128,9 @@ static void nft_flow_offload_eval(const + if (ret < 0) + goto err_flow_add; + ++ if (flowtable->flags & NF_FLOWTABLE_F_HW) ++ nf_flow_offload_hw_add(nft_net(pkt), flow, ct); ++ + dst_release(route.tuple[!dir].dst); + return; + diff --git a/ipq806x/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch b/ipq806x/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch new file mode 100644 index 0000000..9f113c7 --- /dev/null +++ b/ipq806x/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch @@ -0,0 +1,306 @@ +From: Felix Fietkau +Date: Thu, 15 Mar 2018 20:46:31 +0100 +Subject: [PATCH] netfilter: nf_flow_table: support hw offload through + virtual interfaces + +There are hardware offload devices that support offloading VLANs and +PPPoE devices. Additionally, it is useful to be able to offload packets +routed through bridge interfaces as well. +Add support for finding the path to the offload device through these +virtual interfaces, while collecting useful parameters for the offload +device, like VLAN ID/protocol, PPPoE session and Ethernet MAC address. + +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -929,6 +929,7 @@ struct tlsdev_ops; + + + struct flow_offload; ++struct flow_offload_hw_path; + + enum flow_offload_type { + FLOW_OFFLOAD_ADD = 0, +@@ -1167,8 +1168,15 @@ enum flow_offload_type { + * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh, + * u16 flags); + * ++ * int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path); ++ * For virtual devices like bridges, vlan, and pppoe, fill in the ++ * underlying network device that can be used for offloading connections. ++ * Return an error if offloading is not supported. ++ * + * int (*ndo_flow_offload)(enum flow_offload_type type, +- * struct flow_offload *flow); ++ * struct flow_offload *flow, ++ * struct flow_offload_hw_path *src, ++ * struct flow_offload_hw_path *dest); + * Adds/deletes flow entry to/from net device flowtable. + * + * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier); +@@ -1418,8 +1426,11 @@ struct net_device_ops { + int (*ndo_bridge_dellink)(struct net_device *dev, + struct nlmsghdr *nlh, + u16 flags); ++ int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path); + int (*ndo_flow_offload)(enum flow_offload_type type, +- struct flow_offload *flow); ++ struct flow_offload *flow, ++ struct flow_offload_hw_path *src, ++ struct flow_offload_hw_path *dest); + int (*ndo_change_carrier)(struct net_device *dev, + bool new_carrier); + int (*ndo_get_phys_port_id)(struct net_device *dev, +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -85,6 +85,21 @@ struct flow_offload { + }; + }; + ++#define FLOW_OFFLOAD_PATH_ETHERNET BIT(0) ++#define FLOW_OFFLOAD_PATH_VLAN BIT(1) ++#define FLOW_OFFLOAD_PATH_PPPOE BIT(2) ++ ++struct flow_offload_hw_path { ++ struct net_device *dev; ++ u32 flags; ++ ++ u8 eth_src[ETH_ALEN]; ++ u8 eth_dest[ETH_ALEN]; ++ u16 vlan_proto; ++ u16 vlan_id; ++ u16 pppoe_sid; ++}; ++ + #define NF_FLOW_TIMEOUT (30 * HZ) + + struct nf_flow_route { +--- a/net/netfilter/nf_flow_table_hw.c ++++ b/net/netfilter/nf_flow_table_hw.c +@@ -19,48 +19,77 @@ struct flow_offload_hw { + enum flow_offload_type type; + struct flow_offload *flow; + struct nf_conn *ct; +- possible_net_t flow_hw_net; ++ ++ struct flow_offload_hw_path src; ++ struct flow_offload_hw_path dest; + }; + +-static int do_flow_offload_hw(struct net *net, struct flow_offload *flow, +- int type) ++static void flow_offload_check_ethernet(struct flow_offload_tuple *tuple, ++ struct dst_entry *dst, ++ struct flow_offload_hw_path *path) + { +- struct net_device *indev; +- int ret, ifindex; ++ struct net_device *dev = path->dev; ++ struct neighbour *n; + +- ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx; +- indev = dev_get_by_index(net, ifindex); +- if (WARN_ON(!indev)) +- return 0; +- +- mutex_lock(&nf_flow_offload_hw_mutex); +- ret = indev->netdev_ops->ndo_flow_offload(type, flow); +- mutex_unlock(&nf_flow_offload_hw_mutex); ++ if (dev->type != ARPHRD_ETHER) ++ return; + +- dev_put(indev); ++ memcpy(path->eth_src, path->dev->dev_addr, ETH_ALEN); ++ n = dst_neigh_lookup(dst, &tuple->src_v4); ++ if (!n) ++ return; + +- return ret; ++ memcpy(path->eth_dest, n->ha, ETH_ALEN); ++ path->flags |= FLOW_OFFLOAD_PATH_ETHERNET; ++ neigh_release(n); + } + +-static void flow_offload_hw_work_add(struct flow_offload_hw *offload) ++static int flow_offload_check_path(struct net *net, ++ struct flow_offload_tuple *tuple, ++ struct dst_entry *dst, ++ struct flow_offload_hw_path *path) + { +- struct net *net; +- int ret; ++ struct net_device *dev; + +- if (nf_ct_is_dying(offload->ct)) +- return; ++ dev = dev_get_by_index_rcu(net, tuple->iifidx); ++ if (!dev) ++ return -ENOENT; ++ ++ path->dev = dev; ++ flow_offload_check_ethernet(tuple, dst, path); + +- net = read_pnet(&offload->flow_hw_net); +- ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD); +- if (ret >= 0) +- offload->flow->flags |= FLOW_OFFLOAD_HW; ++ if (dev->netdev_ops->ndo_flow_offload_check) ++ return dev->netdev_ops->ndo_flow_offload_check(path); ++ ++ return 0; + } + +-static void flow_offload_hw_work_del(struct flow_offload_hw *offload) ++static int do_flow_offload_hw(struct flow_offload_hw *offload) + { +- struct net *net = read_pnet(&offload->flow_hw_net); ++ struct net_device *src_dev = offload->src.dev; ++ struct net_device *dest_dev = offload->dest.dev; ++ int ret; ++ ++ ret = src_dev->netdev_ops->ndo_flow_offload(offload->type, ++ offload->flow, ++ &offload->src, ++ &offload->dest); ++ ++ /* restore devices in case the driver mangled them */ ++ offload->src.dev = src_dev; ++ offload->dest.dev = dest_dev; + +- do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL); ++ return ret; ++} ++ ++static void flow_offload_hw_free(struct flow_offload_hw *offload) ++{ ++ dev_put(offload->src.dev); ++ dev_put(offload->dest.dev); ++ if (offload->ct) ++ nf_conntrack_put(&offload->ct->ct_general); ++ list_del(&offload->list); ++ kfree(offload); + } + + static void flow_offload_hw_work(struct work_struct *work) +@@ -73,18 +102,22 @@ static void flow_offload_hw_work(struct + spin_unlock_bh(&flow_offload_hw_pending_list_lock); + + list_for_each_entry_safe(offload, next, &hw_offload_pending, list) { ++ mutex_lock(&nf_flow_offload_hw_mutex); + switch (offload->type) { + case FLOW_OFFLOAD_ADD: +- flow_offload_hw_work_add(offload); ++ if (nf_ct_is_dying(offload->ct)) ++ break; ++ ++ if (do_flow_offload_hw(offload) >= 0) ++ offload->flow->flags |= FLOW_OFFLOAD_HW; + break; + case FLOW_OFFLOAD_DEL: +- flow_offload_hw_work_del(offload); ++ do_flow_offload_hw(offload); + break; + } +- if (offload->ct) +- nf_conntrack_put(&offload->ct->ct_general); +- list_del(&offload->list); +- kfree(offload); ++ mutex_unlock(&nf_flow_offload_hw_mutex); ++ ++ flow_offload_hw_free(offload); + } + } + +@@ -97,20 +130,56 @@ static void flow_offload_queue_work(stru + schedule_work(&nf_flow_offload_hw_work); + } + ++static struct flow_offload_hw * ++flow_offload_hw_prepare(struct net *net, struct flow_offload *flow) ++{ ++ struct flow_offload_hw_path src = {}; ++ struct flow_offload_hw_path dest = {}; ++ struct flow_offload_tuple *tuple_s, *tuple_d; ++ struct flow_offload_hw *offload = NULL; ++ ++ rcu_read_lock_bh(); ++ ++ tuple_s = &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple; ++ tuple_d = &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple; ++ ++ if (flow_offload_check_path(net, tuple_s, tuple_d->dst_cache, &src)) ++ goto out; ++ ++ if (flow_offload_check_path(net, tuple_d, tuple_s->dst_cache, &dest)) ++ goto out; ++ ++ if (!src.dev->netdev_ops->ndo_flow_offload) ++ goto out; ++ ++ offload = kzalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); ++ if (!offload) ++ goto out; ++ ++ dev_hold(src.dev); ++ dev_hold(dest.dev); ++ offload->src = src; ++ offload->dest = dest; ++ offload->flow = flow; ++ ++out: ++ rcu_read_unlock_bh(); ++ ++ return offload; ++} ++ + static void flow_offload_hw_add(struct net *net, struct flow_offload *flow, + struct nf_conn *ct) + { + struct flow_offload_hw *offload; + +- offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); ++ offload = flow_offload_hw_prepare(net, flow); + if (!offload) + return; + + nf_conntrack_get(&ct->ct_general); + offload->type = FLOW_OFFLOAD_ADD; + offload->ct = ct; +- offload->flow = flow; +- write_pnet(&offload->flow_hw_net, net); + + flow_offload_queue_work(offload); + } +@@ -119,14 +188,11 @@ static void flow_offload_hw_del(struct n + { + struct flow_offload_hw *offload; + +- offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC); ++ offload = flow_offload_hw_prepare(net, flow); + if (!offload) + return; + + offload->type = FLOW_OFFLOAD_DEL; +- offload->ct = NULL; +- offload->flow = flow; +- write_pnet(&offload->flow_hw_net, net); + + flow_offload_queue_work(offload); + } +@@ -153,12 +219,8 @@ static void __exit nf_flow_table_hw_modu + nf_flow_table_hw_unregister(&flow_offload_hw); + cancel_work_sync(&nf_flow_offload_hw_work); + +- list_for_each_entry_safe(offload, next, &hw_offload_pending, list) { +- if (offload->ct) +- nf_conntrack_put(&offload->ct->ct_general); +- list_del(&offload->list); +- kfree(offload); +- } ++ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) ++ flow_offload_hw_free(offload); + } + + module_init(nf_flow_table_hw_module_init); diff --git a/ipq806x/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch b/ipq806x/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch new file mode 100644 index 0000000..d67cad7 --- /dev/null +++ b/ipq806x/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch @@ -0,0 +1,61 @@ +From: Felix Fietkau +Date: Thu, 15 Mar 2018 20:49:58 +0100 +Subject: [PATCH] net: 8021q: support hardware flow table offload + +Add the VLAN ID and protocol information + +Signed-off-by: Felix Fietkau +--- + +--- a/net/8021q/vlan_dev.c ++++ b/net/8021q/vlan_dev.c +@@ -27,6 +27,11 @@ + #include + #include + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++#include ++#include ++#endif ++ + #include "vlan.h" + #include "vlanproc.h" + #include +@@ -744,6 +749,27 @@ static int vlan_dev_get_iflink(const str + return real_dev->ifindex; + } + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++static int vlan_dev_flow_offload_check(struct flow_offload_hw_path *path) ++{ ++ struct net_device *dev = path->dev; ++ struct vlan_dev_priv *vlan = vlan_dev_priv(dev); ++ ++ if (path->flags & FLOW_OFFLOAD_PATH_VLAN) ++ return -EEXIST; ++ ++ path->flags |= FLOW_OFFLOAD_PATH_VLAN; ++ path->vlan_proto = vlan->vlan_proto; ++ path->vlan_id = vlan->vlan_id; ++ path->dev = vlan->real_dev; ++ ++ if (vlan->real_dev->netdev_ops->ndo_flow_offload_check) ++ return vlan->real_dev->netdev_ops->ndo_flow_offload_check(path); ++ ++ return 0; ++} ++#endif /* CONFIG_NF_FLOW_TABLE */ ++ + static const struct ethtool_ops vlan_ethtool_ops = { + .get_link_ksettings = vlan_ethtool_get_link_ksettings, + .get_drvinfo = vlan_ethtool_get_drvinfo, +@@ -782,6 +808,9 @@ static const struct net_device_ops vlan_ + #endif + .ndo_fix_features = vlan_dev_fix_features, + .ndo_get_iflink = vlan_dev_get_iflink, ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++ .ndo_flow_offload_check = vlan_dev_flow_offload_check, ++#endif + }; + + static void vlan_dev_free(struct net_device *dev) diff --git a/ipq806x/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch b/ipq806x/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch new file mode 100644 index 0000000..d47482d --- /dev/null +++ b/ipq806x/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch @@ -0,0 +1,61 @@ +From: Felix Fietkau +Date: Thu, 15 Mar 2018 20:50:37 +0100 +Subject: [PATCH] net: bridge: support hardware flow table offload + +Look up the real device and pass it on + +Signed-off-by: Felix Fietkau +--- + +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -14,6 +14,10 @@ + #include + #include + #include ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++#include ++#include ++#endif + + #include + #include "br_private.h" +@@ -382,6 +386,28 @@ static const struct ethtool_ops br_ethto + .get_link = ethtool_op_get_link, + }; + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++static int br_flow_offload_check(struct flow_offload_hw_path *path) ++{ ++ struct net_device *dev = path->dev; ++ struct net_bridge *br = netdev_priv(dev); ++ struct net_bridge_fdb_entry *dst; ++ ++ if (!(path->flags & FLOW_OFFLOAD_PATH_ETHERNET)) ++ return -EINVAL; ++ ++ dst = br_fdb_find_rcu(br, path->eth_dest, path->vlan_id); ++ if (!dst || !dst->dst) ++ return -ENOENT; ++ ++ path->dev = dst->dst->dev; ++ if (path->dev->netdev_ops->ndo_flow_offload_check) ++ return path->dev->netdev_ops->ndo_flow_offload_check(path); ++ ++ return 0; ++} ++#endif /* CONFIG_NF_FLOW_TABLE */ ++ + static const struct net_device_ops br_netdev_ops = { + .ndo_open = br_dev_open, + .ndo_stop = br_dev_stop, +@@ -410,6 +436,9 @@ static const struct net_device_ops br_ne + .ndo_bridge_setlink = br_setlink, + .ndo_bridge_dellink = br_dellink, + .ndo_features_check = passthru_features_check, ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++ .ndo_flow_offload_check = br_flow_offload_check, ++#endif + }; + + static struct device_type br_type = { diff --git a/ipq806x/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch b/ipq806x/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch new file mode 100644 index 0000000..1eb6a83 --- /dev/null +++ b/ipq806x/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch @@ -0,0 +1,125 @@ +From: Felix Fietkau +Date: Thu, 15 Mar 2018 21:15:00 +0100 +Subject: [PATCH] net: pppoe: support hardware flow table offload + +Pass on the PPPoE session ID and the remote MAC address + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -53,6 +53,11 @@ + #include + #include + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++#include ++#include ++#endif ++ + #define PPP_VERSION "2.4.2" + + /* +@@ -1373,12 +1378,37 @@ static void ppp_dev_priv_destructor(stru + ppp_destroy_interface(ppp); + } + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++static int ppp_flow_offload_check(struct flow_offload_hw_path *path) ++{ ++ struct ppp *ppp = netdev_priv(path->dev); ++ struct ppp_channel *chan; ++ struct channel *pch; ++ ++ if (ppp->flags & SC_MULTILINK) ++ return -EOPNOTSUPP; ++ ++ if (list_empty(&ppp->channels)) ++ return -ENODEV; ++ ++ pch = list_first_entry(&ppp->channels, struct channel, clist); ++ chan = pch->chan; ++ if (!chan->ops->flow_offload_check) ++ return -EOPNOTSUPP; ++ ++ return chan->ops->flow_offload_check(chan, path); ++} ++#endif /* CONFIG_NF_FLOW_TABLE */ ++ + static const struct net_device_ops ppp_netdev_ops = { + .ndo_init = ppp_dev_init, + .ndo_uninit = ppp_dev_uninit, + .ndo_start_xmit = ppp_start_xmit, + .ndo_do_ioctl = ppp_net_ioctl, + .ndo_get_stats64 = ppp_get_stats64, ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++ .ndo_flow_offload_check = ppp_flow_offload_check, ++#endif + }; + + static struct device_type ppp_type = { +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -73,6 +73,11 @@ + #include + #include + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++#include ++#include ++#endif ++ + #include + #include + #include +@@ -974,8 +979,36 @@ static int pppoe_xmit(struct ppp_channel + return __pppoe_xmit(sk, skb); + } + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++static int pppoe_flow_offload_check(struct ppp_channel *chan, ++ struct flow_offload_hw_path *path) ++{ ++ struct sock *sk = (struct sock *)chan->private; ++ struct pppox_sock *po = pppox_sk(sk); ++ struct net_device *dev = po->pppoe_dev; ++ ++ if (sock_flag(sk, SOCK_DEAD) || ++ !(sk->sk_state & PPPOX_CONNECTED) || !dev) ++ return -ENODEV; ++ ++ path->dev = po->pppoe_dev; ++ path->flags |= FLOW_OFFLOAD_PATH_PPPOE; ++ memcpy(path->eth_src, po->pppoe_dev->dev_addr, ETH_ALEN); ++ memcpy(path->eth_dest, po->pppoe_pa.remote, ETH_ALEN); ++ path->pppoe_sid = be16_to_cpu(po->num); ++ ++ if (path->dev->netdev_ops->ndo_flow_offload_check) ++ return path->dev->netdev_ops->ndo_flow_offload_check(path); ++ ++ return 0; ++} ++#endif /* CONFIG_NF_FLOW_TABLE */ ++ + static const struct ppp_channel_ops pppoe_chan_ops = { + .start_xmit = pppoe_xmit, ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++ .flow_offload_check = pppoe_flow_offload_check, ++#endif + }; + + static int pppoe_recvmsg(struct socket *sock, struct msghdr *m, +--- a/include/linux/ppp_channel.h ++++ b/include/linux/ppp_channel.h +@@ -28,6 +28,10 @@ struct ppp_channel_ops { + int (*start_xmit)(struct ppp_channel *, struct sk_buff *); + /* Handle an ioctl call that has come in via /dev/ppp. */ + int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long); ++ ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++ int (*flow_offload_check)(struct ppp_channel *, struct flow_offload_hw_path *); ++#endif + }; + + struct ppp_channel { diff --git a/ipq806x/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch b/ipq806x/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch new file mode 100644 index 0000000..3c44c29 --- /dev/null +++ b/ipq806x/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch @@ -0,0 +1,37 @@ +From: Felix Fietkau +Date: Sun, 25 Mar 2018 21:10:55 +0200 +Subject: [PATCH] netfilter: nf_flow_table: rework hardware offload timeout + handling + +Some offload implementations send keepalive packets + explicit +notifications of TCP FIN/RST packets. In this case it is more convenient +to simply let the driver update flow->timeout handling and use the +regular flow offload gc step. + +For drivers that manage their own lifetime, a separate flag can be set +to avoid gc timeouts. + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -75,6 +75,7 @@ struct flow_offload_tuple_rhash { + #define FLOW_OFFLOAD_DYING 0x4 + #define FLOW_OFFLOAD_TEARDOWN 0x8 + #define FLOW_OFFLOAD_HW 0x10 ++#define FLOW_OFFLOAD_KEEP 0x20 + + struct flow_offload { + struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX]; +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -370,7 +370,7 @@ static void nf_flow_offload_gc_step(stru + if (!teardown) + nf_ct_offload_timeout(flow); + +- if (nf_flow_in_hw(flow) && !teardown) ++ if ((flow->flags & FLOW_OFFLOAD_KEEP) && !teardown) + return; + + if (nf_flow_has_expired(flow) || teardown) diff --git a/ipq806x/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch b/ipq806x/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch new file mode 100644 index 0000000..159ad8a --- /dev/null +++ b/ipq806x/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Date: Fri, 27 Apr 2018 14:42:14 +0200 +Subject: [PATCH] netfilter: nf_flow_table: rework private driver data + +Move the timeout out of the union, since it can be shared between the +driver and the stack. Add a private pointer that the driver can use to +point to its own data structures + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -80,9 +80,10 @@ struct flow_offload_tuple_rhash { + struct flow_offload { + struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX]; + u32 flags; ++ u32 timeout; + union { + /* Your private driver data here. */ +- u32 timeout; ++ void *priv; + }; + }; + diff --git a/ipq806x/pending-5.4/647-net-dsa-support-hardware-flow-table-offload.patch b/ipq806x/pending-5.4/647-net-dsa-support-hardware-flow-table-offload.patch new file mode 100644 index 0000000..91aae5b --- /dev/null +++ b/ipq806x/pending-5.4/647-net-dsa-support-hardware-flow-table-offload.patch @@ -0,0 +1,78 @@ +From: Felix Fietkau +Date: Thu, 17 Sep 2020 18:41:23 +0200 +Subject: [PATCH] net: dsa: support hardware flow table offload + +Look up the master device and the port id + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -90,6 +90,7 @@ struct flow_offload { + #define FLOW_OFFLOAD_PATH_ETHERNET BIT(0) + #define FLOW_OFFLOAD_PATH_VLAN BIT(1) + #define FLOW_OFFLOAD_PATH_PPPOE BIT(2) ++#define FLOW_OFFLOAD_PATH_DSA BIT(3) + + struct flow_offload_hw_path { + struct net_device *dev; +@@ -100,6 +101,7 @@ struct flow_offload_hw_path { + u16 vlan_proto; + u16 vlan_id; + u16 pppoe_sid; ++ u16 dsa_port; + }; + + #define NF_FLOW_TIMEOUT (30 * HZ) +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -19,6 +19,10 @@ + #include + #include + #include ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++#include ++#include ++#endif + + #include "dsa_priv.h" + +@@ -1226,6 +1230,27 @@ static struct devlink_port *dsa_slave_ge + return dp->ds->devlink ? &dp->devlink_port : NULL; + } + ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++static int dsa_flow_offload_check(struct flow_offload_hw_path *path) ++{ ++ struct net_device *dev = path->dev; ++ struct dsa_port *dp; ++ ++ if (!(path->flags & FLOW_OFFLOAD_PATH_ETHERNET)) ++ return -EINVAL; ++ ++ dp = dsa_slave_to_port(dev); ++ path->dsa_port = dp->index; ++ path->dev = dsa_slave_to_master(dev); ++ path->flags |= FLOW_OFFLOAD_PATH_DSA; ++ ++ if (path->dev->netdev_ops->ndo_flow_offload_check) ++ return path->dev->netdev_ops->ndo_flow_offload_check(path); ++ ++ return 0; ++} ++#endif /* CONFIG_NF_FLOW_TABLE */ ++ + static const struct net_device_ops dsa_slave_netdev_ops = { + .ndo_open = dsa_slave_open, + .ndo_stop = dsa_slave_close, +@@ -1250,6 +1275,9 @@ static const struct net_device_ops dsa_s + .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid, + .ndo_get_devlink_port = dsa_slave_get_devlink_port, ++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE) ++ .ndo_flow_offload_check = dsa_flow_offload_check, ++#endif + }; + + static struct device_type dsa_type = { diff --git a/ipq806x/pending-5.4/655-increase_skb_pad.patch b/ipq806x/pending-5.4/655-increase_skb_pad.patch new file mode 100644 index 0000000..e325301 --- /dev/null +++ b/ipq806x/pending-5.4/655-increase_skb_pad.patch @@ -0,0 +1,20 @@ +From: Felix Fietkau +Subject: kernel: add a few patches for avoiding unnecessary skb reallocations - significantly improves ethernet<->wireless performance + +lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd +Signed-off-by: Felix Fietkau +--- + include/linux/skbuff.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2650,7 +2650,7 @@ static inline int pskb_network_may_pull( + * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) + */ + #ifndef NET_SKB_PAD +-#define NET_SKB_PAD max(32, L1_CACHE_BYTES) ++#define NET_SKB_PAD max(64, L1_CACHE_BYTES) + #endif + + int ___pskb_trim(struct sk_buff *skb, unsigned int len); diff --git a/ipq806x/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/ipq806x/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch new file mode 100644 index 0000000..39f7af2 --- /dev/null +++ b/ipq806x/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch @@ -0,0 +1,501 @@ +From: Steven Barth +Subject: Add support for MAP-E FMRs (mesh mode) + +MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication +between MAP CEs (mesh mode) without the need to forward such data to a +border relay. This is similar to how 6rd works but for IPv4 over IPv6. + +Signed-off-by: Steven Barth +--- + include/net/ip6_tunnel.h | 13 ++ + include/uapi/linux/if_tunnel.h | 13 ++ + net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 291 insertions(+), 11 deletions(-) + +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -18,6 +18,18 @@ + /* determine capability on a per-packet basis */ + #define IP6_TNL_F_CAP_PER_PACKET 0x40000 + ++/* IPv6 tunnel FMR */ ++struct __ip6_tnl_fmr { ++ struct __ip6_tnl_fmr *next; /* next fmr in list */ ++ struct in6_addr ip6_prefix; ++ struct in_addr ip4_prefix; ++ ++ __u8 ip6_prefix_len; ++ __u8 ip4_prefix_len; ++ __u8 ea_len; ++ __u8 offset; ++}; ++ + struct __ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ +@@ -29,6 +41,7 @@ struct __ip6_tnl_parm { + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ ++ struct __ip6_tnl_fmr *fmrs; /* FMRs */ + + __be16 i_flags; + __be16 o_flags; +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -77,10 +77,23 @@ enum { + IFLA_IPTUN_ENCAP_DPORT, + IFLA_IPTUN_COLLECT_METADATA, + IFLA_IPTUN_FWMARK, ++ IFLA_IPTUN_FMRS, + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) + ++enum { ++ IFLA_IPTUN_FMR_UNSPEC, ++ IFLA_IPTUN_FMR_IP6_PREFIX, ++ IFLA_IPTUN_FMR_IP4_PREFIX, ++ IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ++ IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ++ IFLA_IPTUN_FMR_EA_LEN, ++ IFLA_IPTUN_FMR_OFFSET, ++ __IFLA_IPTUN_FMR_MAX, ++}; ++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1) ++ + enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -11,6 +11,9 @@ + * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c + * + * RFC 2473 ++ * ++ * Changes: ++ * Steven Barth : MAP-E FMR support + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -67,9 +70,9 @@ static bool log_ecn_error = true; + module_param(log_ecn_error, bool, 0644); + MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); + +-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) ++static u32 HASH(const struct in6_addr *addr) + { +- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); ++ u32 hash = ipv6_addr_hash(addr); + + return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT); + } +@@ -136,20 +139,29 @@ static struct net_device_stats *ip6_get_ + static struct ip6_tnl * + ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) + { +- unsigned int hash = HASH(remote, local); ++ unsigned int hash = HASH(local); + struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct in6_addr any; ++ struct __ip6_tnl_fmr *fmr; + + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { +- if (ipv6_addr_equal(local, &t->parms.laddr) && +- ipv6_addr_equal(remote, &t->parms.raddr) && +- (t->dev->flags & IFF_UP)) ++ if (!ipv6_addr_equal(local, &t->parms.laddr) || ++ !(t->dev->flags & IFF_UP)) ++ continue; ++ ++ if (ipv6_addr_equal(remote, &t->parms.raddr)) + return t; ++ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ if (ipv6_prefix_equal(remote, &fmr->ip6_prefix, ++ fmr->ip6_prefix_len)) ++ return t; ++ } + } + + memset(&any, 0, sizeof(any)); +- hash = HASH(&any, local); ++ hash = HASH(local); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && + ipv6_addr_any(&t->parms.raddr) && +@@ -157,7 +169,7 @@ ip6_tnl_lookup(struct net *net, const st + return t; + } + +- hash = HASH(remote, &any); ++ hash = HASH(&any); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && + ipv6_addr_any(&t->parms.laddr) && +@@ -197,7 +209,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; +- h = HASH(remote, local); ++ h = HASH(local); + } + return &ip6n->tnls[prio][h]; + } +@@ -377,6 +389,12 @@ ip6_tnl_dev_uninit(struct net_device *de + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ + if (dev == ip6n->fb_tnl_dev) + RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); + else +@@ -766,6 +784,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, + } + EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); + ++/** ++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR ++ * @dest: destination IPv6 address buffer ++ * @skb: received socket buffer ++ * @fmr: MAP FMR ++ * @xmit: Calculate for xmit or rcv ++ **/ ++static void ip4ip6_fmr_calc(struct in6_addr *dest, ++ const struct iphdr *iph, const uint8_t *end, ++ const struct __ip6_tnl_fmr *fmr, bool xmit) ++{ ++ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len); ++ u8 *portp = NULL; ++ bool use_dest_addr; ++ const struct iphdr *dsth = iph; ++ ++ if ((u8*)dsth >= end) ++ return; ++ ++ /* find significant IP header */ ++ if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ if (ih && ((u8*)&ih[1]) <= end && ( ++ ih->type == ICMP_DEST_UNREACH || ++ ih->type == ICMP_SOURCE_QUENCH || ++ ih->type == ICMP_TIME_EXCEEDED || ++ ih->type == ICMP_PARAMETERPROB || ++ ih->type == ICMP_REDIRECT)) ++ dsth = (const struct iphdr*)&ih[1]; ++ } ++ ++ /* in xmit-path use dest port by default and source port only if ++ this is an ICMP reply to something else; vice versa in rcv-path */ ++ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph); ++ ++ /* get dst port */ ++ if (((u8*)&dsth[1]) <= end && ( ++ dsth->protocol == IPPROTO_UDP || ++ dsth->protocol == IPPROTO_TCP || ++ dsth->protocol == IPPROTO_SCTP || ++ dsth->protocol == IPPROTO_DCCP)) { ++ /* for UDP, TCP, SCTP and DCCP source and dest port ++ follow IPv4 header directly */ ++ portp = ((u8*)dsth) + dsth->ihl * 4; ++ ++ if (use_dest_addr) ++ portp += sizeof(u16); ++ } else if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ ++ /* use icmp identifier as port */ ++ if (((u8*)&ih) <= end && ( ++ (use_dest_addr && ( ++ ih->type == ICMP_ECHOREPLY || ++ ih->type == ICMP_TIMESTAMPREPLY || ++ ih->type == ICMP_INFO_REPLY || ++ ih->type == ICMP_ADDRESSREPLY)) || ++ (!use_dest_addr && ( ++ ih->type == ICMP_ECHO || ++ ih->type == ICMP_TIMESTAMP || ++ ih->type == ICMP_INFO_REQUEST || ++ ih->type == ICMP_ADDRESS) ++ ))) ++ portp = (u8*)&ih->un.echo.id; ++ } ++ ++ if ((portp && &portp[2] <= end) || psidlen == 0) { ++ int frombyte = fmr->ip6_prefix_len / 8; ++ int fromrem = fmr->ip6_prefix_len % 8; ++ int bytes = sizeof(struct in6_addr) - frombyte; ++ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr; ++ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len); ++ u64 t = 0; ++ ++ /* extract PSID from port and add it to eabits */ ++ u16 psidbits = 0; ++ if (psidlen > 0) { ++ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]); ++ psidbits >>= 16 - psidlen - fmr->offset; ++ psidbits = (u16)(psidbits << (16 - psidlen)); ++ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen)); ++ } ++ ++ /* rewrite destination address */ ++ *dest = fmr->ip6_prefix; ++ memcpy(&dest->s6_addr[10], addr, sizeof(*addr)); ++ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen)); ++ ++ if (bytes > sizeof(u64)) ++ bytes = sizeof(u64); ++ ++ /* insert eabits */ ++ memcpy(&t, &dest->s6_addr[frombyte], bytes); ++ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1) ++ << (64 - fmr->ea_len - fromrem)); ++ t = cpu_to_be64(t | (eabits >> fromrem)); ++ memcpy(&dest->s6_addr[frombyte], &t, bytes); ++ } ++} ++ ++ + static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, + const struct tnl_ptk_info *tpi, + struct metadata_dst *tun_dst, +@@ -818,6 +937,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl + skb_reset_network_header(skb); + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + ++ if (tpi->proto == htons(ETH_P_IP) && tunnel->parms.fmrs && ++ !ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) { ++ /* Packet didn't come from BR, so lookup FMR */ ++ struct __ip6_tnl_fmr *fmr; ++ struct in6_addr expected = tunnel->parms.raddr; ++ for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next) ++ if (ipv6_prefix_equal(&ipv6h->saddr, ++ &fmr->ip6_prefix, fmr->ip6_prefix_len)) ++ break; ++ ++ /* Check that IPv6 matches IPv4 source to prevent spoofing */ ++ if (fmr) ++ ip4ip6_fmr_calc(&expected, ip_hdr(skb), ++ skb_tail_pointer(skb), fmr, false); ++ ++ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) { ++ rcu_read_unlock(); ++ goto drop; ++ } ++ } ++ + __skb_tunnel_rx(skb, tunnel->dev, tunnel->net); + + err = dscp_ecn_decapsulate(tunnel, ipv6h, skb); +@@ -958,6 +1098,7 @@ static void init_tel_txopt(struct ipv6_t + opt->ops.opt_nflen = 8; + } + ++ + /** + * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own + * @t: the outgoing tunnel device +@@ -1310,6 +1451,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str + { + struct ip6_tnl *t = netdev_priv(dev); + struct ipv6hdr *ipv6h; ++ struct __ip6_tnl_fmr *fmr; + int encap_limit = -1; + __u16 offset; + struct flowi6 fl6; +@@ -1375,6 +1517,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h)); + ++ /* try to find matching FMR */ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ unsigned mshift = 32 - fmr->ip4_prefix_len; ++ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift == ++ ntohl(ip_hdr(skb)->daddr) >> mshift) ++ break; ++ } ++ ++ /* change dstaddr according to FMR */ ++ if (fmr) ++ ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true); ++ + if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) + return -1; + +@@ -1504,6 +1658,14 @@ ip6_tnl_change(struct ip6_tnl *t, const + t->parms.link = p->link; + t->parms.proto = p->proto; + t->parms.fwmark = p->fwmark; ++ ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ t->parms.fmrs = p->fmrs; ++ + dst_cache_reset(&t->dst_cache); + ip6_tnl_link_config(t); + return 0; +@@ -1542,6 +1704,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_ + p->flowinfo = u->flowinfo; + p->link = u->link; + p->proto = u->proto; ++ p->fmrs = NULL; + memcpy(p->name, u->name, sizeof(u->name)); + } + +@@ -1926,6 +2089,15 @@ static int ip6_tnl_validate(struct nlatt + return 0; + } + ++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = { ++ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) }, ++ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 } ++}; ++ + static void ip6_tnl_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) + { +@@ -1963,6 +2135,46 @@ static void ip6_tnl_netlink_parms(struct + + if (data[IFLA_IPTUN_FWMARK]) + parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); ++ ++ if (data[IFLA_IPTUN_FMRS]) { ++ unsigned rem; ++ struct nlattr *fmr; ++ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) { ++ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c; ++ struct __ip6_tnl_fmr *nfmr; ++ ++ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX, ++ fmr, ip6_tnl_fmr_policy, NULL); ++ ++ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL))) ++ continue; ++ ++ nfmr->offset = 6; ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX])) ++ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX], ++ sizeof(nfmr->ip6_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX])) ++ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX], ++ sizeof(nfmr->ip4_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN])) ++ nfmr->ip6_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN])) ++ nfmr->ip4_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN])) ++ nfmr->ea_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET])) ++ nfmr->offset = nla_get_u8(c); ++ ++ nfmr->next = parms->fmrs; ++ parms->fmrs = nfmr; ++ } ++ } + } + + static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[], +@@ -2078,6 +2290,12 @@ static void ip6_tnl_dellink(struct net_d + + static size_t ip6_tnl_get_size(const struct net_device *dev) + { ++ const struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *c; ++ int fmrs = 0; ++ for (c = t->parms.fmrs; c; c = c->next) ++ ++fmrs; ++ + return + /* IFLA_IPTUN_LINK */ + nla_total_size(4) + +@@ -2107,6 +2325,24 @@ static size_t ip6_tnl_get_size(const str + nla_total_size(0) + + /* IFLA_IPTUN_FWMARK */ + nla_total_size(4) + ++ /* IFLA_IPTUN_FMRS */ ++ nla_total_size(0) + ++ ( ++ /* nest */ ++ nla_total_size(0) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX */ ++ nla_total_size(sizeof(struct in6_addr)) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX */ ++ nla_total_size(sizeof(struct in_addr)) + ++ /* IFLA_IPTUN_FMR_EA_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_OFFSET */ ++ nla_total_size(1) ++ ) * fmrs + + 0; + } + +@@ -2114,6 +2350,9 @@ static int ip6_tnl_fill_info(struct sk_b + { + struct ip6_tnl *tunnel = netdev_priv(dev); + struct __ip6_tnl_parm *parm = &tunnel->parms; ++ struct __ip6_tnl_fmr *c; ++ int fmrcnt = 0; ++ struct nlattr *fmrs; + + if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || + nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) || +@@ -2123,9 +2362,27 @@ static int ip6_tnl_fill_info(struct sk_b + nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || + nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || + nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || +- nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark)) ++ nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) || ++ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS))) + goto nla_put_failure; + ++ for (c = parm->fmrs; c; c = c->next) { ++ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt); ++ if (!fmr || ++ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX, ++ sizeof(c->ip6_prefix), &c->ip6_prefix) || ++ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX, ++ sizeof(c->ip4_prefix), &c->ip4_prefix) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset)) ++ goto nla_put_failure; ++ ++ nla_nest_end(skb, fmr); ++ } ++ nla_nest_end(skb, fmrs); ++ + if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) || +@@ -2165,6 +2422,7 @@ static const struct nla_policy ip6_tnl_p + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, + [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, + [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, ++ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ip6_link_ops __read_mostly = { diff --git a/ipq806x/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/ipq806x/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 0000000..06227cf --- /dev/null +++ b/ipq806x/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,263 @@ +From: Jonas Gorski +Subject: ipv6: allow rejecting with "source address failed policy" + +RFC6204 L-14 requires rejecting traffic from invalid addresses with +ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/ +egress policy) on the LAN side, so add an appropriate rule for that. + +Signed-off-by: Jonas Gorski +--- + include/net/netns/ipv6.h | 1 + + include/uapi/linux/fib_rules.h | 4 +++ + include/uapi/linux/rtnetlink.h | 1 + + net/ipv4/fib_semantics.c | 4 +++ + net/ipv4/fib_trie.c | 1 + + net/ipv4/ipmr.c | 1 + + net/ipv6/fib6_rules.c | 4 +++ + net/ipv6/ip6mr.c | 2 ++ + net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++- + 9 files changed, 75 insertions(+), 1 deletion(-) + +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -84,6 +84,7 @@ struct netns_ipv6 { + unsigned int fib6_rules_require_fldissect; + bool fib6_has_custom_rules; + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_policy_failed_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -82,6 +82,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_POLICY_FAILED, /* Drop with EACCES */ + __FR_ACT_MAX, + }; + +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -235,6 +235,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_POLICY_FAILED, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -141,6 +141,10 @@ const struct fib_prop fib_props[RTN_MAX + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_POLICY_FAILED] = { ++ .error = -EACCES, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2596,6 +2596,7 @@ static const char *const rtn_type_names[ + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_POLICY_FAILED] = "POLICY_FAILED", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -173,6 +173,7 @@ static int ipmr_rule_action(struct fib_r + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_POLICY_FAILED: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -216,6 +216,10 @@ static int __fib6_rule_action(struct fib + err = -EACCES; + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_POLICY_FAILED: ++ err = -EACCES; ++ rt = net->ipv6.ip6_policy_failed_entry; ++ goto discard_pkt; + } + + tb_id = fib_rule_get_table(rule, arg); +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -161,6 +161,8 @@ static int ip6mr_rule_action(struct fib_ + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_POLICY_FAILED: ++ return -EACCES; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -94,6 +94,8 @@ static int ip6_pkt_discard(struct sk_bu + static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); + static int ip6_pkt_prohibit(struct sk_buff *skb); + static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb); ++static int ip6_pkt_policy_failed(struct sk_buff *skb); ++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb); + static void ip6_link_failure(struct sk_buff *skb); + static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu, +@@ -327,6 +329,18 @@ static const struct rt6_info ip6_prohibi + .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), + }; + ++static const struct rt6_info ip6_policy_failed_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EACCES, ++ .input = ip6_pkt_policy_failed, ++ .output = ip6_pkt_policy_failed_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1048,6 +1062,7 @@ static const int fib6_prop[RTN_MAX + 1] + [RTN_BLACKHOLE] = -EINVAL, + [RTN_UNREACHABLE] = -EHOSTUNREACH, + [RTN_PROHIBIT] = -EACCES, ++ [RTN_POLICY_FAILED] = -EACCES, + [RTN_THROW] = -EAGAIN, + [RTN_NAT] = -EINVAL, + [RTN_XRESOLVE] = -EINVAL, +@@ -1085,6 +1100,10 @@ static void ip6_rt_init_dst_reject(struc + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; + break; ++ case RTN_POLICY_FAILED: ++ rt->dst.output = ip6_pkt_policy_failed_out; ++ rt->dst.input = ip6_pkt_policy_failed; ++ break; + case RTN_THROW: + case RTN_UNREACHABLE: + default: +@@ -4434,6 +4453,17 @@ static int ip6_pkt_prohibit_out(struct n + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_policy_failed(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES); ++} ++ + /* + * Allocate a dst for local (unicast / anycast) address. + */ +@@ -4914,7 +4944,8 @@ static int rtm_to_fib6_config(struct sk_ + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_POLICY_FAILED) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -6037,6 +6068,8 @@ static int ip6_route_dev_notify(struct n + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_policy_failed_entry->dst.dev = dev; ++ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -6048,6 +6081,7 @@ static int ip6_route_dev_notify(struct n + in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); ++ in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev); + in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); + #endif + } +@@ -6240,6 +6274,8 @@ static int __net_init ip6_route_net_init + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.fib6_has_custom_rules = false; ++ ++ + net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, + sizeof(*net->ipv6.ip6_prohibit_entry), + GFP_KERNEL); +@@ -6250,11 +6286,21 @@ static int __net_init ip6_route_net_init + ip6_template_metrics, true); + INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->rt6i_uncached); + ++ net->ipv6.ip6_policy_failed_entry = ++ kmemdup(&ip6_policy_failed_entry_template, ++ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_policy_failed_entry) ++ goto out_ip6_prohibit_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst, ++ ip6_template_metrics, true); ++ INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->rt6i_uncached); ++ + net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, + sizeof(*net->ipv6.ip6_blk_hole_entry), + GFP_KERNEL); + if (!net->ipv6.ip6_blk_hole_entry) +- goto out_ip6_prohibit_entry; ++ goto out_ip6_policy_failed_entry; + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); +@@ -6278,6 +6324,8 @@ out: + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_policy_failed_entry: ++ kfree(net->ipv6.ip6_policy_failed_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -6297,6 +6345,7 @@ static void __net_exit ip6_route_net_exi + kfree(net->ipv6.ip6_null_entry); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); ++ kfree(net->ipv6.ip6_policy_failed_entry); + kfree(net->ipv6.ip6_blk_hole_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); +@@ -6374,6 +6423,9 @@ void __init ip6_route_init_special_entri + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + } + diff --git a/ipq806x/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/ipq806x/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch new file mode 100644 index 0000000..a92d8ec --- /dev/null +++ b/ipq806x/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch @@ -0,0 +1,50 @@ +From: Jonas Gorski +Subject: net: provide defines for _POLICY_FAILED until all code is updated + +Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination +unreachable, conflicting with our name. + +Add appropriate defines to allow our code to build with the new +name until we have updated our local patches for older kernels +and userspace packages. + +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/fib_rules.h | 2 ++ + include/uapi/linux/icmpv6.h | 2 ++ + include/uapi/linux/rtnetlink.h | 2 ++ + 3 files changed, 6 insertions(+) + +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -89,6 +89,8 @@ enum { + __FR_ACT_MAX, + }; + ++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED ++ + #define FR_ACT_MAX (__FR_ACT_MAX - 1) + + #endif +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -125,6 +125,8 @@ struct icmp6hdr { + #define ICMPV6_POLICY_FAIL 5 + #define ICMPV6_REJECT_ROUTE 6 + ++#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL ++ + /* + * Codes for Time Exceeded + */ +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -239,6 +239,8 @@ enum { + __RTN_MAX + }; + ++#define RTN_FAILED_POLICY RTN_POLICY_FAILED ++ + #define RTN_MAX (__RTN_MAX - 1) + + diff --git a/ipq806x/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/ipq806x/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch new file mode 100644 index 0000000..e054086 --- /dev/null +++ b/ipq806x/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -0,0 +1,149 @@ +From: Felix Fietkau +Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses + +Signed-off-by: Felix Fietkau +--- + include/linux/netdevice.h | 2 ++ + include/linux/skbuff.h | 3 ++- + net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ + net/ethernet/eth.c | 18 +++++++++++++++++- + 4 files changed, 69 insertions(+), 2 deletions(-) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1931,6 +1931,8 @@ struct net_device { + struct netdev_hw_addr_list mc; + struct netdev_hw_addr_list dev_addrs; + ++ unsigned char local_addr_mask[MAX_ADDR_LEN]; ++ + #ifdef CONFIG_SYSFS + struct kset *queues_kset; + #endif +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -824,6 +824,7 @@ struct sk_buff { + #ifdef CONFIG_TLS_DEVICE + __u8 decrypted:1; + #endif ++ __u8 gro_skip:1; + + #ifdef CONFIG_NET_SCHED + __u16 tc_index; /* traffic control index */ +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -5495,6 +5495,9 @@ static enum gro_result dev_gro_receive(s + int same_flow; + int grow; + ++ if (skb->gro_skip) ++ goto normal; ++ + if (netif_elide_gro(skb->dev)) + goto normal; + +@@ -7297,6 +7300,48 @@ static void __netdev_adjacent_dev_unlink + &upper_dev->adj_list.lower); + } + ++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr, ++ struct net_device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < dev->addr_len; i++) ++ mask[i] |= addr[i] ^ dev->dev_addr[i]; ++} ++ ++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev, ++ struct net_device *lower) ++{ ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ netdev_for_each_upper_dev_rcu(dev, cur, iter) { ++ __netdev_addr_mask(mask, cur->dev_addr, lower); ++ __netdev_upper_mask(mask, cur, lower); ++ } ++} ++ ++static void __netdev_update_addr_mask(struct net_device *dev) ++{ ++ unsigned char mask[MAX_ADDR_LEN]; ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ memset(mask, 0, sizeof(mask)); ++ __netdev_upper_mask(mask, dev, dev); ++ memcpy(dev->local_addr_mask, mask, dev->addr_len); ++ ++ netdev_for_each_lower_dev(dev, cur, iter) ++ __netdev_update_addr_mask(cur); ++} ++ ++static void netdev_update_addr_mask(struct net_device *dev) ++{ ++ rcu_read_lock(); ++ __netdev_update_addr_mask(dev); ++ rcu_read_unlock(); ++} ++ + static int __netdev_upper_dev_link(struct net_device *dev, + struct net_device *upper_dev, bool master, + void *upper_priv, void *upper_info, +@@ -7347,6 +7392,7 @@ static int __netdev_upper_dev_link(struc + if (ret) + return ret; + ++ netdev_update_addr_mask(dev); + ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, + &changeupper_info.info); + ret = notifier_to_errno(ret); +@@ -7440,6 +7486,7 @@ void netdev_upper_dev_unlink(struct net_ + + __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, + &changeupper_info.info); + +@@ -8170,6 +8217,7 @@ int dev_set_mac_address(struct net_devic + if (err) + return err; + dev->addr_assign_type = NET_ADDR_SET; ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + add_device_randomness(dev->dev_addr, dev->addr_len); + return 0; +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -143,6 +143,18 @@ u32 eth_get_headlen(const struct net_dev + } + EXPORT_SYMBOL(eth_get_headlen); + ++static inline bool ++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask) ++{ ++ const u16 *a1 = addr1; ++ const u16 *a2 = addr2; ++ const u16 *m = mask; ++ ++ return (((a1[0] ^ a2[0]) & ~m[0]) | ++ ((a1[1] ^ a2[1]) & ~m[1]) | ++ ((a1[2] ^ a2[2]) & ~m[2])); ++} ++ + /** + * eth_type_trans - determine the packet's protocol ID. + * @skb: received socket data +@@ -174,6 +186,10 @@ __be16 eth_type_trans(struct sk_buff *sk + } else { + skb->pkt_type = PACKET_OTHERHOST; + } ++ ++ if (eth_check_local_mask(eth->h_dest, dev->dev_addr, ++ dev->local_addr_mask)) ++ skb->gro_skip = 1; + } + + /* diff --git a/ipq806x/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch b/ipq806x/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch new file mode 100644 index 0000000..b02febe --- /dev/null +++ b/ipq806x/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch @@ -0,0 +1,135 @@ +From: John Crispin +Subject: NET: add mtd-mac-address support to of_get_mac_address() + +Many embedded devices have information such as mac addresses stored inside mtd +devices. This patch allows us to add a property inside a node describing a +network interface. The new property points at a mtd partition with an offset +where the mac address can be found. + +Signed-off-by: John Crispin +Signed-off-by: Felix Fietkau +--- + drivers/of/of_net.c | 37 +++++++++++++++++++++++++++++++++++++ + include/linux/of_net.h | 1 + + 2 files changed, 38 insertions(+) + +--- a/drivers/of/of_net.c ++++ b/drivers/of/of_net.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + /** + * of_get_phy_mode - Get phy mode for given device_node +@@ -39,7 +40,7 @@ int of_get_phy_mode(struct device_node * + } + EXPORT_SYMBOL_GPL(of_get_phy_mode); + +-static const void *of_get_mac_addr(struct device_node *np, const char *name) ++static void *of_get_mac_addr(struct device_node *np, const char *name) + { + struct property *pp = of_find_property(np, name, NULL); + +@@ -72,6 +73,79 @@ static const void *of_get_mac_addr_nvmem + return mac; + } + ++static const void *of_get_mac_address_mtd(struct device_node *np) ++{ ++#ifdef CONFIG_MTD ++ struct device_node *mtd_np = NULL; ++ struct property *prop; ++ size_t retlen; ++ int size, ret; ++ struct mtd_info *mtd; ++ const char *part; ++ const __be32 *list; ++ phandle phandle; ++ u32 mac_inc = 0; ++ u8 mac[ETH_ALEN]; ++ void *addr; ++ u32 inc_idx; ++ ++ list = of_get_property(np, "mtd-mac-address", &size); ++ if (!list || (size != (2 * sizeof(*list)))) ++ return NULL; ++ ++ phandle = be32_to_cpup(list++); ++ if (phandle) ++ mtd_np = of_find_node_by_phandle(phandle); ++ ++ if (!mtd_np) ++ return NULL; ++ ++ part = of_get_property(mtd_np, "label", NULL); ++ if (!part) ++ part = mtd_np->name; ++ ++ mtd = get_mtd_device_nm(part); ++ if (IS_ERR(mtd)) ++ return NULL; ++ ++ ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac); ++ put_mtd_device(mtd); ++ ++ if (of_property_read_u32(np, "mtd-mac-address-increment-byte", &inc_idx)) ++ inc_idx = 5; ++ if (inc_idx > 5) ++ return NULL; ++ ++ if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc)) ++ mac[inc_idx] += mac_inc; ++ ++ if (!is_valid_ether_addr(mac)) ++ return NULL; ++ ++ addr = of_get_mac_addr(np, "mac-address"); ++ if (addr) { ++ memcpy(addr, mac, ETH_ALEN); ++ return addr; ++ } ++ ++ prop = kzalloc(sizeof(*prop), GFP_KERNEL); ++ if (!prop) ++ return NULL; ++ ++ prop->name = "mac-address"; ++ prop->length = ETH_ALEN; ++ prop->value = kmemdup(mac, ETH_ALEN, GFP_KERNEL); ++ if (!prop->value || of_add_property(np, prop)) ++ goto free; ++ ++ return prop->value; ++free: ++ kfree(prop->value); ++ kfree(prop); ++#endif ++ return NULL; ++} ++ + /** + * Search the device tree for the best MAC address to use. 'mac-address' is + * checked first, because that is supposed to contain to "most recent" MAC +@@ -92,12 +166,20 @@ static const void *of_get_mac_addr_nvmem + * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists + * but is all zeros. + * ++ * ++ * If a mtd-mac-address property exists, try to fetch the MAC address from the ++ * specified mtd device, and store it as a 'mac-address' property ++ * + * Return: Will be a valid pointer on success and ERR_PTR in case of error. + */ + const void *of_get_mac_address(struct device_node *np) + { + const void *addr; + ++ addr = of_get_mac_address_mtd(np); ++ if (addr) ++ return addr; ++ + addr = of_get_mac_addr(np, "mac-address"); + if (addr) + return addr; diff --git a/ipq806x/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch b/ipq806x/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch new file mode 100644 index 0000000..b74b04c --- /dev/null +++ b/ipq806x/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -0,0 +1,38 @@ +From: Gabor Juhos +Subject: generic: add detach callback to struct phy_driver + +lede-commit: fe61fc2d7d0b3fb348b502f68f98243b3ddf5867 + +Signed-off-by: Gabor Juhos +--- + drivers/net/phy/phy_device.c | 3 +++ + include/linux/phy.h | 6 ++++++ + 2 files changed, 9 insertions(+) + +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1465,6 +1465,9 @@ void phy_detach(struct phy_device *phyde + struct module *ndev_owner = NULL; + struct mii_bus *bus; + ++ if (phydev->drv && phydev->drv->detach) ++ phydev->drv->detach(phydev); ++ + if (phydev->sysfs_links) { + if (dev) + sysfs_remove_link(&dev->dev.kobj, "phydev"); +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -540,6 +540,12 @@ struct phy_driver { + /* Override default interrupt handling */ + int (*handle_interrupt)(struct phy_device *phydev); + ++ /* ++ * Called before an ethernet device is detached ++ * from the PHY. ++ */ ++ void (*detach)(struct phy_device *phydev); ++ + /* Clears up any memory if needed */ + void (*remove)(struct phy_device *phydev); + diff --git a/ipq806x/pending-5.4/710-bridge-add-sysctl-knob-for-filtering-rx-tx-BPDU-pack.patch b/ipq806x/pending-5.4/710-bridge-add-sysctl-knob-for-filtering-rx-tx-BPDU-pack.patch new file mode 100644 index 0000000..586d264 --- /dev/null +++ b/ipq806x/pending-5.4/710-bridge-add-sysctl-knob-for-filtering-rx-tx-BPDU-pack.patch @@ -0,0 +1,107 @@ +From: Felix Fietkau +Date: Fri, 27 Aug 2021 12:22:32 +0200 +Subject: [PATCH] bridge: add sysctl knob for filtering rx/tx BPDU packets on a + port + +Some devices (e.g. wireless APs) can't have devices behind them be part of +a bridge topology with redundant links, due to address limitations. +Additionally, broadcast traffic on these devices is somewhat expensive, due to +the low data rate and wakeups of clients in powersave mode. +This sysctl knob can be used to ensure that BPDU packets are never sent +or forwarded to/from these devices + +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -47,6 +47,7 @@ struct br_ip_list { + #define BR_BCAST_FLOOD BIT(14) + #define BR_NEIGH_SUPPRESS BIT(15) + #define BR_ISOLATED BIT(16) ++#define BR_BPDU_FILTER BIT(17) + + #define BR_DEFAULT_AGEING_TIME (300 * HZ) + +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -191,6 +191,7 @@ out: + void br_flood(struct net_bridge *br, struct sk_buff *skb, + enum br_pkt_type pkt_type, bool local_rcv, bool local_orig) + { ++ const unsigned char *dest = eth_hdr(skb)->h_dest; + struct net_bridge_port *prev = NULL; + struct net_bridge_port *p; + +@@ -206,6 +207,10 @@ void br_flood(struct net_bridge *br, str + case BR_PKT_MULTICAST: + if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) + continue; ++ if ((p->flags & BR_BPDU_FILTER) && ++ unlikely(is_link_local_ether_addr(dest) && ++ dest[5] == 0)) ++ continue; + break; + case BR_PKT_BROADCAST: + if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -300,6 +300,8 @@ rx_handler_result_t br_handle_frame(stru + fwd_mask |= p->group_fwd_mask; + switch (dest[5]) { + case 0x00: /* Bridge Group Address */ ++ if (p->flags & BR_BPDU_FILTER) ++ goto drop; + /* If STP is turned off, + then must forward to keep loop detection */ + if (p->br->stp_enabled == BR_NO_STP || +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -233,6 +233,7 @@ BRPORT_ATTR_FLAG(multicast_flood, BR_MCA + BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD); + BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS); + BRPORT_ATTR_FLAG(isolated, BR_ISOLATED); ++BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER); + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) +@@ -285,6 +286,7 @@ static const struct brport_attribute *br + &brport_attr_group_fwd_mask, + &brport_attr_neigh_suppress, + &brport_attr_isolated, ++ &brport_attr_bpdu_filter, + &brport_attr_backup_port, + NULL + }; +--- a/net/bridge/br_stp_bpdu.c ++++ b/net/bridge/br_stp_bpdu.c +@@ -80,7 +80,8 @@ void br_send_config_bpdu(struct net_brid + { + unsigned char buf[35]; + +- if (p->br->stp_enabled != BR_KERNEL_STP) ++ if (p->br->stp_enabled != BR_KERNEL_STP || ++ (p->flags & BR_BPDU_FILTER)) + return; + + buf[0] = 0; +@@ -125,7 +126,8 @@ void br_send_tcn_bpdu(struct net_bridge_ + { + unsigned char buf[4]; + +- if (p->br->stp_enabled != BR_KERNEL_STP) ++ if (p->br->stp_enabled != BR_KERNEL_STP || ++ (p->flags & BR_BPDU_FILTER)) + return; + + buf[0] = 0; +@@ -168,6 +170,9 @@ void br_stp_rcv(const struct stp_proto * + if (!(br->dev->flags & IFF_UP)) + goto out; + ++ if (p->flags & BR_BPDU_FILTER) ++ goto out; ++ + if (p->state == BR_STATE_DISABLED) + goto out; + diff --git a/ipq806x/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch b/ipq806x/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch new file mode 100644 index 0000000..7957430 --- /dev/null +++ b/ipq806x/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch @@ -0,0 +1,51 @@ +From: Roman Yeryomin +Subject: kernel: add at803x fix for sgmii mode + +Some (possibly broken) bootloaders incorreclty initialize at8033 +phy. This patch enables sgmii autonegotiation mode. + +[john@phrozen.org: felix added this to his upstream queue] + +Signed-off-by: Roman Yeryomin +--- + drivers/net/phy/at803x.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -46,6 +46,7 @@ + #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A + #define AT803X_REG_CHIP_CONFIG 0x1f + #define AT803X_BT_BX_REG_SEL 0x8000 ++#define AT803X_SGMII_ANEG_EN 0x1000 + + #define AT803X_DEBUG_ADDR 0x1D + #define AT803X_DEBUG_DATA 0x1E +@@ -259,6 +260,27 @@ static int at803x_probe(struct phy_devic + static int at803x_config_init(struct phy_device *phydev) + { + int ret; ++ u32 v; ++ ++ if (phydev->drv->phy_id == ATH8031_PHY_ID && ++ phydev->interface == PHY_INTERFACE_MODE_SGMII) ++ { ++ v = phy_read(phydev, AT803X_REG_CHIP_CONFIG); ++ /* select SGMII/fiber page */ ++ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG, ++ v & ~AT803X_BT_BX_REG_SEL); ++ if (ret) ++ return ret; ++ /* enable SGMII autonegotiation */ ++ ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN); ++ if (ret) ++ return ret; ++ /* select copper page */ ++ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG, ++ v | AT803X_BT_BX_REG_SEL); ++ if (ret) ++ return ret; ++ } + + /* The RX and TX delay default is: + * after HW reset: RX delay enabled and TX delay disabled diff --git a/ipq806x/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch b/ipq806x/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch new file mode 100644 index 0000000..627d33e --- /dev/null +++ b/ipq806x/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch @@ -0,0 +1,108 @@ +From 283b211aa01bdae94dffb3121655dbb20bf237f4 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 3 Dec 2019 15:22:05 +0000 +Subject: net: sfp: avoid tx-fault with Nokia GPON module + +The Nokia GPON module can hold tx-fault active while it is initialising +which can take up to 60s. Avoid this causing the module to be declared +faulty after the SFP MSA defined non-cooled module timeout. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 42 ++++++++++++++++++++++++++++++------------ + 1 file changed, 30 insertions(+), 12 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -155,10 +155,20 @@ 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) ++/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a ++ * non-cooled module to initialise its laser safety circuitry. We wait ++ * an initial T_WAIT period before we check the tx fault to give any PHY ++ * on board (for a copper SFP) time to initialise. ++ */ ++#define T_WAIT msecs_to_jiffies(50) ++#define T_START_UP msecs_to_jiffies(300) ++#define T_START_UP_BAD_GPON msecs_to_jiffies(60000) ++ ++/* t_reset is the time required to assert the TX_DISABLE signal to reset ++ * an indicated TX_FAULT. ++ */ ++#define T_RESET_US 10 ++#define T_FAULT_RECOVER msecs_to_jiffies(1000) + + /* SFP module presence detection is poor: the three MOD DEF signals are + * the same length on the PCB, which means it's possible for MOD DEF 0 to +@@ -218,6 +228,7 @@ struct sfp { + + struct sfp_eeprom_id id; + unsigned int module_power_mW; ++ unsigned int module_t_start_up; + + #if IS_ENABLED(CONFIG_HWMON) + struct sfp_diag diag; +@@ -1655,6 +1666,12 @@ static int sfp_sm_mod_probe(struct sfp * + if (ret < 0) + return ret; + ++ if (!memcmp(id.base.vendor_name, "ALCATELLUCENT ", 16) && ++ !memcmp(id.base.vendor_pn, "3FE46541AA ", 16)) ++ sfp->module_t_start_up = T_START_UP_BAD_GPON; ++ else ++ sfp->module_t_start_up = T_START_UP; ++ + return 0; + } + +@@ -1860,11 +1877,12 @@ static void sfp_sm_main(struct sfp *sfp, + break; + + 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. ++ /* Wait up to t_init (SFF-8472) or t_start_up (SFF-8431) ++ * from the TX_DISABLE deassertion for the module to ++ * initialise, which is indicated by TX_FAULT ++ * deasserting. + */ +- timeout = T_INIT_JIFFIES; ++ timeout = sfp->module_t_start_up; + if (timeout > T_WAIT) + timeout -= T_WAIT; + else +@@ -1881,8 +1899,8 @@ static void sfp_sm_main(struct sfp *sfp, + + case SFP_S_INIT: + 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. ++ /* TX_FAULT is still asserted after t_init or ++ * or t_start_up, so assume there is a fault. + */ + sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, + sfp->sm_retries == 5); +@@ -1901,7 +1919,7 @@ static void sfp_sm_main(struct sfp *sfp, + 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); ++ sfp_sm_next(sfp, SFP_S_INIT, sfp->module_t_start_up); + } + break; + +@@ -1925,7 +1943,7 @@ static void sfp_sm_main(struct sfp *sfp, + case SFP_S_TX_FAULT: + if (event == SFP_E_TIMEOUT) { + sfp_module_tx_fault_reset(sfp); +- sfp_sm_next(sfp, SFP_S_REINIT, T_INIT_JIFFIES); ++ sfp_sm_next(sfp, SFP_S_REINIT, sfp->module_t_start_up); + } + break; + diff --git a/ipq806x/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch b/ipq806x/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch new file mode 100644 index 0000000..4de6305 --- /dev/null +++ b/ipq806x/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch @@ -0,0 +1,52 @@ +From 29cd215aaf6c2050c43e4de03aee436c16f90b96 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 21 Nov 2019 17:27:14 +0000 +Subject: [PATCH 643/660] net: sfp: remove incomplete 100BASE-FX and 100BASE-LX + support + +The 100BASE-FX and 100BASE-LX support assumes a PHY is present; this +is probably an incorrect assumption. In any case, sfp_parse_support() +will fail such a module. Let's stop pretending we support these +modules. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp-bus.c | 4 +--- + drivers/net/phy/sfp.c | 13 +------------ + 2 files changed, 2 insertions(+), 15 deletions(-) + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -342,9 +342,7 @@ phy_interface_t sfp_select_interface(str + if (phylink_test(link_modes, 2500baseX_Full)) + return PHY_INTERFACE_MODE_2500BASEX; + +- if (id->base.e1000_base_t || +- id->base.e100_base_lx || +- id->base.e100_base_fx) ++ if (id->base.e1000_base_t) + return PHY_INTERFACE_MODE_SGMII; + + if (phylink_test(link_modes, 1000baseX_Full)) +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -1489,18 +1489,7 @@ static void sfp_sm_fault(struct sfp *sfp + + 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. +- * +- * If it's a gigabit-only fiber module, it probably does +- * not have a PHY, so switch to 802.3z negotiation mode. +- * Otherwise, switch to SGMII mode (which is required to +- * support non-gigabit speeds) and probe for a PHY. +- */ +- if (sfp->id.base.e1000_base_t || +- sfp->id.base.e100_base_lx || +- sfp->id.base.e100_base_fx) ++ if (sfp->id.base.e1000_base_t) + sfp_sm_probe_phy(sfp); + } + diff --git a/ipq806x/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch b/ipq806x/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch new file mode 100644 index 0000000..8158c78 --- /dev/null +++ b/ipq806x/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch @@ -0,0 +1,89 @@ +From dc45d9e04572b5cd6d32f51cdf9f62b18022e6dd Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 21 Nov 2019 17:32:59 +0000 +Subject: [PATCH 644/660] net: sfp: derive interface mode from ethtool link + modes + +We don't need the EEPROM ID to derive the phy interface mode as we can +derive it merely from the ethtool link modes. Remove the EEPROM ID +argument to sfp_select_interface(). + +Signed-off-by: Russell King +--- + drivers/net/phy/marvell10g.c | 2 +- + drivers/net/phy/phylink.c | 2 +- + drivers/net/phy/sfp-bus.c | 11 ++++------- + include/linux/sfp.h | 2 -- + 4 files changed, 6 insertions(+), 11 deletions(-) + +--- a/drivers/net/phy/marvell10g.c ++++ b/drivers/net/phy/marvell10g.c +@@ -214,7 +214,7 @@ static int mv3310_sfp_insert(void *upstr + phy_interface_t iface; + + sfp_parse_support(phydev->sfp_bus, id, support); +- iface = sfp_select_interface(phydev->sfp_bus, id, support); ++ iface = sfp_select_interface(phydev->sfp_bus, support); + + if (iface != PHY_INTERFACE_MODE_10GKR) { + dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1718,7 +1718,7 @@ static int phylink_sfp_module_insert(voi + + linkmode_copy(support1, support); + +- iface = sfp_select_interface(pl->sfp_bus, id, config.advertising); ++ iface = sfp_select_interface(pl->sfp_bus, config.advertising); + if (iface == PHY_INTERFACE_MODE_NA) { + phylink_err(pl, + "selection of interface failed, advertisement %*pb\n", +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -320,16 +320,12 @@ EXPORT_SYMBOL_GPL(sfp_parse_support); + /** + * sfp_select_interface() - Select appropriate phy_interface_t mode + * @bus: a pointer to the &struct sfp_bus structure for the sfp module +- * @id: a pointer to the module's &struct sfp_eeprom_id + * @link_modes: ethtool link modes mask + * +- * Derive the phy_interface_t mode for the information found in the +- * module's identifying EEPROM and the link modes mask. There is no +- * standard or defined way to derive this information, so we decide +- * based upon the link mode mask. ++ * Derive the phy_interface_t mode for the SFP module from the link ++ * modes mask. + */ + phy_interface_t sfp_select_interface(struct sfp_bus *bus, +- const struct sfp_eeprom_id *id, + unsigned long *link_modes) + { + if (phylink_test(link_modes, 10000baseCR_Full) || +@@ -342,7 +338,8 @@ phy_interface_t sfp_select_interface(str + if (phylink_test(link_modes, 2500baseX_Full)) + return PHY_INTERFACE_MODE_2500BASEX; + +- if (id->base.e1000_base_t) ++ if (phylink_test(link_modes, 1000baseT_Half) || ++ phylink_test(link_modes, 1000baseT_Full)) + return PHY_INTERFACE_MODE_SGMII; + + if (phylink_test(link_modes, 1000baseX_Full)) +--- a/include/linux/sfp.h ++++ b/include/linux/sfp.h +@@ -504,7 +504,6 @@ int sfp_parse_port(struct sfp_bus *bus, + void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, + unsigned long *support); + phy_interface_t sfp_select_interface(struct sfp_bus *bus, +- const struct sfp_eeprom_id *id, + unsigned long *link_modes); + + int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo); +@@ -532,7 +531,6 @@ static inline void sfp_parse_support(str + } + + static inline phy_interface_t sfp_select_interface(struct sfp_bus *bus, +- const struct sfp_eeprom_id *id, + unsigned long *link_modes) + { + return PHY_INTERFACE_MODE_NA; diff --git a/ipq806x/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch b/ipq806x/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch new file mode 100644 index 0000000..0ddca28 --- /dev/null +++ b/ipq806x/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch @@ -0,0 +1,251 @@ +From c66a4e76c8554c84e64b9315314576ac403c6641 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 26 Sep 2019 15:14:18 +0100 +Subject: [PATCH 645/660] net: sfp: add more extended compliance codes + +SFF-8024 is used to define various constants re-used in several SFF +SFP-related specifications. Split these constants from the enum, and +rename them to indicate that they're defined by SFF-8024. + +Add and use updated SFF-8024 extended compliance code definitions for +10GBASE-T, 5GBASE-T and 2.5GBASE-T modules. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp-bus.c | 60 ++++++++++++++++------------ + drivers/net/phy/sfp.c | 4 +- + include/linux/sfp.h | 82 ++++++++++++++++++++++++++------------- + 3 files changed, 93 insertions(+), 53 deletions(-) + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -124,35 +124,35 @@ int sfp_parse_port(struct sfp_bus *bus, + + /* port is the physical connector, set this from the connector field. */ + switch (id->base.connector) { +- case SFP_CONNECTOR_SC: +- case SFP_CONNECTOR_FIBERJACK: +- case SFP_CONNECTOR_LC: +- case SFP_CONNECTOR_MT_RJ: +- case SFP_CONNECTOR_MU: +- case SFP_CONNECTOR_OPTICAL_PIGTAIL: ++ case SFF8024_CONNECTOR_SC: ++ case SFF8024_CONNECTOR_FIBERJACK: ++ case SFF8024_CONNECTOR_LC: ++ case SFF8024_CONNECTOR_MT_RJ: ++ case SFF8024_CONNECTOR_MU: ++ case SFF8024_CONNECTOR_OPTICAL_PIGTAIL: ++ case SFF8024_CONNECTOR_MPO_1X12: ++ case SFF8024_CONNECTOR_MPO_2X16: + port = PORT_FIBRE; + break; + +- case SFP_CONNECTOR_RJ45: ++ case SFF8024_CONNECTOR_RJ45: + port = PORT_TP; + break; + +- case SFP_CONNECTOR_COPPER_PIGTAIL: ++ case SFF8024_CONNECTOR_COPPER_PIGTAIL: + port = PORT_DA; + break; + +- case SFP_CONNECTOR_UNSPEC: ++ case SFF8024_CONNECTOR_UNSPEC: + if (id->base.e1000_base_t) { + port = PORT_TP; + break; + } + /* fallthrough */ +- case SFP_CONNECTOR_SG: /* guess */ +- case SFP_CONNECTOR_MPO_1X12: +- case SFP_CONNECTOR_MPO_2X16: +- case SFP_CONNECTOR_HSSDC_II: +- case SFP_CONNECTOR_NOSEPARATE: +- case SFP_CONNECTOR_MXC_2X16: ++ case SFF8024_CONNECTOR_SG: /* guess */ ++ case SFF8024_CONNECTOR_HSSDC_II: ++ case SFF8024_CONNECTOR_NOSEPARATE: ++ case SFF8024_CONNECTOR_MXC_2X16: + port = PORT_OTHER; + break; + default: +@@ -261,22 +261,33 @@ void sfp_parse_support(struct sfp_bus *b + } + + switch (id->base.extended_cc) { +- case 0x00: /* Unspecified */ ++ case SFF8024_ECC_UNSPEC: + break; +- case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */ ++ case SFF8024_ECC_100GBASE_SR4_25GBASE_SR: + phylink_set(modes, 100000baseSR4_Full); + phylink_set(modes, 25000baseSR_Full); + break; +- case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */ +- case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */ ++ case SFF8024_ECC_100GBASE_LR4_25GBASE_LR: ++ case SFF8024_ECC_100GBASE_ER4_25GBASE_ER: + phylink_set(modes, 100000baseLR4_ER4_Full); + break; +- case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */ +- case 0x0c: /* 25Gbase-CR CA-S */ +- case 0x0d: /* 25Gbase-CR CA-N */ ++ case SFF8024_ECC_100GBASE_CR4: + phylink_set(modes, 100000baseCR4_Full); ++ /* fallthrough */ ++ case SFF8024_ECC_25GBASE_CR_S: ++ case SFF8024_ECC_25GBASE_CR_N: + phylink_set(modes, 25000baseCR_Full); + break; ++ case SFF8024_ECC_10GBASE_T_SFI: ++ case SFF8024_ECC_10GBASE_T_SR: ++ phylink_set(modes, 10000baseT_Full); ++ break; ++ case SFF8024_ECC_5GBASE_T: ++ phylink_set(modes, 5000baseT_Full); ++ break; ++ case SFF8024_ECC_2_5GBASE_T: ++ phylink_set(modes, 2500baseT_Full); ++ break; + default: + dev_warn(bus->sfp_dev, + "Unknown/unsupported extended compliance code: 0x%02x\n", +@@ -301,7 +312,7 @@ void sfp_parse_support(struct sfp_bus *b + */ + if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) { + /* If the encoding and bit rate allows 1000baseX */ +- if (id->base.encoding == SFP_ENCODING_8B10B && br_nom && ++ if (id->base.encoding == SFF8024_ENCODING_8B10B && br_nom && + br_min <= 1300 && br_max >= 1200) + phylink_set(modes, 1000baseX_Full); + } +@@ -332,7 +343,8 @@ phy_interface_t sfp_select_interface(str + phylink_test(link_modes, 10000baseSR_Full) || + phylink_test(link_modes, 10000baseLR_Full) || + phylink_test(link_modes, 10000baseLRM_Full) || +- phylink_test(link_modes, 10000baseER_Full)) ++ phylink_test(link_modes, 10000baseER_Full) || ++ phylink_test(link_modes, 10000baseT_Full)) + return PHY_INTERFACE_MODE_10GKR; + + if (phylink_test(link_modes, 2500baseX_Full)) +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -242,7 +242,7 @@ struct sfp { + + static bool sff_module_supported(const struct sfp_eeprom_id *id) + { +- return id->base.phys_id == SFP_PHYS_ID_SFF && ++ return id->base.phys_id == SFF8024_ID_SFF_8472 && + id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP; + } + +@@ -253,7 +253,7 @@ static const struct sff_data sff_data = + + static bool sfp_module_supported(const struct sfp_eeprom_id *id) + { +- return id->base.phys_id == SFP_PHYS_ID_SFP && ++ return id->base.phys_id == SFF8024_ID_SFP && + id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP; + } + +--- a/include/linux/sfp.h ++++ b/include/linux/sfp.h +@@ -275,6 +275,61 @@ struct sfp_diag { + __be16 cal_v_offset; + } __packed; + ++/* SFF8024 defined constants */ ++enum { ++ SFF8024_ID_UNK = 0x00, ++ SFF8024_ID_SFF_8472 = 0x02, ++ SFF8024_ID_SFP = 0x03, ++ SFF8024_ID_DWDM_SFP = 0x0b, ++ SFF8024_ID_QSFP_8438 = 0x0c, ++ SFF8024_ID_QSFP_8436_8636 = 0x0d, ++ SFF8024_ID_QSFP28_8636 = 0x11, ++ ++ SFF8024_ENCODING_UNSPEC = 0x00, ++ SFF8024_ENCODING_8B10B = 0x01, ++ SFF8024_ENCODING_4B5B = 0x02, ++ SFF8024_ENCODING_NRZ = 0x03, ++ SFF8024_ENCODING_8472_MANCHESTER= 0x04, ++ SFF8024_ENCODING_8472_SONET = 0x05, ++ SFF8024_ENCODING_8472_64B66B = 0x06, ++ SFF8024_ENCODING_8436_MANCHESTER= 0x06, ++ SFF8024_ENCODING_8436_SONET = 0x04, ++ SFF8024_ENCODING_8436_64B66B = 0x05, ++ SFF8024_ENCODING_256B257B = 0x07, ++ SFF8024_ENCODING_PAM4 = 0x08, ++ ++ SFF8024_CONNECTOR_UNSPEC = 0x00, ++ /* codes 01-05 not supportable on SFP, but some modules have single SC */ ++ SFF8024_CONNECTOR_SC = 0x01, ++ SFF8024_CONNECTOR_FIBERJACK = 0x06, ++ SFF8024_CONNECTOR_LC = 0x07, ++ SFF8024_CONNECTOR_MT_RJ = 0x08, ++ SFF8024_CONNECTOR_MU = 0x09, ++ SFF8024_CONNECTOR_SG = 0x0a, ++ SFF8024_CONNECTOR_OPTICAL_PIGTAIL= 0x0b, ++ SFF8024_CONNECTOR_MPO_1X12 = 0x0c, ++ SFF8024_CONNECTOR_MPO_2X16 = 0x0d, ++ SFF8024_CONNECTOR_HSSDC_II = 0x20, ++ SFF8024_CONNECTOR_COPPER_PIGTAIL= 0x21, ++ SFF8024_CONNECTOR_RJ45 = 0x22, ++ SFF8024_CONNECTOR_NOSEPARATE = 0x23, ++ SFF8024_CONNECTOR_MXC_2X16 = 0x24, ++ ++ SFF8024_ECC_UNSPEC = 0x00, ++ SFF8024_ECC_100G_25GAUI_C2M_AOC = 0x01, ++ SFF8024_ECC_100GBASE_SR4_25GBASE_SR = 0x02, ++ SFF8024_ECC_100GBASE_LR4_25GBASE_LR = 0x03, ++ SFF8024_ECC_100GBASE_ER4_25GBASE_ER = 0x04, ++ SFF8024_ECC_100GBASE_SR10 = 0x05, ++ SFF8024_ECC_100GBASE_CR4 = 0x0b, ++ SFF8024_ECC_25GBASE_CR_S = 0x0c, ++ SFF8024_ECC_25GBASE_CR_N = 0x0d, ++ SFF8024_ECC_10GBASE_T_SFI = 0x16, ++ SFF8024_ECC_10GBASE_T_SR = 0x1c, ++ SFF8024_ECC_5GBASE_T = 0x1d, ++ SFF8024_ECC_2_5GBASE_T = 0x1e, ++}; ++ + /* SFP EEPROM registers */ + enum { + SFP_PHYS_ID = 0x00, +@@ -309,34 +364,7 @@ enum { + SFP_SFF8472_COMPLIANCE = 0x5e, + SFP_CC_EXT = 0x5f, + +- SFP_PHYS_ID_SFF = 0x02, +- SFP_PHYS_ID_SFP = 0x03, + SFP_PHYS_EXT_ID_SFP = 0x04, +- SFP_CONNECTOR_UNSPEC = 0x00, +- /* codes 01-05 not supportable on SFP, but some modules have single SC */ +- SFP_CONNECTOR_SC = 0x01, +- SFP_CONNECTOR_FIBERJACK = 0x06, +- SFP_CONNECTOR_LC = 0x07, +- SFP_CONNECTOR_MT_RJ = 0x08, +- SFP_CONNECTOR_MU = 0x09, +- SFP_CONNECTOR_SG = 0x0a, +- SFP_CONNECTOR_OPTICAL_PIGTAIL = 0x0b, +- SFP_CONNECTOR_MPO_1X12 = 0x0c, +- SFP_CONNECTOR_MPO_2X16 = 0x0d, +- SFP_CONNECTOR_HSSDC_II = 0x20, +- SFP_CONNECTOR_COPPER_PIGTAIL = 0x21, +- SFP_CONNECTOR_RJ45 = 0x22, +- SFP_CONNECTOR_NOSEPARATE = 0x23, +- SFP_CONNECTOR_MXC_2X16 = 0x24, +- SFP_ENCODING_UNSPEC = 0x00, +- SFP_ENCODING_8B10B = 0x01, +- SFP_ENCODING_4B5B = 0x02, +- SFP_ENCODING_NRZ = 0x03, +- SFP_ENCODING_8472_MANCHESTER = 0x04, +- SFP_ENCODING_8472_SONET = 0x05, +- SFP_ENCODING_8472_64B66B = 0x06, +- SFP_ENCODING_256B257B = 0x07, +- SFP_ENCODING_PAM4 = 0x08, + SFP_OPTIONS_HIGH_POWER_LEVEL = BIT(13), + SFP_OPTIONS_PAGING_A2 = BIT(12), + SFP_OPTIONS_RETIMER = BIT(11), diff --git a/ipq806x/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch b/ipq806x/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch new file mode 100644 index 0000000..44de1b2 --- /dev/null +++ b/ipq806x/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch @@ -0,0 +1,131 @@ +From f9a5a54b59cb904b37bf7409a43635ab195d0214 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 19 Nov 2019 10:13:25 +0000 +Subject: [PATCH 646/660] net: sfp: add module start/stop upstream + notifications + +When dealing with some copper modules, we can't positively know the +module capabilities are until we have probed the PHY. Without the full +capabilities, we may end up failing a module that we could otherwise +drive with a restricted set of capabilities. + +An example of this would be a module with a NBASE-T PHY plugged into +a host that supports phy interface modes 2500BASE-X and SGMII. The +PHY supports 10GBASE-R, 5000BASE-X, 2500BASE-X, SGMII interface modes, +which means a subset of the capabilities are compatible with the host. + +However, reading the module EEPROM leads us to believe that the module +only supports ethtool link mode 10GBASE-T, which is incompatible with +the host - and thus results in the module being rejected. + +This patch adds an extra notification which are triggered after the +SFP module's PHY probe, and a corresponding notification just before +the PHY is removed. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp-bus.c | 21 +++++++++++++++++++++ + drivers/net/phy/sfp.c | 8 ++++++++ + drivers/net/phy/sfp.h | 2 ++ + include/linux/sfp.h | 4 ++++ + 4 files changed, 35 insertions(+) + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -712,6 +712,27 @@ void sfp_module_remove(struct sfp_bus *b + } + EXPORT_SYMBOL_GPL(sfp_module_remove); + ++int sfp_module_start(struct sfp_bus *bus) ++{ ++ const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); ++ int ret = 0; ++ ++ if (ops && ops->module_start) ++ ret = ops->module_start(bus->upstream); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(sfp_module_start); ++ ++void sfp_module_stop(struct sfp_bus *bus) ++{ ++ const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); ++ ++ if (ops && ops->module_stop) ++ ops->module_stop(bus->upstream); ++} ++EXPORT_SYMBOL_GPL(sfp_module_stop); ++ + static void sfp_socket_clear(struct sfp_bus *bus) + { + bus->sfp_dev = NULL; +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -59,6 +59,7 @@ enum { + SFP_DEV_UP, + + SFP_S_DOWN = 0, ++ SFP_S_FAIL, + SFP_S_WAIT, + SFP_S_INIT, + SFP_S_INIT_TX_FAULT, +@@ -122,6 +123,7 @@ static const char *event_to_str(unsigned + + static const char * const sm_state_strings[] = { + [SFP_S_DOWN] = "down", ++ [SFP_S_FAIL] = "fail", + [SFP_S_WAIT] = "wait", + [SFP_S_INIT] = "init", + [SFP_S_INIT_TX_FAULT] = "init_tx_fault", +@@ -1831,6 +1833,8 @@ static void sfp_sm_main(struct sfp *sfp, + if (sfp->sm_state == SFP_S_LINK_UP && + sfp->sm_dev_state == SFP_DEV_UP) + sfp_sm_link_down(sfp); ++ if (sfp->sm_state > SFP_S_INIT) ++ sfp_module_stop(sfp->sfp_bus); + if (sfp->mod_phy) + sfp_sm_phy_detach(sfp); + sfp_module_tx_disable(sfp); +@@ -1898,6 +1902,10 @@ static void sfp_sm_main(struct sfp *sfp, + * clear. Probe for the PHY and check the LOS state. + */ + sfp_sm_probe_for_phy(sfp); ++ if (sfp_module_start(sfp->sfp_bus)) { ++ sfp_sm_next(sfp, SFP_S_FAIL, 0); ++ break; ++ } + sfp_sm_link_check_los(sfp); + + /* Reset the fault retry count */ +--- a/drivers/net/phy/sfp.h ++++ b/drivers/net/phy/sfp.h +@@ -22,6 +22,8 @@ void sfp_link_up(struct sfp_bus *bus); + void sfp_link_down(struct sfp_bus *bus); + int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id); + void sfp_module_remove(struct sfp_bus *bus); ++int sfp_module_start(struct sfp_bus *bus); ++void sfp_module_stop(struct sfp_bus *bus); + int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id); + struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp, + const struct sfp_socket_ops *ops); +--- a/include/linux/sfp.h ++++ b/include/linux/sfp.h +@@ -507,6 +507,8 @@ struct sfp_bus; + * @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. ++ * @module_start: called after the PHY probe step ++ * @module_stop: called before the PHY is removed + * @link_down: called when the link is non-operational for whatever + * reason. + * @link_up: called when the link is operational. +@@ -520,6 +522,8 @@ struct sfp_upstream_ops { + void (*detach)(void *priv, struct sfp_bus *bus); + int (*module_insert)(void *priv, const struct sfp_eeprom_id *id); + void (*module_remove)(void *priv); ++ int (*module_start)(void *priv); ++ void (*module_stop)(void *priv); + void (*link_down)(void *priv); + void (*link_up)(void *priv); + int (*connect_phy)(void *priv, struct phy_device *); diff --git a/ipq806x/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch b/ipq806x/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch new file mode 100644 index 0000000..e88a81d --- /dev/null +++ b/ipq806x/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch @@ -0,0 +1,72 @@ +From e2dc261b872a92a055eb2e86ac136baf9b20f2f2 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 21 Nov 2019 17:21:33 +0000 +Subject: [PATCH 647/660] net: sfp: move phy_start()/phy_stop() to phylink + +Move phy_start() and phy_stop() into the module_start and module_stop +notifications in phylink, rather than having them in the SFP code. +This gives phylink responsibility for controlling the PHY, rather +than having SFP start and stop the PHY state machine. + +Signed-off-by: Russell King +--- + drivers/net/phy/phylink.c | 22 ++++++++++++++++++++++ + drivers/net/phy/sfp.c | 2 -- + 2 files changed, 22 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1772,6 +1772,26 @@ static int phylink_sfp_module_insert(voi + return ret; + } + ++static int phylink_sfp_module_start(void *upstream) ++{ ++ struct phylink *pl = upstream; ++ ++ /* If this SFP module has a PHY, start the PHY now. */ ++ if (pl->phydev) ++ phy_start(pl->phydev); ++ ++ return 0; ++} ++ ++static void phylink_sfp_module_stop(void *upstream) ++{ ++ struct phylink *pl = upstream; ++ ++ /* If this SFP module has a PHY, stop it. */ ++ if (pl->phydev) ++ phy_stop(pl->phydev); ++} ++ + static void phylink_sfp_link_down(void *upstream) + { + struct phylink *pl = upstream; +@@ -1807,6 +1827,8 @@ static const struct sfp_upstream_ops sfp + .attach = phylink_sfp_attach, + .detach = phylink_sfp_detach, + .module_insert = phylink_sfp_module_insert, ++ .module_start = phylink_sfp_module_start, ++ .module_stop = phylink_sfp_module_stop, + .link_up = phylink_sfp_link_up, + .link_down = phylink_sfp_link_down, + .connect_phy = phylink_sfp_connect_phy, +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -1396,7 +1396,6 @@ static void sfp_sm_mod_next(struct sfp * + + static void sfp_sm_phy_detach(struct sfp *sfp) + { +- phy_stop(sfp->mod_phy); + sfp_remove_phy(sfp->sfp_bus); + phy_device_remove(sfp->mod_phy); + phy_device_free(sfp->mod_phy); +@@ -1427,7 +1426,6 @@ static void sfp_sm_probe_phy(struct sfp + } + + sfp->mod_phy = phy; +- phy_start(phy); + } + + static void sfp_sm_link_up(struct sfp *sfp) diff --git a/ipq806x/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch b/ipq806x/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch new file mode 100644 index 0000000..761a94b --- /dev/null +++ b/ipq806x/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch @@ -0,0 +1,74 @@ +From c9de73988a35c6c85810a992954ac568cca503e5 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 2 Oct 2019 10:31:10 +0100 +Subject: [PATCH 648/660] net: mdio-i2c: add support for Clause 45 accesses + +Some SFP+ modules have PHYs on them just like SFP modules do, except +they are Clause 45 PHYs. The I2C protocol used to access them is +modified slightly in order to send the device address and 16-bit +register index. + +Signed-off-by: Russell King +--- + drivers/net/phy/mdio-i2c.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +--- a/drivers/net/phy/mdio-i2c.c ++++ b/drivers/net/phy/mdio-i2c.c +@@ -33,17 +33,24 @@ static int i2c_mii_read(struct mii_bus * + { + struct i2c_adapter *i2c = bus->priv; + struct i2c_msg msgs[2]; +- u8 data[2], dev_addr = reg; ++ u8 addr[3], data[2], *p; + int bus_addr, ret; + + if (!i2c_mii_valid_phy_id(phy_id)) + return 0xffff; + ++ p = addr; ++ if (reg & MII_ADDR_C45) { ++ *p++ = 0x20 | ((reg >> 16) & 31); ++ *p++ = reg >> 8; ++ } ++ *p++ = reg; ++ + bus_addr = i2c_mii_phy_addr(phy_id); + msgs[0].addr = bus_addr; + msgs[0].flags = 0; +- msgs[0].len = 1; +- msgs[0].buf = &dev_addr; ++ msgs[0].len = p - addr; ++ msgs[0].buf = addr; + msgs[1].addr = bus_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = sizeof(data); +@@ -61,18 +68,23 @@ static int i2c_mii_write(struct mii_bus + struct i2c_adapter *i2c = bus->priv; + struct i2c_msg msg; + int ret; +- u8 data[3]; ++ u8 data[5], *p; + + if (!i2c_mii_valid_phy_id(phy_id)) + return 0; + +- data[0] = reg; +- data[1] = val >> 8; +- data[2] = val; ++ p = data; ++ if (reg & MII_ADDR_C45) { ++ *p++ = (reg >> 16) & 31; ++ *p++ = reg >> 8; ++ } ++ *p++ = reg; ++ *p++ = val >> 8; ++ *p++ = val; + + msg.addr = i2c_mii_phy_addr(phy_id); + msg.flags = 0; +- msg.len = 3; ++ msg.len = p - data; + msg.buf = data; + + ret = i2c_transfer(i2c, &msg, 1); diff --git a/ipq806x/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch b/ipq806x/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch new file mode 100644 index 0000000..d547a18 --- /dev/null +++ b/ipq806x/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch @@ -0,0 +1,93 @@ +From 0db7fba746b5608c30d4e2ba1c99a2a309e2d288 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Fri, 8 Nov 2019 15:22:48 +0000 +Subject: [PATCH 649/660] net: phylink: re-split __phylink_connect_phy() + +In order to support Clause 45 PHYs on SFP+ modules, which have an +indeterminant phy interface mode, we need to be able to call +phylink_bringup_phy() with a different interface mode to that used when +binding the PHY. Reduce __phylink_connect_phy() to an attach operation, +and move the call to phylink_bringup_phy() to its call sites. + +Signed-off-by: Russell King +--- + drivers/net/phy/phylink.c | 39 ++++++++++++++++++++++++--------------- + 1 file changed, 24 insertions(+), 15 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -765,11 +765,9 @@ static int phylink_bringup_phy(struct ph + return 0; + } + +-static int __phylink_connect_phy(struct phylink *pl, struct phy_device *phy, +- phy_interface_t interface) ++static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, ++ phy_interface_t interface) + { +- int ret; +- + if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED || + (pl->link_an_mode == MLO_AN_INBAND && + phy_interface_mode_is_8023z(interface)))) +@@ -778,15 +776,7 @@ static int __phylink_connect_phy(struct + if (pl->phydev) + return -EBUSY; + +- ret = phy_attach_direct(pl->netdev, phy, 0, interface); +- if (ret) +- return ret; +- +- ret = phylink_bringup_phy(pl, phy); +- if (ret) +- phy_detach(phy); +- +- return ret; ++ return phy_attach_direct(pl->netdev, phy, 0, interface); + } + + /** +@@ -806,13 +796,23 @@ static int __phylink_connect_phy(struct + */ + int phylink_connect_phy(struct phylink *pl, struct phy_device *phy) + { ++ int ret; ++ + /* Use PHY device/driver interface */ + if (pl->link_interface == PHY_INTERFACE_MODE_NA) { + pl->link_interface = phy->interface; + pl->link_config.interface = pl->link_interface; + } + +- return __phylink_connect_phy(pl, phy, pl->link_interface); ++ ret = phylink_attach_phy(pl, phy, pl->link_interface); ++ if (ret < 0) ++ return ret; ++ ++ ret = phylink_bringup_phy(pl, phy); ++ if (ret) ++ phy_detach(phy); ++ ++ return ret; + } + EXPORT_SYMBOL_GPL(phylink_connect_phy); + +@@ -1814,8 +1814,17 @@ static void phylink_sfp_link_up(void *up + static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) + { + struct phylink *pl = upstream; ++ int ret; + +- return __phylink_connect_phy(upstream, phy, pl->link_config.interface); ++ ret = phylink_attach_phy(pl, phy, pl->link_config.interface); ++ if (ret < 0) ++ return ret; ++ ++ ret = phylink_bringup_phy(pl, phy); ++ if (ret) ++ phy_detach(phy); ++ ++ return ret; + } + + static void phylink_sfp_disconnect_phy(void *upstream) diff --git a/ipq806x/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch b/ipq806x/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch new file mode 100644 index 0000000..673de10 --- /dev/null +++ b/ipq806x/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch @@ -0,0 +1,89 @@ +From caf32f96f13df7d3ae6cb8bf8001c88ae22025ca Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Fri, 8 Nov 2019 15:28:22 +0000 +Subject: [PATCH 650/660] net: phylink: support Clause 45 PHYs on SFP+ modules + +Some SFP+ modules have Clause 45 PHYs embedded on them, which need a +little more handling in order to ensure that they are correctly setup, +as they switch the PHY link mode according to the negotiated speed. + +With Clause 22 PHYs, we assumed that they would operate in SGMII mode, +but this assumption is now false. Adapt phylink to support Clause 45 +PHYs on SFP+ modules. + +Signed-off-by: Russell King +--- + drivers/net/phy/phylink.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -712,7 +712,8 @@ static void phylink_phy_change(struct ph + phy_duplex_to_str(phydev->duplex)); + } + +-static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy) ++static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy, ++ phy_interface_t interface) + { + struct phylink_link_state config; + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); +@@ -730,7 +731,7 @@ static int phylink_bringup_phy(struct ph + memset(&config, 0, sizeof(config)); + linkmode_copy(supported, phy->supported); + linkmode_copy(config.advertising, phy->advertising); +- config.interface = pl->link_config.interface; ++ config.interface = interface; + + ret = phylink_validate(pl, supported, &config); + if (ret) +@@ -746,6 +747,7 @@ static int phylink_bringup_phy(struct ph + mutex_lock(&phy->lock); + mutex_lock(&pl->state_mutex); + pl->phydev = phy; ++ pl->phy_state.interface = interface; + linkmode_copy(pl->supported, supported); + linkmode_copy(pl->link_config.advertising, config.advertising); + +@@ -808,7 +810,7 @@ int phylink_connect_phy(struct phylink * + if (ret < 0) + return ret; + +- ret = phylink_bringup_phy(pl, phy); ++ ret = phylink_bringup_phy(pl, phy, pl->link_config.interface); + if (ret) + phy_detach(phy); + +@@ -861,7 +863,7 @@ int phylink_of_phy_connect(struct phylin + if (!phy_dev) + return -ENODEV; + +- ret = phylink_bringup_phy(pl, phy_dev); ++ ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface); + if (ret) + phy_detach(phy_dev); + +@@ -1814,13 +1816,22 @@ static void phylink_sfp_link_up(void *up + static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) + { + struct phylink *pl = upstream; ++ phy_interface_t interface = pl->link_config.interface; + int ret; + + ret = phylink_attach_phy(pl, phy, pl->link_config.interface); + if (ret < 0) + return ret; + +- ret = phylink_bringup_phy(pl, phy); ++ /* Clause 45 PHYs switch their Serdes lane between several different ++ * modes, normally 10GBASE-R, SGMII. Some use 2500BASE-X for 2.5G ++ * speeds. We really need to know which interface modes the PHY and ++ * MAC supports to properly work out which linkmodes can be supported. ++ */ ++ if (phy->is_c45) ++ interface = PHY_INTERFACE_MODE_NA; ++ ++ ret = phylink_bringup_phy(pl, phy, interface); + if (ret) + phy_detach(phy); + diff --git a/ipq806x/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch b/ipq806x/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch new file mode 100644 index 0000000..eaf21db --- /dev/null +++ b/ipq806x/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch @@ -0,0 +1,257 @@ +From d1339d6956f0255b6ce2412328a98945be8cc3ca Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Sat, 16 Nov 2019 11:30:18 +0000 +Subject: [PATCH 651/660] net: phylink: split link_an_mode configured and + current settings + +Split link_an_mode between the configured setting and the current +operating setting. This is an important distinction to make when we +need to configure PHY mode for a plugged SFP+ module that does not +use in-band signalling. + +Signed-off-by: Russell King +--- + drivers/net/phy/phylink.c | 59 ++++++++++++++++++++------------------- + 1 file changed, 31 insertions(+), 28 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -48,7 +48,8 @@ struct phylink { + unsigned long phylink_disable_state; /* bitmask of disables */ + struct phy_device *phydev; + phy_interface_t link_interface; /* PHY_INTERFACE_xxx */ +- u8 link_an_mode; /* MLO_AN_xxx */ ++ u8 cfg_link_an_mode; /* MLO_AN_xxx */ ++ u8 cur_link_an_mode; + u8 link_port; /* The current non-phy ethtool port */ + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); + +@@ -258,12 +259,12 @@ static int phylink_parse_mode(struct phy + + dn = fwnode_get_named_child_node(fwnode, "fixed-link"); + if (dn || fwnode_property_present(fwnode, "fixed-link")) +- pl->link_an_mode = MLO_AN_FIXED; ++ pl->cfg_link_an_mode = MLO_AN_FIXED; + fwnode_handle_put(dn); + + if (fwnode_property_read_string(fwnode, "managed", &managed) == 0 && + strcmp(managed, "in-band-status") == 0) { +- if (pl->link_an_mode == MLO_AN_FIXED) { ++ if (pl->cfg_link_an_mode == MLO_AN_FIXED) { + phylink_err(pl, + "can't use both fixed-link and in-band-status\n"); + return -EINVAL; +@@ -275,7 +276,7 @@ static int phylink_parse_mode(struct phy + phylink_set(pl->supported, Asym_Pause); + phylink_set(pl->supported, Pause); + pl->link_config.an_enabled = true; +- pl->link_an_mode = MLO_AN_INBAND; ++ pl->cfg_link_an_mode = MLO_AN_INBAND; + + switch (pl->link_config.interface) { + case PHY_INTERFACE_MODE_SGMII: +@@ -335,14 +336,14 @@ static void phylink_mac_config(struct ph + { + phylink_dbg(pl, + "%s: mode=%s/%s/%s/%s adv=%*pb pause=%02x link=%u an=%u\n", +- __func__, phylink_an_mode_str(pl->link_an_mode), ++ __func__, phylink_an_mode_str(pl->cur_link_an_mode), + phy_modes(state->interface), + phy_speed_to_str(state->speed), + phy_duplex_to_str(state->duplex), + __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, + state->pause, state->link, state->an_enabled); + +- pl->ops->mac_config(pl->config, pl->link_an_mode, state); ++ pl->ops->mac_config(pl->config, pl->cur_link_an_mode, state); + } + + static void phylink_mac_config_up(struct phylink *pl, +@@ -443,7 +444,7 @@ static void phylink_mac_link_up(struct p + struct net_device *ndev = pl->netdev; + + pl->cur_interface = link_state.interface; +- pl->ops->mac_link_up(pl->config, pl->link_an_mode, ++ pl->ops->mac_link_up(pl->config, pl->cur_link_an_mode, + pl->cur_interface, pl->phydev); + + if (ndev) +@@ -462,7 +463,7 @@ static void phylink_mac_link_down(struct + + if (ndev) + netif_carrier_off(ndev); +- pl->ops->mac_link_down(pl->config, pl->link_an_mode, ++ pl->ops->mac_link_down(pl->config, pl->cur_link_an_mode, + pl->cur_interface); + phylink_info(pl, "Link is Down\n"); + } +@@ -481,7 +482,7 @@ static void phylink_resolve(struct work_ + } else if (pl->mac_link_dropped) { + link_state.link = false; + } else { +- switch (pl->link_an_mode) { ++ switch (pl->cur_link_an_mode) { + case MLO_AN_PHY: + link_state = pl->phy_state; + phylink_resolve_flow(pl, &link_state); +@@ -649,7 +650,7 @@ struct phylink *phylink_create(struct ph + return ERR_PTR(ret); + } + +- if (pl->link_an_mode == MLO_AN_FIXED) { ++ if (pl->cfg_link_an_mode == MLO_AN_FIXED) { + ret = phylink_parse_fixedlink(pl, fwnode); + if (ret < 0) { + kfree(pl); +@@ -657,6 +658,8 @@ struct phylink *phylink_create(struct ph + } + } + ++ pl->cur_link_an_mode = pl->cfg_link_an_mode; ++ + ret = phylink_register_sfp(pl, fwnode); + if (ret < 0) { + kfree(pl); +@@ -770,8 +773,8 @@ static int phylink_bringup_phy(struct ph + static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, + phy_interface_t interface) + { +- if (WARN_ON(pl->link_an_mode == MLO_AN_FIXED || +- (pl->link_an_mode == MLO_AN_INBAND && ++ if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED || ++ (pl->cfg_link_an_mode == MLO_AN_INBAND && + phy_interface_mode_is_8023z(interface)))) + return -EINVAL; + +@@ -838,8 +841,8 @@ int phylink_of_phy_connect(struct phylin + int ret; + + /* Fixed links and 802.3z are handled without needing a PHY */ +- if (pl->link_an_mode == MLO_AN_FIXED || +- (pl->link_an_mode == MLO_AN_INBAND && ++ if (pl->cfg_link_an_mode == MLO_AN_FIXED || ++ (pl->cfg_link_an_mode == MLO_AN_INBAND && + phy_interface_mode_is_8023z(pl->link_interface))) + return 0; + +@@ -850,7 +853,7 @@ int phylink_of_phy_connect(struct phylin + phy_node = of_parse_phandle(dn, "phy-device", 0); + + if (!phy_node) { +- if (pl->link_an_mode == MLO_AN_PHY) ++ if (pl->cfg_link_an_mode == MLO_AN_PHY) + return -ENODEV; + return 0; + } +@@ -913,7 +916,7 @@ int phylink_fixed_state_cb(struct phylin + /* It does not make sense to let the link be overriden unless we use + * MLO_AN_FIXED + */ +- if (pl->link_an_mode != MLO_AN_FIXED) ++ if (pl->cfg_link_an_mode != MLO_AN_FIXED) + return -EINVAL; + + mutex_lock(&pl->state_mutex); +@@ -963,7 +966,7 @@ void phylink_start(struct phylink *pl) + ASSERT_RTNL(); + + phylink_info(pl, "configuring for %s/%s link mode\n", +- phylink_an_mode_str(pl->link_an_mode), ++ phylink_an_mode_str(pl->cur_link_an_mode), + phy_modes(pl->link_config.interface)); + + /* Always set the carrier off */ +@@ -986,7 +989,7 @@ 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 && pl->link_gpio) { ++ if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->link_gpio) { + int irq = gpiod_to_irq(pl->link_gpio); + + if (irq > 0) { +@@ -1001,7 +1004,7 @@ void phylink_start(struct phylink *pl) + if (irq <= 0) + mod_timer(&pl->link_poll, jiffies + HZ); + } +- if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) ++ if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) + mod_timer(&pl->link_poll, jiffies + HZ); + if (pl->phydev) + phy_start(pl->phydev); +@@ -1128,7 +1131,7 @@ int phylink_ethtool_ksettings_get(struct + + linkmode_copy(kset->link_modes.supported, pl->supported); + +- switch (pl->link_an_mode) { ++ switch (pl->cur_link_an_mode) { + case MLO_AN_FIXED: + /* We are using fixed settings. Report these as the + * current link settings - and note that these also +@@ -1200,7 +1203,7 @@ int phylink_ethtool_ksettings_set(struct + /* If we have a fixed link (as specified by firmware), refuse + * to change link parameters. + */ +- if (pl->link_an_mode == MLO_AN_FIXED && ++ if (pl->cur_link_an_mode == MLO_AN_FIXED && + (s->speed != pl->link_config.speed || + s->duplex != pl->link_config.duplex)) + return -EINVAL; +@@ -1212,7 +1215,7 @@ int phylink_ethtool_ksettings_set(struct + __clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising); + } else { + /* If we have a fixed link, refuse to enable autonegotiation */ +- if (pl->link_an_mode == MLO_AN_FIXED) ++ if (pl->cur_link_an_mode == MLO_AN_FIXED) + return -EINVAL; + + config.speed = SPEED_UNKNOWN; +@@ -1254,7 +1257,7 @@ int phylink_ethtool_ksettings_set(struct + * configuration. For a fixed link, this isn't able to change any + * parameters, which just leaves inband mode. + */ +- if (pl->link_an_mode == MLO_AN_INBAND && ++ if (pl->cur_link_an_mode == MLO_AN_INBAND && + !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) { + phylink_mac_config(pl, &pl->link_config); + phylink_mac_an_restart(pl); +@@ -1344,7 +1347,7 @@ int phylink_ethtool_set_pauseparam(struc + pause->tx_pause); + } else if (!test_bit(PHYLINK_DISABLE_STOPPED, + &pl->phylink_disable_state)) { +- switch (pl->link_an_mode) { ++ switch (pl->cur_link_an_mode) { + case MLO_AN_FIXED: + /* Should we allow fixed links to change against the config? */ + phylink_resolve_flow(pl, config); +@@ -1551,7 +1554,7 @@ static int phylink_mii_read(struct phyli + struct phylink_link_state state; + int val = 0xffff; + +- switch (pl->link_an_mode) { ++ switch (pl->cur_link_an_mode) { + case MLO_AN_FIXED: + if (phy_id == 0) { + phylink_get_fixed_state(pl, &state); +@@ -1579,7 +1582,7 @@ static int phylink_mii_read(struct phyli + static int phylink_mii_write(struct phylink *pl, unsigned int phy_id, + unsigned int reg, unsigned int val) + { +- switch (pl->link_an_mode) { ++ switch (pl->cur_link_an_mode) { + case MLO_AN_FIXED: + break; + +@@ -1753,10 +1756,10 @@ static int phylink_sfp_module_insert(voi + linkmode_copy(pl->link_config.advertising, config.advertising); + } + +- if (pl->link_an_mode != MLO_AN_INBAND || ++ if (pl->cur_link_an_mode != MLO_AN_INBAND || + pl->link_config.interface != config.interface) { + pl->link_config.interface = config.interface; +- pl->link_an_mode = MLO_AN_INBAND; ++ pl->cur_link_an_mode = MLO_AN_INBAND; + + changed = true; + diff --git a/ipq806x/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch b/ipq806x/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch new file mode 100644 index 0000000..b840d71 --- /dev/null +++ b/ipq806x/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch @@ -0,0 +1,120 @@ +From 36569971241ae6b81376da4937d2c8760122d10b Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 21 Nov 2019 17:58:58 +0000 +Subject: [PATCH 652/660] net: phylink: split phylink_sfp_module_insert() + +Split out the configuration step from phylink_sfp_module_insert() so +we can re-use this later. + +Signed-off-by: Russell King +--- + drivers/net/phy/phylink.c | 47 +++++++++++++++++++++++---------------- + 1 file changed, 28 insertions(+), 19 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1688,25 +1688,21 @@ static void phylink_sfp_detach(void *ups + pl->netdev->sfp_bus = NULL; + } + +-static int phylink_sfp_module_insert(void *upstream, +- const struct sfp_eeprom_id *id) ++static int phylink_sfp_config(struct phylink *pl, u8 mode, u8 port, ++ const unsigned long *supported, ++ const unsigned long *advertising) + { +- struct phylink *pl = upstream; +- __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; + __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support); + struct phylink_link_state config; + phy_interface_t iface; +- int ret = 0; + bool changed; +- u8 port; ++ int ret; + +- ASSERT_RTNL(); +- +- sfp_parse_support(pl->sfp_bus, id, support); +- port = sfp_parse_port(pl->sfp_bus, id, support); ++ linkmode_copy(support, supported); + + memset(&config, 0, sizeof(config)); +- linkmode_copy(config.advertising, support); ++ linkmode_copy(config.advertising, advertising); + config.interface = PHY_INTERFACE_MODE_NA; + config.speed = SPEED_UNKNOWN; + config.duplex = DUPLEX_UNKNOWN; +@@ -1721,8 +1717,6 @@ static int phylink_sfp_module_insert(voi + return ret; + } + +- linkmode_copy(support1, support); +- + iface = sfp_select_interface(pl->sfp_bus, config.advertising); + if (iface == PHY_INTERFACE_MODE_NA) { + phylink_err(pl, +@@ -1732,18 +1726,18 @@ static int phylink_sfp_module_insert(voi + } + + config.interface = iface; ++ linkmode_copy(support1, support); + ret = phylink_validate(pl, support1, &config); + if (ret) { + phylink_err(pl, "validation of %s/%s with support %*pb failed: %d\n", +- phylink_an_mode_str(MLO_AN_INBAND), ++ phylink_an_mode_str(mode), + phy_modes(config.interface), + __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); + return ret; + } + + phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n", +- phylink_an_mode_str(MLO_AN_INBAND), +- phy_modes(config.interface), ++ phylink_an_mode_str(mode), phy_modes(config.interface), + __ETHTOOL_LINK_MODE_MASK_NBITS, support); + + if (phy_interface_mode_is_8023z(iface) && pl->phydev) +@@ -1756,15 +1750,15 @@ static int phylink_sfp_module_insert(voi + linkmode_copy(pl->link_config.advertising, config.advertising); + } + +- if (pl->cur_link_an_mode != MLO_AN_INBAND || ++ if (pl->cur_link_an_mode != mode || + pl->link_config.interface != config.interface) { + pl->link_config.interface = config.interface; +- pl->cur_link_an_mode = MLO_AN_INBAND; ++ pl->cur_link_an_mode = mode; + + changed = true; + + phylink_info(pl, "switched to %s/%s link mode\n", +- phylink_an_mode_str(MLO_AN_INBAND), ++ phylink_an_mode_str(mode), + phy_modes(config.interface)); + } + +@@ -1777,6 +1771,21 @@ static int phylink_sfp_module_insert(voi + return ret; + } + ++static int phylink_sfp_module_insert(void *upstream, ++ const struct sfp_eeprom_id *id) ++{ ++ struct phylink *pl = upstream; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; ++ u8 port; ++ ++ ASSERT_RTNL(); ++ ++ sfp_parse_support(pl->sfp_bus, id, support); ++ port = sfp_parse_port(pl->sfp_bus, id, support); ++ ++ return phylink_sfp_config(pl, MLO_AN_INBAND, port, support, support); ++} ++ + static int phylink_sfp_module_start(void *upstream) + { + struct phylink *pl = upstream; diff --git a/ipq806x/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch b/ipq806x/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch new file mode 100644 index 0000000..667170a --- /dev/null +++ b/ipq806x/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch @@ -0,0 +1,201 @@ +From 52c956003a9d5bcae1f445f9dfd42b624adb6e87 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 11 Dec 2019 10:56:45 +0000 +Subject: [PATCH] net: phylink: delay MAC configuration for copper SFP modules + +Knowing whether we need to delay the MAC configuration because a module +may have a PHY is useful to phylink to allow NBASE-T modules to work on +systems supporting no more than 2.5G speeds. + +This commit allows us to delay such configuration until after the PHY +has been probed by recording the parsed capabilities, and if the module +may have a PHY, doing no more until the module_start() notification is +called. At that point, we either have a PHY, or we don't. + +We move the PHY-based setup a little later, and use the PHYs support +capabilities rather than the EEPROM parsed capabilities to determine +whether we can support the PHY. + +Reviewed-by: Andrew Lunn +Signed-off-by: Russell King +Signed-off-by: David S. Miller +--- + drivers/net/phy/phylink.c | 53 +++++++++++++++++++++++++++++++-------- + drivers/net/phy/sfp-bus.c | 28 +++++++++++++++++++++ + include/linux/sfp.h | 7 ++++++ + 3 files changed, 78 insertions(+), 10 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -72,6 +72,9 @@ struct phylink { + bool mac_link_dropped; + + struct sfp_bus *sfp_bus; ++ bool sfp_may_have_phy; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); ++ u8 sfp_port; + }; + + #define phylink_printk(level, pl, fmt, ...) \ +@@ -1688,7 +1691,7 @@ static void phylink_sfp_detach(void *ups + pl->netdev->sfp_bus = NULL; + } + +-static int phylink_sfp_config(struct phylink *pl, u8 mode, u8 port, ++static int phylink_sfp_config(struct phylink *pl, u8 mode, + const unsigned long *supported, + const unsigned long *advertising) + { +@@ -1762,7 +1765,7 @@ static int phylink_sfp_config(struct phy + phy_modes(config.interface)); + } + +- pl->link_port = port; ++ pl->link_port = pl->sfp_port; + + if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, + &pl->phylink_disable_state)) +@@ -1775,15 +1778,20 @@ static int phylink_sfp_module_insert(voi + const struct sfp_eeprom_id *id) + { + struct phylink *pl = upstream; +- __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; +- u8 port; ++ unsigned long *support = pl->sfp_support; + + ASSERT_RTNL(); + ++ linkmode_zero(support); + sfp_parse_support(pl->sfp_bus, id, support); +- port = sfp_parse_port(pl->sfp_bus, id, support); ++ pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support); + +- return phylink_sfp_config(pl, MLO_AN_INBAND, port, support, support); ++ /* If this module may have a PHY connecting later, defer until later */ ++ pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id); ++ if (pl->sfp_may_have_phy) ++ return 0; ++ ++ return phylink_sfp_config(pl, MLO_AN_INBAND, support, support); + } + + static int phylink_sfp_module_start(void *upstream) +@@ -1791,10 +1799,19 @@ static int phylink_sfp_module_start(void + struct phylink *pl = upstream; + + /* If this SFP module has a PHY, start the PHY now. */ +- if (pl->phydev) ++ if (pl->phydev) { + phy_start(pl->phydev); +- +- return 0; ++ return 0; ++ } ++ ++ /* If the module may have a PHY but we didn't detect one we ++ * need to configure the MAC here. ++ */ ++ if (!pl->sfp_may_have_phy) ++ return 0; ++ ++ return phylink_sfp_config(pl, MLO_AN_INBAND, ++ pl->sfp_support, pl->sfp_support); + } + + static void phylink_sfp_module_stop(void *upstream) +@@ -1828,10 +1845,26 @@ static void phylink_sfp_link_up(void *up + static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) + { + struct phylink *pl = upstream; +- phy_interface_t interface = pl->link_config.interface; ++ phy_interface_t interface; + int ret; + +- ret = phylink_attach_phy(pl, phy, pl->link_config.interface); ++ /* ++ * This is the new way of dealing with flow control for PHYs, ++ * as described by Timur Tabi in commit 529ed1275263 ("net: phy: ++ * phy drivers should not set SUPPORTED_[Asym_]Pause") except ++ * using our validate call to the MAC, we rely upon the MAC ++ * clearing the bits from both supported and advertising fields. ++ */ ++ phy_support_asym_pause(phy); ++ ++ /* Do the initial configuration */ ++ ret = phylink_sfp_config(pl, MLO_AN_INBAND, phy->supported, ++ phy->advertising); ++ if (ret < 0) ++ return ret; ++ ++ interface = pl->link_config.interface; ++ ret = phylink_attach_phy(pl, phy, interface); + if (ret < 0) + return ret; + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -103,6 +103,7 @@ static const struct sfp_quirk *sfp_looku + + return NULL; + } ++ + /** + * sfp_parse_port() - Parse the EEPROM base ID, setting the port type + * @bus: a pointer to the &struct sfp_bus structure for the sfp module +@@ -179,6 +180,33 @@ int sfp_parse_port(struct sfp_bus *bus, + EXPORT_SYMBOL_GPL(sfp_parse_port); + + /** ++ * sfp_may_have_phy() - indicate whether the module may have a PHY ++ * @bus: a pointer to the &struct sfp_bus structure for the sfp module ++ * @id: a pointer to the module's &struct sfp_eeprom_id ++ * ++ * Parse the EEPROM identification given in @id, and return whether ++ * this module may have a PHY. ++ */ ++bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id) ++{ ++ if (id->base.e1000_base_t) ++ return true; ++ ++ if (id->base.phys_id != SFF8024_ID_DWDM_SFP) { ++ switch (id->base.extended_cc) { ++ case SFF8024_ECC_10GBASE_T_SFI: ++ case SFF8024_ECC_10GBASE_T_SR: ++ case SFF8024_ECC_5GBASE_T: ++ case SFF8024_ECC_2_5GBASE_T: ++ return true; ++ } ++ } ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(sfp_may_have_phy); ++ ++/** + * sfp_parse_support() - Parse the eeprom id for supported link modes + * @bus: a pointer to the &struct sfp_bus structure for the sfp module + * @id: a pointer to the module's &struct sfp_eeprom_id +--- a/include/linux/sfp.h ++++ b/include/linux/sfp.h +@@ -533,6 +533,7 @@ struct sfp_upstream_ops { + #if IS_ENABLED(CONFIG_SFP) + int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id, + unsigned long *support); ++bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id); + void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, + unsigned long *support); + phy_interface_t sfp_select_interface(struct sfp_bus *bus, +@@ -556,6 +557,12 @@ static inline int sfp_parse_port(struct + return PORT_OTHER; + } + ++static inline bool sfp_may_have_phy(struct sfp_bus *bus, ++ const struct sfp_eeprom_id *id) ++{ ++ return false; ++} ++ + static inline void sfp_parse_support(struct sfp_bus *bus, + const struct sfp_eeprom_id *id, + unsigned long *support) diff --git a/ipq806x/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch b/ipq806x/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch new file mode 100644 index 0000000..d583044 --- /dev/null +++ b/ipq806x/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch @@ -0,0 +1,59 @@ +From 7adb5b2126bc013f0964ddaefad6ad1b132e86c3 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 11 Dec 2019 10:56:50 +0000 +Subject: [PATCH] net: phylink: make Broadcom BCM84881 based SFPs work + +The Broadcom BCM84881 does not appear to send the SGMII control word +when operating in SGMII mode, which causes network adapters to fail +to link with the PHY, or decide to operate at fixed 1G speed, even if +the PHY negotiated 100M. + +Work around this by detecting the Broadcom BCM84881 and switch to phy +mode rather than inband mode. + +Reviewed-by: Florian Fainelli +Signed-off-by: Russell King +Signed-off-by: David S. Miller +--- + drivers/net/phy/phylink.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -1842,10 +1842,20 @@ static void phylink_sfp_link_up(void *up + phylink_run_resolve(pl); + } + ++/* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII ++ * or 802.3z control word, so inband will not work. ++ */ ++static bool phylink_phy_no_inband(struct phy_device *phy) ++{ ++ return phy->is_c45 && ++ (phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150; ++} ++ + static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) + { + struct phylink *pl = upstream; + phy_interface_t interface; ++ u8 mode; + int ret; + + /* +@@ -1857,9 +1867,13 @@ static int phylink_sfp_connect_phy(void + */ + phy_support_asym_pause(phy); + ++ if (phylink_phy_no_inband(phy)) ++ mode = MLO_AN_PHY; ++ else ++ mode = MLO_AN_INBAND; ++ + /* Do the initial configuration */ +- ret = phylink_sfp_config(pl, MLO_AN_INBAND, phy->supported, +- phy->advertising); ++ ret = phylink_sfp_config(pl, mode, phy->supported, phy->advertising); + if (ret < 0) + return ret; + diff --git a/ipq806x/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch b/ipq806x/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch new file mode 100644 index 0000000..783dec0 --- /dev/null +++ b/ipq806x/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch @@ -0,0 +1,315 @@ +From 75f4d8d10e016f7428c268424483a927ee7a78bb Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 11 Dec 2019 10:56:56 +0000 +Subject: [PATCH] net: phy: add Broadcom BCM84881 PHY driver + +Add a rudimentary Clause 45 driver for the BCM84881 PHY, found on +Methode DM7052 SFPs. + +Reviewed-by: Florian Fainelli +Signed-off-by: Russell King +Signed-off-by: David S. Miller +--- + drivers/net/phy/Kconfig | 6 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/bcm84881.c | 269 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 276 insertions(+) + create mode 100644 drivers/net/phy/bcm84881.c + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -330,6 +330,12 @@ config BROADCOM_PHY + Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, + BCM5481, BCM54810 and BCM5482 PHYs. + ++config BCM84881_PHY ++ tristate "Broadcom BCM84881 PHY" ++ depends on PHYLIB ++ ---help--- ++ Support the Broadcom BCM84881 PHY. ++ + config CICADA_PHY + tristate "Cicada PHYs" + ---help--- +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -62,6 +62,7 @@ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o + obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o + obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o + obj-$(CONFIG_BROADCOM_PHY) += broadcom.o ++obj-$(CONFIG_BCM84881_PHY) += bcm84881.o + obj-$(CONFIG_CICADA_PHY) += cicada.o + obj-$(CONFIG_CORTINA_PHY) += cortina.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o +--- /dev/null ++++ b/drivers/net/phy/bcm84881.c +@@ -0,0 +1,269 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Broadcom BCM84881 NBASE-T PHY driver, as found on a SFP+ module. ++// Copyright (C) 2019 Russell King, Deep Blue Solutions Ltd. ++// ++// Like the Marvell 88x3310, the Broadcom 84881 changes its host-side ++// interface according to the operating speed between 10GBASE-R, ++// 2500BASE-X and SGMII (but unlike the 88x3310, without the control ++// word). ++// ++// This driver only supports those aspects of the PHY that I'm able to ++// observe and test with the SFP+ module, which is an incomplete subset ++// of what this PHY is able to support. For example, I only assume it ++// supports a single lane Serdes connection, but it may be that the PHY ++// is able to support more than that. ++#include ++#include ++#include ++ ++enum { ++ MDIO_AN_C22 = 0xffe0, ++}; ++ ++static int bcm84881_wait_init(struct phy_device *phydev) ++{ ++ unsigned int tries = 20; ++ int ret, val; ++ ++ do { ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1); ++ if (val < 0) { ++ ret = val; ++ break; ++ } ++ if (!(val & MDIO_CTRL1_RESET)) { ++ ret = 0; ++ break; ++ } ++ if (!--tries) { ++ ret = -ETIMEDOUT; ++ break; ++ } ++ msleep(100); ++ } while (1); ++ ++ if (ret) ++ phydev_err(phydev, "%s failed: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static int bcm84881_config_init(struct phy_device *phydev) ++{ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ case PHY_INTERFACE_MODE_10GKR: ++ break; ++ default: ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++static int bcm84881_probe(struct phy_device *phydev) ++{ ++ /* This driver requires PMAPMD and AN blocks */ ++ const u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; ++ ++ if (!phydev->is_c45 || ++ (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) ++ return -ENODEV; ++ ++ return 0; ++} ++ ++static int bcm84881_get_features(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = genphy_c45_pma_read_abilities(phydev); ++ if (ret) ++ return ret; ++ ++ /* Although the PHY sets bit 1.11.8, it does not support 10M modes */ ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, ++ phydev->supported); ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, ++ phydev->supported); ++ ++ return 0; ++} ++ ++static int bcm84881_config_aneg(struct phy_device *phydev) ++{ ++ bool changed = false; ++ u32 adv; ++ int ret; ++ ++ /* Wait for the PHY to finish initialising, otherwise our ++ * advertisement may be overwritten. ++ */ ++ ret = bcm84881_wait_init(phydev); ++ if (ret) ++ return ret; ++ ++ /* We don't support manual MDI control */ ++ phydev->mdix_ctrl = ETH_TP_MDI_AUTO; ++ ++ /* disabled autoneg doesn't seem to work with this PHY */ ++ if (phydev->autoneg == AUTONEG_DISABLE) ++ return -EINVAL; ++ ++ ret = genphy_c45_an_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); ++ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, ++ MDIO_AN_C22 + MII_CTRL1000, ++ ADVERTISE_1000FULL | ADVERTISE_1000HALF, ++ adv); ++ if (ret < 0) ++ return ret; ++ if (ret > 0) ++ changed = true; ++ ++ return genphy_c45_check_and_restart_aneg(phydev, changed); ++} ++ ++static int bcm84881_aneg_done(struct phy_device *phydev) ++{ ++ int bmsr, val; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); ++ if (val < 0) ++ return val; ++ ++ bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR); ++ if (bmsr < 0) ++ return val; ++ ++ return !!(val & MDIO_AN_STAT1_COMPLETE) && ++ !!(bmsr & BMSR_ANEGCOMPLETE); ++} ++ ++static int bcm84881_read_status(struct phy_device *phydev) ++{ ++ unsigned int mode; ++ int bmsr, val; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); ++ if (val < 0) ++ return val; ++ ++ if (val & MDIO_AN_CTRL1_RESTART) { ++ phydev->link = 0; ++ return 0; ++ } ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); ++ if (val < 0) ++ return val; ++ ++ bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR); ++ if (bmsr < 0) ++ return val; ++ ++ phydev->autoneg_complete = !!(val & MDIO_AN_STAT1_COMPLETE) && ++ !!(bmsr & BMSR_ANEGCOMPLETE); ++ phydev->link = !!(val & MDIO_STAT1_LSTATUS) && ++ !!(bmsr & BMSR_LSTATUS); ++ if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete) ++ phydev->link = false; ++ ++ if (!phydev->link) ++ return 0; ++ ++ linkmode_zero(phydev->lp_advertising); ++ phydev->speed = SPEED_UNKNOWN; ++ phydev->duplex = DUPLEX_UNKNOWN; ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ phydev->mdix = 0; ++ ++ if (phydev->autoneg_complete) { ++ val = genphy_c45_read_lpa(phydev); ++ if (val < 0) ++ return val; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_AN, ++ MDIO_AN_C22 + MII_STAT1000); ++ if (val < 0) ++ return val; ++ ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) ++ phy_resolve_aneg_linkmode(phydev); ++ } ++ ++ if (phydev->autoneg == AUTONEG_DISABLE) { ++ /* disabled autoneg doesn't seem to work, so force the link ++ * down. ++ */ ++ phydev->link = 0; ++ return 0; ++ } ++ ++ /* Set the host link mode - we set the phy interface mode and ++ * the speed according to this register so that downshift works. ++ * We leave the duplex setting as per the resolution from the ++ * above. ++ */ ++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x4011); ++ mode = (val & 0x1e) >> 1; ++ if (mode == 1 || mode == 2) ++ phydev->interface = PHY_INTERFACE_MODE_SGMII; ++ else if (mode == 3) ++ phydev->interface = PHY_INTERFACE_MODE_10GKR; ++ else if (mode == 4) ++ phydev->interface = PHY_INTERFACE_MODE_2500BASEX; ++ switch (mode & 7) { ++ case 1: ++ phydev->speed = SPEED_100; ++ break; ++ case 2: ++ phydev->speed = SPEED_1000; ++ break; ++ case 3: ++ phydev->speed = SPEED_10000; ++ break; ++ case 4: ++ phydev->speed = SPEED_2500; ++ break; ++ case 5: ++ phydev->speed = SPEED_5000; ++ break; ++ } ++ ++ return genphy_c45_read_mdix(phydev); ++} ++ ++static struct phy_driver bcm84881_drivers[] = { ++ { ++ .phy_id = 0xae025150, ++ .phy_id_mask = 0xfffffff0, ++ .name = "Broadcom BCM84881", ++ .config_init = bcm84881_config_init, ++ .probe = bcm84881_probe, ++ .get_features = bcm84881_get_features, ++ .config_aneg = bcm84881_config_aneg, ++ .aneg_done = bcm84881_aneg_done, ++ .read_status = bcm84881_read_status, ++ }, ++}; ++ ++module_phy_driver(bcm84881_drivers); ++ ++/* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */ ++static struct mdio_device_id __maybe_unused bcm84881_tbl[] = { ++ { 0xae025150, 0xfffffff0 }, ++ { }, ++}; ++MODULE_AUTHOR("Russell King"); ++MODULE_DESCRIPTION("Broadcom BCM84881 PHY driver"); ++MODULE_DEVICE_TABLE(mdio, bcm84881_tbl); ++MODULE_LICENSE("GPL"); diff --git a/ipq806x/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch b/ipq806x/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch new file mode 100644 index 0000000..338ddc3 --- /dev/null +++ b/ipq806x/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch @@ -0,0 +1,94 @@ +From 6df6709dc3d00e0bc948d45dfa8d8f18ba379c48 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 5 Nov 2019 11:56:18 +0000 +Subject: [PATCH 656/660] net: sfp: add support for Clause 45 PHYs + +Some SFP+ modules have a Clause 45 PHY onboard, which is accessible via +the normal I2C address. Detect 10G BASE-T PHYs which may have an +accessible PHY and probe for it. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 44 +++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 40 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -1402,12 +1402,12 @@ static void sfp_sm_phy_detach(struct sfp + sfp->mod_phy = NULL; + } + +-static void sfp_sm_probe_phy(struct sfp *sfp) ++static void sfp_sm_probe_phy(struct sfp *sfp, bool is_c45) + { + struct phy_device *phy; + int err; + +- phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR); ++ phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45); + if (phy == ERR_PTR(-ENODEV)) { + dev_info(sfp->dev, "no PHY detected\n"); + return; +@@ -1417,6 +1417,13 @@ static void sfp_sm_probe_phy(struct sfp + return; + } + ++ err = phy_device_register(phy); ++ if (err) { ++ phy_device_free(phy); ++ dev_err(sfp->dev, "phy_device_register failed: %d\n", err); ++ return; ++ } ++ + err = sfp_add_phy(sfp->sfp_bus, phy); + if (err) { + phy_device_remove(phy); +@@ -1487,10 +1494,32 @@ static void sfp_sm_fault(struct sfp *sfp + } + } + ++/* Probe a SFP for a PHY device if the module supports copper - the PHY ++ * normally sits at I2C bus address 0x56, and may either be a clause 22 ++ * or clause 45 PHY. ++ * ++ * Clause 22 copper SFP modules normally operate in Cisco SGMII mode with ++ * negotiation enabled, but some may be in 1000base-X - which is for the ++ * PHY driver to determine. ++ * ++ * Clause 45 copper SFP+ modules (10G) appear to switch their interface ++ * mode according to the negotiated line speed. ++ */ + static void sfp_sm_probe_for_phy(struct sfp *sfp) + { +- if (sfp->id.base.e1000_base_t) +- sfp_sm_probe_phy(sfp); ++ switch (sfp->id.base.extended_cc) { ++ case SFF8024_ECC_10GBASE_T_SFI: ++ case SFF8024_ECC_10GBASE_T_SR: ++ case SFF8024_ECC_5GBASE_T: ++ case SFF8024_ECC_2_5GBASE_T: ++ sfp_sm_probe_phy(sfp, true); ++ break; ++ ++ default: ++ if (sfp->id.base.e1000_base_t) ++ sfp_sm_probe_phy(sfp, false); ++ break; ++ } + } + + static int sfp_module_parse_power(struct sfp *sfp) +@@ -1550,6 +1579,13 @@ static int sfp_sm_mod_hpower(struct sfp + return -EAGAIN; + } + ++ /* DM7052 reports as a high power module, responds to reads (with ++ * all bytes 0xff) at 0x51 but does not accept writes. In any case, ++ * if the bit is already set, we're already in high power mode. ++ */ ++ if (!!(val & BIT(0)) == enable) ++ return 0; ++ + if (enable) + val |= BIT(0); + else diff --git a/ipq806x/pending-5.4/754-net-sfp-fix-unbind.patch b/ipq806x/pending-5.4/754-net-sfp-fix-unbind.patch new file mode 100644 index 0000000..8d98a5d --- /dev/null +++ b/ipq806x/pending-5.4/754-net-sfp-fix-unbind.patch @@ -0,0 +1,28 @@ +From 729fd05aac22cdf1e502fbf1bf80e5ebba0d9fbc Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 3 Dec 2019 17:48:28 +0000 +Subject: [PATCH] net: sfp: fix unbind + +When unbinding, we don't correctly tear down the module state, leaving +(for example) the hwmon registration behind. Ensure everything is +properly removed by sending a remove event at unbind. + +Fixes: 6b0da5c9c1a3 ("net: sfp: track upstream's attachment state in state machine") +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -2344,6 +2344,10 @@ static int sfp_remove(struct platform_de + + sfp_unregister_socket(sfp->sfp_bus); + ++ rtnl_lock(); ++ sfp_sm_event(sfp, SFP_E_REMOVE); ++ rtnl_unlock(); ++ + return 0; + } + diff --git a/ipq806x/pending-5.4/755-net-sfp-fix-hwmon.patch b/ipq806x/pending-5.4/755-net-sfp-fix-hwmon.patch new file mode 100644 index 0000000..8bfe37b --- /dev/null +++ b/ipq806x/pending-5.4/755-net-sfp-fix-hwmon.patch @@ -0,0 +1,44 @@ +From 5eb0df5023c6ae8a71a7848fd5e1f788d86e51ae Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 3 Dec 2019 18:46:04 +0000 +Subject: [PATCH] net: sfp: fix hwmon + +The referenced commit below allowed more than one hwmon device to be +created per SFP, which is definitely not what we want. Avoid this by +only creating the hwmon device just as we transition to WAITDEV state. + +Fixes: 139d3a212a1f ("net: sfp: allow modules with slow diagnostics to probe") +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -1796,6 +1796,10 @@ static void sfp_sm_module(struct sfp *sf + break; + } + ++ err = sfp_hwmon_insert(sfp); ++ if (err) ++ dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); ++ + sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); + /* fall through */ + case SFP_MOD_WAITDEV: +@@ -1845,15 +1849,6 @@ static void sfp_sm_module(struct sfp *sf + case SFP_MOD_ERROR: + break; + } +- +-#if IS_ENABLED(CONFIG_HWMON) +- if (sfp->sm_mod_state >= SFP_MOD_WAITDEV && +- IS_ERR_OR_NULL(sfp->hwmon_dev)) { +- err = sfp_hwmon_insert(sfp); +- if (err) +- dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); +- } +-#endif + } + + static void sfp_sm_main(struct sfp *sfp, unsigned int event) diff --git a/ipq806x/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch b/ipq806x/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch new file mode 100644 index 0000000..47d8078 --- /dev/null +++ b/ipq806x/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch @@ -0,0 +1,55 @@ +From 4d6bfb6fbb00af38402db4d1ce464e22def9fd9e Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 28 Nov 2019 14:24:40 +0000 +Subject: [PATCH 1/4] net: sfp: use a definition for the fault recovery + attempts + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -172,6 +172,14 @@ static const enum gpiod_flags gpio_flags + #define T_RESET_US 10 + #define T_FAULT_RECOVER msecs_to_jiffies(1000) + ++/* N_FAULT_INIT is the number of recovery attempts at module initialisation ++ * time. If the TX_FAULT signal is not deasserted after this number of ++ * attempts at clearing it, we decide that the module is faulty. ++ * N_FAULT is the same but after the module has initialised. ++ */ ++#define N_FAULT_INIT 5 ++#define N_FAULT 5 ++ + /* SFP module presence detection is poor: the three MOD DEF signals are + * 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. +@@ -1885,7 +1893,7 @@ static void sfp_sm_main(struct sfp *sfp, + sfp_module_tx_enable(sfp); + + /* Initialise the fault clearance retries */ +- sfp->sm_retries = 5; ++ sfp->sm_retries = N_FAULT_INIT; + + /* We need to check the TX_FAULT state, which is not defined + * while TX_DISABLE is asserted. The earliest we want to do +@@ -1925,7 +1933,7 @@ static void sfp_sm_main(struct sfp *sfp, + * or t_start_up, so assume there is a fault. + */ + sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, +- sfp->sm_retries == 5); ++ sfp->sm_retries == N_FAULT_INIT); + } 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. +@@ -1938,7 +1946,7 @@ static void sfp_sm_main(struct sfp *sfp, + sfp_sm_link_check_los(sfp); + + /* Reset the fault retry count */ +- sfp->sm_retries = 5; ++ sfp->sm_retries = N_FAULT; + } + break; + diff --git a/ipq806x/pending-5.4/757-net-sfp-rename-sm_retries.patch b/ipq806x/pending-5.4/757-net-sfp-rename-sm_retries.patch new file mode 100644 index 0000000..0ca73c9 --- /dev/null +++ b/ipq806x/pending-5.4/757-net-sfp-rename-sm_retries.patch @@ -0,0 +1,60 @@ +From bfa3cbb01c7ea34d7369c9bd2ec1b2dc67082b04 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 2 Dec 2019 18:06:44 +0000 +Subject: [PATCH 2/4] net: sfp: rename sm_retries + +Rename sm_retries as sm_fault_retries, as this is what this member is +tracking. + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -234,7 +234,7 @@ struct sfp { + unsigned char sm_mod_tries; + unsigned char sm_dev_state; + unsigned short sm_state; +- unsigned int sm_retries; ++ unsigned char sm_fault_retries; + + struct sfp_eeprom_id id; + unsigned int module_power_mW; +@@ -1490,7 +1490,7 @@ static bool sfp_los_event_inactive(struc + + static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) + { +- if (sfp->sm_retries && !--sfp->sm_retries) { ++ if (sfp->sm_fault_retries && !--sfp->sm_fault_retries) { + dev_err(sfp->dev, + "module persistently indicates fault, disabling\n"); + sfp_sm_next(sfp, SFP_S_TX_DISABLE, 0); +@@ -1893,7 +1893,7 @@ static void sfp_sm_main(struct sfp *sfp, + sfp_module_tx_enable(sfp); + + /* Initialise the fault clearance retries */ +- sfp->sm_retries = N_FAULT_INIT; ++ sfp->sm_fault_retries = N_FAULT_INIT; + + /* We need to check the TX_FAULT state, which is not defined + * while TX_DISABLE is asserted. The earliest we want to do +@@ -1933,7 +1933,7 @@ static void sfp_sm_main(struct sfp *sfp, + * or t_start_up, so assume there is a fault. + */ + sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, +- sfp->sm_retries == N_FAULT_INIT); ++ sfp->sm_fault_retries == N_FAULT_INIT); + } 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. +@@ -1946,7 +1946,7 @@ static void sfp_sm_main(struct sfp *sfp, + sfp_sm_link_check_los(sfp); + + /* Reset the fault retry count */ +- sfp->sm_retries = N_FAULT; ++ sfp->sm_fault_retries = N_FAULT; + } + break; + diff --git a/ipq806x/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch b/ipq806x/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch new file mode 100644 index 0000000..b0bb905 --- /dev/null +++ b/ipq806x/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch @@ -0,0 +1,97 @@ +From 1fba543dc8edf4a43bff3276306648bb27c1e207 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Fri, 29 Nov 2019 00:30:08 +0000 +Subject: [PATCH 3/4] net: sfp: error handling for phy probe + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -1410,7 +1410,7 @@ static void sfp_sm_phy_detach(struct sfp + sfp->mod_phy = NULL; + } + +-static void sfp_sm_probe_phy(struct sfp *sfp, bool is_c45) ++static int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45) + { + struct phy_device *phy; + int err; +@@ -1418,18 +1418,18 @@ static void sfp_sm_probe_phy(struct sfp + phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45); + if (phy == ERR_PTR(-ENODEV)) { + dev_info(sfp->dev, "no PHY detected\n"); +- return; ++ return 0; + } + if (IS_ERR(phy)) { + dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy)); +- return; ++ return PTR_ERR(phy); + } + + err = phy_device_register(phy); + if (err) { + phy_device_free(phy); + dev_err(sfp->dev, "phy_device_register failed: %d\n", err); +- return; ++ return err; + } + + err = sfp_add_phy(sfp->sfp_bus, phy); +@@ -1437,10 +1437,12 @@ static void sfp_sm_probe_phy(struct sfp + phy_device_remove(phy); + phy_device_free(phy); + dev_err(sfp->dev, "sfp_add_phy failed: %d\n", err); +- return; ++ return err; + } + + sfp->mod_phy = phy; ++ ++ return 0; + } + + static void sfp_sm_link_up(struct sfp *sfp) +@@ -1513,21 +1515,24 @@ static void sfp_sm_fault(struct sfp *sfp + * Clause 45 copper SFP+ modules (10G) appear to switch their interface + * mode according to the negotiated line speed. + */ +-static void sfp_sm_probe_for_phy(struct sfp *sfp) ++static int sfp_sm_probe_for_phy(struct sfp *sfp) + { ++ int err = 0; ++ + switch (sfp->id.base.extended_cc) { + case SFF8024_ECC_10GBASE_T_SFI: + case SFF8024_ECC_10GBASE_T_SR: + case SFF8024_ECC_5GBASE_T: + case SFF8024_ECC_2_5GBASE_T: +- sfp_sm_probe_phy(sfp, true); ++ err = sfp_sm_probe_phy(sfp, true); + break; + + default: + if (sfp->id.base.e1000_base_t) +- sfp_sm_probe_phy(sfp, false); ++ err = sfp_sm_probe_phy(sfp, false); + break; + } ++ return err; + } + + static int sfp_module_parse_power(struct sfp *sfp) +@@ -1938,7 +1943,10 @@ static void sfp_sm_main(struct sfp *sfp, + 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); ++ if (sfp_sm_probe_for_phy(sfp)) { ++ sfp_sm_next(sfp, SFP_S_FAIL, 0); ++ break; ++ } + if (sfp_module_start(sfp->sfp_bus)) { + sfp_sm_next(sfp, SFP_S_FAIL, 0); + break; diff --git a/ipq806x/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch b/ipq806x/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch new file mode 100644 index 0000000..d122bc7 --- /dev/null +++ b/ipq806x/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch @@ -0,0 +1,132 @@ +From 6c4efe83a0acf6f06c89ae17b885fa5739eb5be7 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 2 Dec 2019 18:20:22 +0000 +Subject: [PATCH 4/4] net: sfp: re-attempt probing for phy + +Some 1000BASE-T PHY modules take a while for the PHY to wake up. +Retry the probe a number of times before deciding that the module has +no PHY. + +Tested with: + Sourcephotonics SPGBTXCNFC - PHY takes less than 50ms to respond. + Champion One 1000SFPT - PHY takes about 200ms to respond. + Mikrotik S-RJ01 - no PHY + +Signed-off-by: Russell King +--- + drivers/net/phy/sfp.c | 59 ++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 42 insertions(+), 17 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -62,6 +62,7 @@ enum { + SFP_S_FAIL, + SFP_S_WAIT, + SFP_S_INIT, ++ SFP_S_INIT_PHY, + SFP_S_INIT_TX_FAULT, + SFP_S_WAIT_LOS, + SFP_S_LINK_UP, +@@ -126,6 +127,7 @@ static const char * const sm_state_strin + [SFP_S_FAIL] = "fail", + [SFP_S_WAIT] = "wait", + [SFP_S_INIT] = "init", ++ [SFP_S_INIT_PHY] = "init_phy", + [SFP_S_INIT_TX_FAULT] = "init_tx_fault", + [SFP_S_WAIT_LOS] = "wait_los", + [SFP_S_LINK_UP] = "link_up", +@@ -180,6 +182,12 @@ static const enum gpiod_flags gpio_flags + #define N_FAULT_INIT 5 + #define N_FAULT 5 + ++/* T_PHY_RETRY is the time interval between attempts to probe the PHY. ++ * R_PHY_RETRY is the number of attempts. ++ */ ++#define T_PHY_RETRY msecs_to_jiffies(50) ++#define R_PHY_RETRY 12 ++ + /* SFP module presence detection is poor: the three MOD DEF signals are + * 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. +@@ -235,6 +243,7 @@ struct sfp { + unsigned char sm_dev_state; + unsigned short sm_state; + unsigned char sm_fault_retries; ++ unsigned char sm_phy_retries; + + struct sfp_eeprom_id id; + unsigned int module_power_mW; +@@ -1416,10 +1425,8 @@ static int sfp_sm_probe_phy(struct sfp * + int err; + + phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45); +- if (phy == ERR_PTR(-ENODEV)) { +- dev_info(sfp->dev, "no PHY detected\n"); +- return 0; +- } ++ if (phy == ERR_PTR(-ENODEV)) ++ return PTR_ERR(phy); + if (IS_ERR(phy)) { + dev_err(sfp->dev, "mdiobus scan returned %ld\n", PTR_ERR(phy)); + return PTR_ERR(phy); +@@ -1867,6 +1874,7 @@ static void sfp_sm_module(struct sfp *sf + static void sfp_sm_main(struct sfp *sfp, unsigned int event) + { + unsigned long timeout; ++ int ret; + + /* Some events are global */ + if (sfp->sm_state != SFP_S_DOWN && +@@ -1940,22 +1948,39 @@ static void sfp_sm_main(struct sfp *sfp, + sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, + sfp->sm_fault_retries == N_FAULT_INIT); + } 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. +- */ +- if (sfp_sm_probe_for_phy(sfp)) { +- sfp_sm_next(sfp, SFP_S_FAIL, 0); +- break; +- } +- if (sfp_module_start(sfp->sfp_bus)) { +- sfp_sm_next(sfp, SFP_S_FAIL, 0); ++ init_done: ++ sfp->sm_phy_retries = R_PHY_RETRY; ++ goto phy_probe; ++ } ++ break; ++ ++ case SFP_S_INIT_PHY: ++ if (event != SFP_E_TIMEOUT) ++ break; ++ phy_probe: ++ /* TX_FAULT deasserted or we timed out with TX_FAULT ++ * clear. Probe for the PHY and check the LOS state. ++ */ ++ ret = sfp_sm_probe_for_phy(sfp); ++ if (ret == -ENODEV) { ++ if (--sfp->sm_phy_retries) { ++ sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY); + break; ++ } else { ++ dev_info(sfp->dev, "no PHY detected\n"); + } +- sfp_sm_link_check_los(sfp); +- +- /* Reset the fault retry count */ +- sfp->sm_fault_retries = N_FAULT; ++ } else if (ret) { ++ sfp_sm_next(sfp, SFP_S_FAIL, 0); ++ break; + } ++ if (sfp_module_start(sfp->sfp_bus)) { ++ sfp_sm_next(sfp, SFP_S_FAIL, 0); ++ break; ++ } ++ sfp_sm_link_check_los(sfp); ++ ++ /* Reset the fault retry count */ ++ sfp->sm_fault_retries = N_FAULT; + break; + + case SFP_S_INIT_TX_FAULT: diff --git a/ipq806x/pending-5.4/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch b/ipq806x/pending-5.4/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch new file mode 100644 index 0000000..a49b48f --- /dev/null +++ b/ipq806x/pending-5.4/760-net-dsa-mv88e6xxx-fix-vlan-setup.patch @@ -0,0 +1,27 @@ +From a1b291f3f6c80a6c5ccad7283fc472d77a2a4763 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Sun, 22 Dec 2019 12:40:11 +0000 +Subject: [PATCH] net: dsa: mv88e6xxx: fix vlan setup + +Provide an option that drivers can set to indicate they want to receive +vlan configuration even when vlan filtering is disabled. This is safe +for Marvell DSA bridges, which do not look up ingress traffic in the +VTU if the port is in 8021Q disabled state. Whether this change is +suitable for all DSA bridges is not known. + +Signed-off-by: Russell King +Signed-off-by: DENG Qingfang +--- + drivers/net/dsa/mv88e6xxx/chip.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -2663,6 +2663,7 @@ static int mv88e6xxx_setup(struct dsa_sw + + chip->ds = ds; + ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip); ++ ds->configure_vlan_while_not_filtering = true; + + mv88e6xxx_reg_lock(chip); + diff --git a/ipq806x/pending-5.4/761-net-dsa-mt7530-Support-EEE-features.patch b/ipq806x/pending-5.4/761-net-dsa-mt7530-Support-EEE-features.patch new file mode 100644 index 0000000..c2dc35d --- /dev/null +++ b/ipq806x/pending-5.4/761-net-dsa-mt7530-Support-EEE-features.patch @@ -0,0 +1,121 @@ +From 9cfb2d426c38272f245e9e6f62b3552d1ed5852b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= +Date: Tue, 21 Apr 2020 00:18:08 +0200 +Subject: [PATCH] net: dsa: mt7530: Support EEE features +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: René van Dorst +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1407,9 +1407,13 @@ static void mt7530_phylink_mac_config(st + switch (state->speed) { + case SPEED_1000: + mcr_new |= PMCR_FORCE_SPEED_1000; ++ if (priv->eee_enable & BIT(port)) ++ mcr_new |= PMCR_FORCE_EEE1G; + break; + case SPEED_100: + mcr_new |= PMCR_FORCE_SPEED_100; ++ if (priv->eee_enable & BIT(port)) ++ mcr_new |= PMCR_FORCE_EEE100; + break; + } + if (state->duplex == DUPLEX_FULL) { +@@ -1545,6 +1549,54 @@ mt7530_phylink_mac_link_state(struct dsa + return 1; + } + ++static int mt7530_get_mac_eee(struct dsa_switch *ds, int port, ++ struct ethtool_eee *e) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 eeecr, pmsr; ++ ++ e->eee_enabled = !!(priv->eee_enable & BIT(port)); ++ ++ if (e->eee_enabled) { ++ eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port)); ++ e->tx_lpi_enabled = !(eeecr & LPI_MODE_EN); ++ e->tx_lpi_timer = (eeecr >> 4) & 0xFFF; ++ pmsr = mt7530_read(priv, MT7530_PMSR_P(port)); ++ e->eee_active = e->eee_enabled && !!(pmsr & PMSR_EEE1G); ++ } else { ++ e->tx_lpi_enabled = 0; ++ e->tx_lpi_timer = 0; ++ e->eee_active = 0; ++ } ++ ++ return 0; ++} ++ ++static int mt7530_set_mac_eee(struct dsa_switch *ds, int port, ++ struct ethtool_eee *e) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 eeecr; ++ ++ if (e->tx_lpi_enabled && e->tx_lpi_timer > 0xFFF) ++ return -EINVAL; ++ ++ if (e->eee_enabled) { ++ priv->eee_enable |= BIT(port); ++ //MT7530_PMEEECR_P ++ eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port)); ++ eeecr &= 0xFFFF0000; ++ if (!e->tx_lpi_enabled) ++ eeecr |= LPI_MODE_EN; ++ eeecr |= LPI_THRESH(e->tx_lpi_timer); ++ mt7530_write(priv, MT7530_PMEEECR_P(port), eeecr); ++ } else { ++ priv->eee_enable &= ~(BIT(port)); ++ } ++ ++ return 0; ++} ++ + static const struct dsa_switch_ops mt7530_switch_ops = { + .get_tag_protocol = mtk_get_tag_protocol, + .setup = mt7530_setup, +@@ -1572,6 +1624,8 @@ static const struct dsa_switch_ops mt753 + .phylink_mac_config = mt7530_phylink_mac_config, + .phylink_mac_link_down = mt7530_phylink_mac_link_down, + .phylink_mac_link_up = mt7530_phylink_mac_link_up, ++ .get_mac_eee = mt7530_get_mac_eee, ++ .set_mac_eee = mt7530_set_mac_eee, + }; + + static const struct of_device_id mt7530_of_match[] = { +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -212,6 +212,8 @@ enum mt7530_vlan_port_attr { + #define PMCR_RX_EN BIT(13) + #define PMCR_BACKOFF_EN BIT(9) + #define PMCR_BACKPR_EN BIT(8) ++#define PMCR_FORCE_EEE1G BIT(7) ++#define PMCR_FORCE_EEE100 BIT(6) + #define PMCR_TX_FC_EN BIT(5) + #define PMCR_RX_FC_EN BIT(4) + #define PMCR_FORCE_SPEED_1000 BIT(3) +@@ -233,6 +235,12 @@ enum mt7530_vlan_port_attr { + #define PMSR_DPX BIT(1) + #define PMSR_LINK BIT(0) + ++#define MT7530_PMEEECR_P(x) (0x3004 + (x) * 0x100) ++#define WAKEUP_TIME_1000(x) ((x & 0xFF) << 24) ++#define WAKEUP_TIME_100(x) ((x & 0xFF) << 16) ++#define LPI_THRESH(x) ((x & 0xFFF) << 4) ++#define LPI_MODE_EN BIT(0) ++ + /* Register for MIB */ + #define MT7530_PORT_MIB_COUNTER(x) (0x4000 + (x) * 0x100) + #define MT7530_MIB_CCR 0x4fe0 +@@ -471,6 +479,7 @@ struct mt7530_priv { + unsigned int p5_intf_sel; + u8 mirror_rx; + u8 mirror_tx; ++ u8 eee_enable; + + struct mt7530_port ports[MT7530_NUM_PORTS]; + /* protect among processes for registers access*/ diff --git a/ipq806x/pending-5.4/762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch b/ipq806x/pending-5.4/762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch new file mode 100644 index 0000000..bfa2d37 --- /dev/null +++ b/ipq806x/pending-5.4/762-net-bridge-switchdev-Refactor-br_switchdev_fdb_notif.patch @@ -0,0 +1,71 @@ +From 46fe6cecb296d850c1ee2b333e57093ac4b733f3 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Sat, 16 Jan 2021 02:25:09 +0100 +Subject: [PATCH] net: bridge: switchdev: Refactor br_switchdev_fdb_notify + +Instead of having to add more and more arguments to +br_switchdev_fdb_call_notifiers, get rid of it and build the info +struct directly in br_switchdev_fdb_notify. + +Signed-off-by: Tobias Waldekranz +Reviewed-by: Vladimir Oltean +--- + net/bridge/br_switchdev.c | 37 +++++++++++-------------------------- + 1 file changed, 11 insertions(+), 26 deletions(-) + +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -102,42 +102,27 @@ int br_switchdev_set_port_flag(struct ne + return 0; + } + +-static void +-br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac, +- u16 vid, struct net_device *dev, +- bool added_by_user, bool offloaded) +-{ +- struct switchdev_notifier_fdb_info info; +- unsigned long notifier_type; +- +- info.addr = mac; +- info.vid = vid; +- info.added_by_user = added_by_user; +- info.offloaded = offloaded; +- notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE; +- call_switchdev_notifiers(notifier_type, dev, &info.info, NULL); +-} +- + void + br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) + { ++ struct switchdev_notifier_fdb_info info = { ++ .addr = fdb->key.addr.addr, ++ .vid = fdb->key.vlan_id, ++ .added_by_user = fdb->added_by_user, ++ .offloaded = fdb->offloaded, ++ }; ++ + if (!fdb->dst) + return; + + switch (type) { + case RTM_DELNEIGH: +- br_switchdev_fdb_call_notifiers(false, fdb->key.addr.addr, +- fdb->key.vlan_id, +- fdb->dst->dev, +- fdb->added_by_user, +- fdb->offloaded); ++ call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE, ++ fdb->dst->dev, &info.info, NULL); + break; + case RTM_NEWNEIGH: +- br_switchdev_fdb_call_notifiers(true, fdb->key.addr.addr, +- fdb->key.vlan_id, +- fdb->dst->dev, +- fdb->added_by_user, +- fdb->offloaded); ++ call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE, ++ fdb->dst->dev, &info.info, NULL); + break; + } + } diff --git a/ipq806x/pending-5.4/763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch b/ipq806x/pending-5.4/763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch new file mode 100644 index 0000000..49d6f07 --- /dev/null +++ b/ipq806x/pending-5.4/763-net-bridge-switchdev-Include-local-flag-in-FDB-notif.patch @@ -0,0 +1,42 @@ +From ec5be4f79026282925ae383caa431a8d41e3456a Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Sat, 16 Jan 2021 02:25:10 +0100 +Subject: [PATCH] net: bridge: switchdev: Include local flag in FDB + notifications + +Some switchdev drivers, notably DSA, ignore all dynamically learned +address notifications (!added_by_user) as these are autonomously added +by the switch. Previously, such a notification was indistinguishable +from a local address notification. Include a local bit in the +notification so that the two classes can be discriminated. + +This allows DSA-like devices to add local addresses to the hardware +FDB (with the CPU as the destination), thereby avoiding flows towards +the CPU being flooded by the switch as unknown unicast. + +Signed-off-by: Tobias Waldekranz +--- + include/net/switchdev.h | 1 + + net/bridge/br_switchdev.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/include/net/switchdev.h ++++ b/include/net/switchdev.h +@@ -124,6 +124,7 @@ struct switchdev_notifier_fdb_info { + const unsigned char *addr; + u16 vid; + u8 added_by_user:1, ++ local:1, + offloaded:1; + }; + +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -109,6 +109,7 @@ br_switchdev_fdb_notify(const struct net + .addr = fdb->key.addr.addr, + .vid = fdb->key.vlan_id, + .added_by_user = fdb->added_by_user, ++ .local = fdb->is_local, + .offloaded = fdb->offloaded, + }; + diff --git a/ipq806x/pending-5.4/764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch b/ipq806x/pending-5.4/764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch new file mode 100644 index 0000000..8b869dd --- /dev/null +++ b/ipq806x/pending-5.4/764-net-bridge-switchdev-Send-FDB-notifications-for-host.patch @@ -0,0 +1,94 @@ +From 2e50fd9322047253c327550b4485cf8761035a8c Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Sat, 16 Jan 2021 02:25:11 +0100 +Subject: [PATCH] net: bridge: switchdev: Send FDB notifications for host + addresses + +Treat addresses added to the bridge itself in the same way as regular +ports and send out a notification so that drivers may sync it down to +the hardware FDB. + +Signed-off-by: Tobias Waldekranz +--- + net/bridge/br_fdb.c | 4 ++-- + net/bridge/br_private.h | 7 ++++--- + net/bridge/br_switchdev.c | 11 +++++------ + 3 files changed, 11 insertions(+), 11 deletions(-) + +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -581,7 +581,7 @@ void br_fdb_update(struct net_bridge *br + + /* fastpath: update of existing entry */ + if (unlikely(source != fdb->dst && !fdb->is_sticky)) { +- br_switchdev_fdb_notify(fdb, RTM_DELNEIGH); ++ br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH); + fdb->dst = source; + fdb_modified = true; + /* Take over HW learned entry */ +@@ -697,7 +697,7 @@ static void fdb_notify(struct net_bridge + int err = -ENOBUFS; + + if (swdev_notify) +- br_switchdev_fdb_notify(fdb, type); ++ br_switchdev_fdb_notify(br, fdb, type); + + skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); + if (skb == NULL) +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -1203,8 +1203,8 @@ bool nbp_switchdev_allowed_egress(const + int br_switchdev_set_port_flag(struct net_bridge_port *p, + unsigned long flags, + unsigned long mask); +-void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, +- int type); ++void br_switchdev_fdb_notify(struct net_bridge *br, ++ const struct net_bridge_fdb_entry *fdb, int type); + int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags, + struct netlink_ext_ack *extack); + int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid); +@@ -1250,7 +1250,8 @@ static inline int br_switchdev_port_vlan + } + + static inline void +-br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) ++br_switchdev_fdb_notify(struct net_bridge *br, ++ const struct net_bridge_fdb_entry *fdb, int type) + { + } + +--- a/net/bridge/br_switchdev.c ++++ b/net/bridge/br_switchdev.c +@@ -103,7 +103,8 @@ int br_switchdev_set_port_flag(struct ne + } + + void +-br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) ++br_switchdev_fdb_notify(struct net_bridge *br, ++ const struct net_bridge_fdb_entry *fdb, int type) + { + struct switchdev_notifier_fdb_info info = { + .addr = fdb->key.addr.addr, +@@ -112,18 +113,16 @@ br_switchdev_fdb_notify(const struct net + .local = fdb->is_local, + .offloaded = fdb->offloaded, + }; +- +- if (!fdb->dst) +- return; ++ struct net_device *dev = fdb->dst ? fdb->dst->dev : br->dev; + + switch (type) { + case RTM_DELNEIGH: + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE, +- fdb->dst->dev, &info.info, NULL); ++ dev, &info.info, NULL); + break; + case RTM_NEWNEIGH: + call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE, +- fdb->dst->dev, &info.info, NULL); ++ dev, &info.info, NULL); + break; + } + } diff --git a/ipq806x/pending-5.4/765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch b/ipq806x/pending-5.4/765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch new file mode 100644 index 0000000..d951246 --- /dev/null +++ b/ipq806x/pending-5.4/765-net-dsa-Include-local-addresses-in-assisted-CPU-port.patch @@ -0,0 +1,36 @@ +From dd082716b43a3684b2f473ae5d1e76d1c076d86d Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Sat, 16 Jan 2021 02:25:12 +0100 +Subject: [PATCH] net: dsa: Include local addresses in assisted CPU port + learning + +Add local addresses (i.e. the ports' MAC addresses) to the hardware +FDB when assisted CPU port learning is enabled. + +NOTE: The bridge's own MAC address is also "local". If that address is +not shared with any port, the bridge's MAC is not be added by this +functionality - but the following commit takes care of that case. + +Signed-off-by: Tobias Waldekranz +--- + net/dsa/slave.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1698,10 +1698,12 @@ static int dsa_slave_switchdev_event(str + fdb_info = ptr; + + if (dsa_slave_dev_check(dev)) { +- if (!fdb_info->added_by_user) +- return NOTIFY_OK; +- + dp = dsa_slave_to_port(dev); ++ ++ if (fdb_info->local && dp->ds->assisted_learning_on_cpu_port) ++ dp = dp->cpu_dp; ++ else if (!fdb_info->added_by_user) ++ return NOTIFY_OK; + } else { + /* Snoop addresses learnt on foreign interfaces + * bridged with us, for switches that don't diff --git a/ipq806x/pending-5.4/766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch b/ipq806x/pending-5.4/766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch new file mode 100644 index 0000000..46504ae --- /dev/null +++ b/ipq806x/pending-5.4/766-net-dsa-Include-bridge-addresses-in-assisted-CPU-por.patch @@ -0,0 +1,30 @@ +From 0663ebde114a6fb2c28c622ba5212b302d4d2581 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Sat, 16 Jan 2021 02:25:13 +0100 +Subject: [PATCH] net: dsa: Include bridge addresses in assisted CPU port + learning + +Now that notifications are sent out for addresses added to the bridge +itself, extend DSA to include those addresses in the hardware FDB when +assisted CPU port learning is enabled. + +Signed-off-by: Tobias Waldekranz +--- + net/dsa/slave.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1712,7 +1712,11 @@ static int dsa_slave_switchdev_event(str + struct net_device *br_dev; + struct dsa_slave_priv *p; + +- br_dev = netdev_master_upper_dev_get_rcu(dev); ++ if (netif_is_bridge_master(dev)) ++ br_dev = dev; ++ else ++ br_dev = netdev_master_upper_dev_get_rcu(dev); ++ + if (!br_dev) + return NOTIFY_DONE; + diff --git a/ipq806x/pending-5.4/767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch b/ipq806x/pending-5.4/767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch new file mode 100644 index 0000000..e626086 --- /dev/null +++ b/ipq806x/pending-5.4/767-net-dsa-Sync-static-FDB-entries-on-foreign-interface.patch @@ -0,0 +1,56 @@ +From 81e39fd78db82fb51b05fff309b9c521f1a0bc5a Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Sat, 16 Jan 2021 02:25:14 +0100 +Subject: [PATCH] net: dsa: Sync static FDB entries on foreign interfaces to + hardware + +Reuse the "assisted_learning_on_cpu_port" functionality to always add +entries for user-configured entries on foreign interfaces, even if +assisted_learning_on_cpu_port is not enabled. E.g. in this situation: + + br0 + / \ +swp0 dummy0 + +$ bridge fdb add 02:00:de:ad:00:01 dev dummy0 vlan 1 master + +Results in DSA adding an entry in the hardware FDB, pointing this +address towards the CPU port. + +The same is true for entries added to the bridge itself, e.g: + +$ bridge fdb add 02:00:de:ad:00:01 dev br0 vlan 1 self + +Signed-off-by: Tobias Waldekranz +--- + net/dsa/slave.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1705,9 +1705,12 @@ static int dsa_slave_switchdev_event(str + else if (!fdb_info->added_by_user) + return NOTIFY_OK; + } else { +- /* Snoop addresses learnt on foreign interfaces +- * bridged with us, for switches that don't +- * automatically learn SA from CPU-injected traffic ++ /* Snoop addresses added to foreign interfaces ++ * bridged with us, or the bridge ++ * itself. Dynamically learned addresses can ++ * also be added for switches that don't ++ * automatically learn SA from CPU-injected ++ * traffic. + */ + struct net_device *br_dev; + struct dsa_slave_priv *p; +@@ -1729,7 +1732,8 @@ static int dsa_slave_switchdev_event(str + + dp = p->dp->cpu_dp; + +- if (!dp->ds->assisted_learning_on_cpu_port) ++ if (!fdb_info->added_by_user && ++ !dp->ds->assisted_learning_on_cpu_port) + return NOTIFY_DONE; + } + diff --git a/ipq806x/pending-5.4/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch b/ipq806x/pending-5.4/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch new file mode 100644 index 0000000..cb421f1 --- /dev/null +++ b/ipq806x/pending-5.4/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch @@ -0,0 +1,27 @@ +From: Tobias Waldekranz +Subject: [RFC net-next 7/7] net: dsa: mv88e6xxx: Request assisted learning on CPU port +Date: Sat, 16 Jan 2021 02:25:15 +0100 +Archived-At: + +While the hardware is capable of performing learning on the CPU port, +it requires alot of additions to the bridge's forwarding path in order +to handle multi-destination traffic correctly. + +Until that is in place, opt for the next best thing and let DSA sync +the relevant addresses down to the hardware FDB. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -5080,6 +5080,7 @@ static int mv88e6xxx_register_switch(str + ds->ops = &mv88e6xxx_switch_ops; + ds->ageing_time_min = chip->info->age_time_coeff; + ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; ++ ds->assisted_learning_on_cpu_port = true; + + dev_set_drvdata(dev, ds); + diff --git a/ipq806x/pending-5.4/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch b/ipq806x/pending-5.4/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch new file mode 100644 index 0000000..2f0c793 --- /dev/null +++ b/ipq806x/pending-5.4/770-00-net-ethernet-mtk_eth_soc-use-napi_consume_skb.patch @@ -0,0 +1,72 @@ +From: Felix Fietkau +Date: Mon, 8 Jun 2020 17:01:12 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: use napi_consume_skb + +Should improve performance, since it can use bulk free + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -874,7 +874,8 @@ static int txd_to_idx(struct mtk_tx_ring + return ((void *)dma - (void *)ring->dma) / sizeof(*dma); + } + +-static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf) ++static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, ++ bool napi) + { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { + if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { +@@ -906,8 +907,12 @@ static void mtk_tx_unmap(struct mtk_eth + + tx_buf->flags = 0; + if (tx_buf->skb && +- (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) +- dev_kfree_skb_any(tx_buf->skb); ++ (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) { ++ if (napi) ++ napi_consume_skb(tx_buf->skb, napi); ++ else ++ dev_kfree_skb_any(tx_buf->skb); ++ } + tx_buf->skb = NULL; + } + +@@ -1085,7 +1090,7 @@ err_dma: + tx_buf = mtk_desc_to_tx_buf(ring, itxd); + + /* unmap dma */ +- mtk_tx_unmap(eth, tx_buf); ++ mtk_tx_unmap(eth, tx_buf, false); + + itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) +@@ -1403,7 +1408,7 @@ static int mtk_poll_tx_qdma(struct mtk_e + done[mac]++; + budget--; + } +- mtk_tx_unmap(eth, tx_buf); ++ mtk_tx_unmap(eth, tx_buf, true); + + ring->last_free = desc; + atomic_inc(&ring->free_count); +@@ -1440,7 +1445,7 @@ static int mtk_poll_tx_pdma(struct mtk_e + budget--; + } + +- mtk_tx_unmap(eth, tx_buf); ++ mtk_tx_unmap(eth, tx_buf, true); + + desc = &ring->dma[cpu]; + ring->last_free = desc; +@@ -1642,7 +1647,7 @@ static void mtk_tx_clean(struct mtk_eth + + if (ring->buf) { + for (i = 0; i < MTK_DMA_SIZE; i++) +- mtk_tx_unmap(eth, &ring->buf[i]); ++ mtk_tx_unmap(eth, &ring->buf[i], false); + kfree(ring->buf); + ring->buf = NULL; + } diff --git a/ipq806x/pending-5.4/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch b/ipq806x/pending-5.4/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch new file mode 100644 index 0000000..922c35a --- /dev/null +++ b/ipq806x/pending-5.4/770-01-net-ethernet-mtk_eth_soc-significantly-reduce-mdio-b.patch @@ -0,0 +1,26 @@ +From: Felix Fietkau +Date: Mon, 8 Jun 2020 17:02:39 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: significantly reduce mdio bus + access latency + +usleep_range often ends up sleeping much longer than the 10-20us provided +as a range here. This causes significant latency in mdio bus acceses, +which easily adds multiple seconds to the boot time on MT7621 when polling +DSA slave ports. +Use cond_resched instead of usleep_range, since the MDIO access does not +take much time + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -85,7 +85,7 @@ static int mtk_mdio_busy_wait(struct mtk + return 0; + if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT)) + break; +- usleep_range(10, 20); ++ cond_resched(); + } + + dev_err(eth->dev, "mdio: MDIO timeout\n"); diff --git a/ipq806x/pending-5.4/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch b/ipq806x/pending-5.4/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch new file mode 100644 index 0000000..6eeae69 --- /dev/null +++ b/ipq806x/pending-5.4/770-03-net-ethernet-mtk_eth_soc-fix-unnecessary-tx-queue-st.patch @@ -0,0 +1,50 @@ +From: Felix Fietkau +Date: Wed, 26 Aug 2020 16:55:54 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix unnecessary tx queue + stops + +When running short on descriptors, only stop the queue for the netdev that tx +was attempted for. By the time the something tries to send on the other netdev, +the ring might have some more room already + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1147,17 +1147,6 @@ static void mtk_wake_queue(struct mtk_et + } + } + +-static void mtk_stop_queue(struct mtk_eth *eth) +-{ +- int i; +- +- for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i]) +- continue; +- netif_stop_queue(eth->netdev[i]); +- } +-} +- + static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); +@@ -1178,7 +1167,7 @@ static int mtk_start_xmit(struct sk_buff + + tx_num = mtk_cal_txd_req(skb); + if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { +- mtk_stop_queue(eth); ++ netif_stop_queue(dev); + netif_err(eth, tx_queued, dev, + "Tx Ring full when queue awake!\n"); + spin_unlock(ð->page_lock); +@@ -1204,7 +1193,7 @@ static int mtk_start_xmit(struct sk_buff + goto drop; + + if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) +- mtk_stop_queue(eth); ++ netif_stop_queue(dev); + + spin_unlock(ð->page_lock); + diff --git a/ipq806x/pending-5.4/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch b/ipq806x/pending-5.4/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch new file mode 100644 index 0000000..cd042ce --- /dev/null +++ b/ipq806x/pending-5.4/770-04-net-ethernet-mtk_eth_soc-use-larger-burst-size-for-q.patch @@ -0,0 +1,32 @@ +From: Felix Fietkau +Date: Wed, 26 Aug 2020 16:58:55 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: use larger burst size for + qdma tx + +Improves tx performance + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2208,7 +2208,7 @@ static int mtk_start_dma(struct mtk_eth + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { + mtk_w32(eth, + MTK_TX_WB_DDONE | MTK_TX_DMA_EN | +- MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO | ++ MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | + MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | + MTK_RX_BT_32DWORDS, + MTK_QDMA_GLO_CFG); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -197,7 +197,7 @@ + #define MTK_RX_BT_32DWORDS (3 << 11) + #define MTK_NDP_CO_PRO BIT(10) + #define MTK_TX_WB_DDONE BIT(6) +-#define MTK_DMA_SIZE_16DWORDS (2 << 4) ++#define MTK_TX_BT_32DWORDS (3 << 4) + #define MTK_RX_DMA_BUSY BIT(3) + #define MTK_TX_DMA_BUSY BIT(1) + #define MTK_RX_DMA_EN BIT(2) diff --git a/ipq806x/pending-5.4/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch b/ipq806x/pending-5.4/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch new file mode 100644 index 0000000..f68cbc3 --- /dev/null +++ b/ipq806x/pending-5.4/770-05-net-ethernet-mtk_eth_soc-increase-DMA-ring-sizes.patch @@ -0,0 +1,21 @@ +From: Felix Fietkau +Date: Wed, 26 Aug 2020 16:59:41 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: increase DMA ring sizes + +256 descriptors is not enough for multi-gigabit traffic under load on MT7622. +Bump it to 512 to improve performance + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -19,7 +19,7 @@ + #define MTK_QDMA_PAGE_SIZE 2048 + #define MTK_MAX_RX_LENGTH 1536 + #define MTK_TX_DMA_BUF_LEN 0x3fff +-#define MTK_DMA_SIZE 256 ++#define MTK_DMA_SIZE 512 + #define MTK_NAPI_WEIGHT 64 + #define MTK_MAC_COUNT 2 + #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) diff --git a/ipq806x/pending-5.4/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch b/ipq806x/pending-5.4/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch new file mode 100644 index 0000000..9302f0b --- /dev/null +++ b/ipq806x/pending-5.4/770-06-net-ethernet-mtk_eth_soc-implement-dynamic-interrupt.patch @@ -0,0 +1,281 @@ +From: Felix Fietkau +Date: Wed, 26 Aug 2020 17:02:30 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: implement dynamic interrupt + moderation + +Reduces the number of interrupts under load + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -10,6 +10,7 @@ if NET_VENDOR_MEDIATEK + config NET_MEDIATEK_SOC + tristate "MediaTek SoC Gigabit Ethernet support" + select PHYLINK ++ select DIMLIB + ---help--- + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1249,12 +1249,13 @@ static void mtk_update_rx_cpu_idx(struct + static int mtk_poll_rx(struct napi_struct *napi, int budget, + struct mtk_eth *eth) + { ++ struct dim_sample dim_sample = {}; + struct mtk_rx_ring *ring; + int idx; + struct sk_buff *skb; + u8 *data, *new_data; + struct mtk_rx_dma *rxd, trxd; +- int done = 0; ++ int done = 0, bytes = 0; + + while (done < budget) { + struct net_device *netdev; +@@ -1328,6 +1329,7 @@ static int mtk_poll_rx(struct napi_struc + else + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); ++ bytes += pktlen; + + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && + (trxd.rxd2 & RX_DMA_VTAG)) +@@ -1359,6 +1361,12 @@ rx_done: + mtk_update_rx_cpu_idx(eth); + } + ++ eth->rx_packets += done; ++ eth->rx_bytes += bytes; ++ dim_update_sample(eth->rx_events, eth->rx_packets, eth->rx_bytes, ++ &dim_sample); ++ net_dim(ð->rx_dim, dim_sample); ++ + return done; + } + +@@ -1451,6 +1459,7 @@ static int mtk_poll_tx_pdma(struct mtk_e + static int mtk_poll_tx(struct mtk_eth *eth, int budget) + { + struct mtk_tx_ring *ring = ð->tx_ring; ++ struct dim_sample dim_sample = {}; + unsigned int done[MTK_MAX_DEVS]; + unsigned int bytes[MTK_MAX_DEVS]; + int total = 0, i; +@@ -1468,8 +1477,14 @@ static int mtk_poll_tx(struct mtk_eth *e + continue; + netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); + total += done[i]; ++ eth->tx_packets += done[i]; ++ eth->tx_bytes += bytes[i]; + } + ++ dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes, ++ &dim_sample); ++ net_dim(ð->tx_dim, dim_sample); ++ + if (mtk_queue_stopped(eth) && + (atomic_read(&ring->free_count) > ring->thresh)) + mtk_wake_queue(eth); +@@ -2144,6 +2159,7 @@ static irqreturn_t mtk_handle_irq_rx(int + { + struct mtk_eth *eth = _eth; + ++ eth->rx_events++; + if (likely(napi_schedule_prep(ð->rx_napi))) { + __napi_schedule(ð->rx_napi); + mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); +@@ -2156,6 +2172,7 @@ static irqreturn_t mtk_handle_irq_tx(int + { + struct mtk_eth *eth = _eth; + ++ eth->tx_events++; + if (likely(napi_schedule_prep(ð->tx_napi))) { + __napi_schedule(ð->tx_napi); + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); +@@ -2332,6 +2349,9 @@ static int mtk_stop(struct net_device *d + napi_disable(ð->tx_napi); + napi_disable(ð->rx_napi); + ++ cancel_work_sync(ð->rx_dim.work); ++ cancel_work_sync(ð->tx_dim.work); ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) + mtk_stop_dma(eth, MTK_QDMA_GLO_CFG); + mtk_stop_dma(eth, MTK_PDMA_GLO_CFG); +@@ -2381,6 +2401,64 @@ err_disable_clks: + return ret; + } + ++static void mtk_dim_rx(struct work_struct *work) ++{ ++ struct dim *dim = container_of(work, struct dim, work); ++ struct mtk_eth *eth = container_of(dim, struct mtk_eth, rx_dim); ++ struct dim_cq_moder cur_profile; ++ u32 val, cur; ++ ++ cur_profile = net_dim_get_rx_moderation(eth->rx_dim.mode, ++ dim->profile_ix); ++ spin_lock_bh(ð->dim_lock); ++ ++ val = mtk_r32(eth, MTK_PDMA_DELAY_INT); ++ val &= MTK_PDMA_DELAY_TX_MASK; ++ val |= MTK_PDMA_DELAY_RX_EN; ++ ++ cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK); ++ val |= cur << MTK_PDMA_DELAY_RX_PTIME_SHIFT; ++ ++ cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); ++ val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT; ++ ++ mtk_w32(eth, val, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, val, MTK_QDMA_DELAY_INT); ++ ++ spin_unlock_bh(ð->dim_lock); ++ ++ dim->state = DIM_START_MEASURE; ++} ++ ++static void mtk_dim_tx(struct work_struct *work) ++{ ++ struct dim *dim = container_of(work, struct dim, work); ++ struct mtk_eth *eth = container_of(dim, struct mtk_eth, tx_dim); ++ struct dim_cq_moder cur_profile; ++ u32 val, cur; ++ ++ cur_profile = net_dim_get_tx_moderation(eth->tx_dim.mode, ++ dim->profile_ix); ++ spin_lock_bh(ð->dim_lock); ++ ++ val = mtk_r32(eth, MTK_PDMA_DELAY_INT); ++ val &= MTK_PDMA_DELAY_RX_MASK; ++ val |= MTK_PDMA_DELAY_TX_EN; ++ ++ cur = min_t(u32, DIV_ROUND_UP(cur_profile.usec, 20), MTK_PDMA_DELAY_PTIME_MASK); ++ val |= cur << MTK_PDMA_DELAY_TX_PTIME_SHIFT; ++ ++ cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); ++ val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT; ++ ++ mtk_w32(eth, val, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, val, MTK_QDMA_DELAY_INT); ++ ++ spin_unlock_bh(ð->dim_lock); ++ ++ dim->state = DIM_START_MEASURE; ++} ++ + static int mtk_hw_init(struct mtk_eth *eth) + { + int i, val, ret; +@@ -2402,9 +2480,6 @@ static int mtk_hw_init(struct mtk_eth *e + goto err_disable_pm; + } + +- /* enable interrupt delay for RX */ +- mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); +- + /* disable delay and normal interrupt */ + mtk_tx_irq_disable(eth, ~0); + mtk_rx_irq_disable(eth, ~0); +@@ -2443,11 +2518,10 @@ static int mtk_hw_init(struct mtk_eth *e + /* Enable RX VLan Offloading */ + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + +- /* enable interrupt delay for RX */ +- mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); ++ mtk_dim_rx(ð->rx_dim.work); ++ mtk_dim_tx(ð->tx_dim.work); + + /* disable delay and normal interrupt */ +- mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); + mtk_tx_irq_disable(eth, ~0); + mtk_rx_irq_disable(eth, ~0); + +@@ -2951,6 +3025,13 @@ static int mtk_probe(struct platform_dev + spin_lock_init(ð->page_lock); + spin_lock_init(ð->tx_irq_lock); + spin_lock_init(ð->rx_irq_lock); ++ spin_lock_init(ð->dim_lock); ++ ++ eth->rx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; ++ INIT_WORK(ð->rx_dim.work, mtk_dim_rx); ++ ++ eth->tx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; ++ INIT_WORK(ð->tx_dim.work, mtk_dim_tx); + + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #define MTK_QDMA_PAGE_SIZE 2048 + #define MTK_MAX_RX_LENGTH 1536 +@@ -131,13 +132,18 @@ + + /* PDMA Delay Interrupt Register */ + #define MTK_PDMA_DELAY_INT 0xa0c ++#define MTK_PDMA_DELAY_RX_MASK GENMASK(15, 0) + #define MTK_PDMA_DELAY_RX_EN BIT(15) +-#define MTK_PDMA_DELAY_RX_PINT 4 + #define MTK_PDMA_DELAY_RX_PINT_SHIFT 8 +-#define MTK_PDMA_DELAY_RX_PTIME 4 +-#define MTK_PDMA_DELAY_RX_DELAY \ +- (MTK_PDMA_DELAY_RX_EN | MTK_PDMA_DELAY_RX_PTIME | \ +- (MTK_PDMA_DELAY_RX_PINT << MTK_PDMA_DELAY_RX_PINT_SHIFT)) ++#define MTK_PDMA_DELAY_RX_PTIME_SHIFT 0 ++ ++#define MTK_PDMA_DELAY_TX_MASK GENMASK(31, 16) ++#define MTK_PDMA_DELAY_TX_EN BIT(31) ++#define MTK_PDMA_DELAY_TX_PINT_SHIFT 24 ++#define MTK_PDMA_DELAY_TX_PTIME_SHIFT 16 ++ ++#define MTK_PDMA_DELAY_PINT_MASK 0x7f ++#define MTK_PDMA_DELAY_PTIME_MASK 0xff + + /* PDMA Interrupt Status Register */ + #define MTK_PDMA_INT_STATUS 0xa20 +@@ -219,6 +225,7 @@ + /* QDMA Interrupt Status Register */ + #define MTK_QDMA_INT_STATUS 0x1A18 + #define MTK_RX_DONE_DLY BIT(30) ++#define MTK_TX_DONE_DLY BIT(28) + #define MTK_RX_DONE_INT3 BIT(19) + #define MTK_RX_DONE_INT2 BIT(18) + #define MTK_RX_DONE_INT1 BIT(17) +@@ -228,8 +235,7 @@ + #define MTK_TX_DONE_INT1 BIT(1) + #define MTK_TX_DONE_INT0 BIT(0) + #define MTK_RX_DONE_INT MTK_RX_DONE_DLY +-#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ +- MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) ++#define MTK_TX_DONE_INT MTK_TX_DONE_DLY + + /* QDMA Interrupt grouping registers */ + #define MTK_QDMA_INT_GRP1 0x1a20 +@@ -912,6 +918,18 @@ struct mtk_eth { + + const struct mtk_soc_data *soc; + ++ spinlock_t dim_lock; ++ ++ u32 rx_events; ++ u32 rx_packets; ++ u32 rx_bytes; ++ struct dim rx_dim; ++ ++ u32 tx_events; ++ u32 tx_packets; ++ u32 tx_bytes; ++ struct dim tx_dim; ++ + u32 tx_int_mask_reg; + u32 tx_int_status_reg; + u32 rx_dma_l4_valid; diff --git a/ipq806x/pending-5.4/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch b/ipq806x/pending-5.4/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch new file mode 100644 index 0000000..b280b6c --- /dev/null +++ b/ipq806x/pending-5.4/770-08-net-ethernet-mtk_eth_soc-cache-hardware-pointer-of-l.patch @@ -0,0 +1,67 @@ +From: Felix Fietkau +Date: Thu, 27 Aug 2020 06:32:03 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: cache hardware pointer of last + freed tx descriptor + +The value is only updated by the CPU, so it is cheaper to access from the ring +data structure than from a hardware register + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1379,7 +1379,7 @@ static int mtk_poll_tx_qdma(struct mtk_e + struct mtk_tx_buf *tx_buf; + u32 cpu, dma; + +- cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); ++ cpu = ring->last_free_ptr; + dma = mtk_r32(eth, MTK_QTX_DRX_PTR); + + desc = mtk_qdma_phys_to_virt(ring, cpu); +@@ -1413,6 +1413,7 @@ static int mtk_poll_tx_qdma(struct mtk_e + cpu = next_cpu; + } + ++ ring->last_free_ptr = cpu; + mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); + + return budget; +@@ -1613,6 +1614,7 @@ static int mtk_tx_alloc(struct mtk_eth * + atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); + ring->next_free = &ring->dma[0]; + ring->last_free = &ring->dma[MTK_DMA_SIZE - 1]; ++ ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); + ring->thresh = MAX_SKB_FRAGS; + + /* make sure that all changes to the dma ring are flushed before we +@@ -1626,9 +1628,7 @@ static int mtk_tx_alloc(struct mtk_eth * + mtk_w32(eth, + ring->phys + ((MTK_DMA_SIZE - 1) * sz), + MTK_QTX_CRX_PTR); +- mtk_w32(eth, +- ring->phys + ((MTK_DMA_SIZE - 1) * sz), +- MTK_QTX_DRX_PTR); ++ mtk_w32(eth, ring->last_free_ptr, MTK_QTX_DRX_PTR); + mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, + MTK_QTX_CFG(0)); + } else { +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -644,6 +644,7 @@ struct mtk_tx_buf { + * @phys: The physical addr of tx_buf + * @next_free: Pointer to the next free descriptor + * @last_free: Pointer to the last free descriptor ++ * @last_free_ptr: Hardware pointer value of the last free descriptor + * @thresh: The threshold of minimum amount of free descriptors + * @free_count: QDMA uses a linked list. Track how many free descriptors + * are present +@@ -654,6 +655,7 @@ struct mtk_tx_ring { + dma_addr_t phys; + struct mtk_tx_dma *next_free; + struct mtk_tx_dma *last_free; ++ u32 last_free_ptr; + u16 thresh; + atomic_t free_count; + int dma_size; diff --git a/ipq806x/pending-5.4/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch b/ipq806x/pending-5.4/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch new file mode 100644 index 0000000..c2f5013 --- /dev/null +++ b/ipq806x/pending-5.4/770-09-net-ethernet-mtk_eth_soc-only-read-the-full-rx-descr.patch @@ -0,0 +1,44 @@ +From: Felix Fietkau +Date: Thu, 27 Aug 2020 09:24:25 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: only read the full rx + descriptor if DMA is done + +Uncached memory access is expensive, and there is no need to access all +descriptor words if we can't process them anyway + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -793,13 +793,18 @@ static inline int mtk_max_buf_size(int f + return buf_size; + } + +-static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd, ++static inline bool mtk_rx_get_desc(struct mtk_rx_dma *rxd, + struct mtk_rx_dma *dma_rxd) + { +- rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); + rxd->rxd2 = READ_ONCE(dma_rxd->rxd2); ++ if (!(rxd->rxd2 & RX_DMA_DONE)) ++ return false; ++ ++ rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); + rxd->rxd3 = READ_ONCE(dma_rxd->rxd3); + rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); ++ ++ return true; + } + + /* the qdma core needs scratch memory to be setup */ +@@ -1271,8 +1276,7 @@ static int mtk_poll_rx(struct napi_struc + rxd = &ring->dma[idx]; + data = ring->data[idx]; + +- mtk_rx_get_desc(&trxd, rxd); +- if (!(trxd.rxd2 & RX_DMA_DONE)) ++ if (!mtk_rx_get_desc(&trxd, rxd)) + break; + + /* find out which mac the packet come from. values start at 1 */ diff --git a/ipq806x/pending-5.4/770-10-net-ethernet-mtk_eth_soc-unmap-rx-data-before-callin.patch b/ipq806x/pending-5.4/770-10-net-ethernet-mtk_eth_soc-unmap-rx-data-before-callin.patch new file mode 100644 index 0000000..285fcf8 --- /dev/null +++ b/ipq806x/pending-5.4/770-10-net-ethernet-mtk_eth_soc-unmap-rx-data-before-callin.patch @@ -0,0 +1,44 @@ +From: Felix Fietkau +Date: Thu, 27 Aug 2020 09:44:43 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: unmap rx data before calling + build_skb + +Since build_skb accesses the data area (for initializing shinfo), dma unmap +needs to happen before that call + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1314,17 +1314,18 @@ static int mtk_poll_rx(struct napi_struc + goto release_desc; + } + ++ dma_unmap_single(eth->dev, trxd.rxd1, ++ ring->buf_size, DMA_FROM_DEVICE); ++ + /* receive data */ + skb = build_skb(data, ring->frag_size); + if (unlikely(!skb)) { +- skb_free_frag(new_data); ++ skb_free_frag(data); + netdev->stats.rx_dropped++; +- goto release_desc; ++ goto skip_rx; + } + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + +- dma_unmap_single(eth->dev, trxd.rxd1, +- ring->buf_size, DMA_FROM_DEVICE); + pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; + skb_put(skb, pktlen); +@@ -1342,6 +1343,7 @@ static int mtk_poll_rx(struct napi_struc + skb_record_rx_queue(skb, 0); + napi_gro_receive(napi, skb); + ++skip_rx: + ring->data[idx] = new_data; + rxd->rxd1 = (unsigned int)dma_addr; + diff --git a/ipq806x/pending-5.4/770-11-net-ethernet-mtk_eth_soc-avoid-rearming-interrupt-if.patch b/ipq806x/pending-5.4/770-11-net-ethernet-mtk_eth_soc-avoid-rearming-interrupt-if.patch new file mode 100644 index 0000000..4036e32 --- /dev/null +++ b/ipq806x/pending-5.4/770-11-net-ethernet-mtk_eth_soc-avoid-rearming-interrupt-if.patch @@ -0,0 +1,35 @@ +From: Felix Fietkau +Date: Fri, 4 Sep 2020 18:14:05 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: avoid rearming interrupt if + napi_complete returns false + +Reduces unnecessary interrupts + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1536,8 +1536,8 @@ static int mtk_napi_tx(struct napi_struc + if (status & MTK_TX_DONE_INT) + return budget; + +- napi_complete(napi); +- mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); ++ if (napi_complete(napi)) ++ mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); + + return tx_done; + } +@@ -1570,8 +1570,9 @@ poll_again: + remain_budget -= rx_done; + goto poll_again; + } +- napi_complete(napi); +- mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); ++ ++ if (napi_complete(napi)) ++ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); + + return rx_done + budget - remain_budget; + } diff --git a/ipq806x/pending-5.4/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch b/ipq806x/pending-5.4/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch new file mode 100644 index 0000000..b1bde7b --- /dev/null +++ b/ipq806x/pending-5.4/770-13-net-ethernet-mtk_eth_soc-fix-parsing-packets-in-GDM.patch @@ -0,0 +1,67 @@ +From: Felix Fietkau +Date: Sun, 13 Sep 2020 08:17:02 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix parsing packets in GDM + +When using DSA, set the special tag in GDM ingress control to allow the MAC +to parse packets properly earlier. This affects rx DMA source port reporting. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include "mtk_eth_soc.h" + +@@ -1280,13 +1281,12 @@ static int mtk_poll_rx(struct napi_struc + break; + + /* find out which mac the packet come from. values start at 1 */ +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) || ++ (trxd.rxd4 & RX_DMA_SPECIAL_TAG)) + mac = 0; +- } else { +- mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & +- RX_DMA_FPORT_MASK; +- mac--; +- } ++ else ++ mac = ((trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & ++ RX_DMA_FPORT_MASK) - 1; + + if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || + !eth->netdev[mac])) +@@ -2268,6 +2268,9 @@ static void mtk_gdm_config(struct mtk_et + + val |= config; + ++ if (!i && eth->netdev[0] && netdev_uses_dsa(eth->netdev[0])) ++ val |= MTK_GDMA_SPECIAL_TAG; ++ + mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); + } + /* Reset and enable PSE */ +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -82,6 +82,7 @@ + + /* GDM Exgress Control Register */ + #define MTK_GDMA_FWD_CFG(x) (0x500 + (x * 0x1000)) ++#define MTK_GDMA_SPECIAL_TAG BIT(24) + #define MTK_GDMA_ICS_EN BIT(22) + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) +@@ -324,6 +325,7 @@ + #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */ + #define RX_DMA_FPORT_SHIFT 19 + #define RX_DMA_FPORT_MASK 0x7 ++#define RX_DMA_SPECIAL_TAG BIT(22) + + /* PHY Indirect Access Control registers */ + #define MTK_PHY_IAC 0x10004 diff --git a/ipq806x/pending-5.4/770-14-net-ethernet-mtk_eth_soc-set-PPE-flow-hash-as-skb-ha.patch b/ipq806x/pending-5.4/770-14-net-ethernet-mtk_eth_soc-set-PPE-flow-hash-as-skb-ha.patch new file mode 100644 index 0000000..4ab3d84 --- /dev/null +++ b/ipq806x/pending-5.4/770-14-net-ethernet-mtk_eth_soc-set-PPE-flow-hash-as-skb-ha.patch @@ -0,0 +1,41 @@ +From: Felix Fietkau +Date: Sun, 13 Sep 2020 08:27:24 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: set PPE flow hash as skb hash + if present + +This improves GRO performance + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + + #include "mtk_eth_soc.h" +@@ -1267,6 +1268,7 @@ static int mtk_poll_rx(struct napi_struc + struct net_device *netdev; + unsigned int pktlen; + dma_addr_t dma_addr; ++ u32 hash; + int mac; + + ring = mtk_get_rx_ring(eth); +@@ -1336,6 +1338,12 @@ static int mtk_poll_rx(struct napi_struc + skb->protocol = eth_type_trans(skb, netdev); + bytes += pktlen; + ++ hash = trxd.rxd4 & GENMASK(13, 0); ++ if (hash != GENMASK(13, 0)) { ++ hash = jhash_1word(hash, 0); ++ skb_set_hash(skb, hash, PKT_HASH_TYPE_L4); ++ } ++ + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && + (trxd.rxd2 & RX_DMA_VTAG)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), diff --git a/ipq806x/pending-5.4/770-15-net-ethernet-mediatek-mtk_eth_soc-add-support-for-in.patch b/ipq806x/pending-5.4/770-15-net-ethernet-mediatek-mtk_eth_soc-add-support-for-in.patch new file mode 100644 index 0000000..f609f11 --- /dev/null +++ b/ipq806x/pending-5.4/770-15-net-ethernet-mediatek-mtk_eth_soc-add-support-for-in.patch @@ -0,0 +1,1058 @@ +From: Felix Fietkau +Date: Sun, 11 Oct 2020 22:23:08 +0200 +Subject: [PATCH] ethernet: mediatek: mtk_eth_soc: add support for + initializing the PPE + +The PPE (packet processing engine) is used to offload NAT/routed or even +bridged flows. This patch brings up the PPE and uses it to get a packet +hash. It also contains some functionality that will be used to bring up +flow offloading later + +Signed-off-by: Felix Fietkau +--- + create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.h + create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_regs.h + +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -4,4 +4,4 @@ + # + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o +-mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o ++mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2301,12 +2301,17 @@ static int mtk_open(struct net_device *d + + /* we run 2 netdevs on the same dma ring so we only bring it up once */ + if (!refcount_read(ð->dma_refcnt)) { +- int err = mtk_start_dma(eth); ++ u32 gdm_config = MTK_GDMA_TO_PDMA; ++ int err; + ++ err = mtk_start_dma(eth); + if (err) + return err; + +- mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); ++ if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0) ++ gdm_config = MTK_GDMA_TO_PPE; ++ ++ mtk_gdm_config(eth, gdm_config); + + napi_enable(ð->tx_napi); + napi_enable(ð->rx_napi); +@@ -2376,6 +2381,9 @@ static int mtk_stop(struct net_device *d + + mtk_dma_free(eth); + ++ if (eth->soc->offload_version) ++ mtk_ppe_stop(ð->ppe); ++ + return 0; + } + +@@ -3165,6 +3173,13 @@ static int mtk_probe(struct platform_dev + goto err_free_dev; + } + ++ if (eth->soc->offload_version) { ++ err = mtk_ppe_init(ð->ppe, eth->dev, ++ eth->base + MTK_ETH_PPE_BASE, 2); ++ if (err) ++ goto err_free_dev; ++ } ++ + for (i = 0; i < MTK_MAX_DEVS; i++) { + if (!eth->netdev[i]) + continue; +@@ -3239,6 +3254,7 @@ static const struct mtk_soc_data mt7621_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7621_CLKS_BITMAP, + .required_pctl = false, ++ .offload_version = 2, + }; + + static const struct mtk_soc_data mt7622_data = { +@@ -3247,6 +3263,7 @@ static const struct mtk_soc_data mt7622_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7622_CLKS_BITMAP, + .required_pctl = false, ++ .offload_version = 2, + }; + + static const struct mtk_soc_data mt7623_data = { +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include "mtk_ppe.h" + + #define MTK_QDMA_PAGE_SIZE 2048 + #define MTK_MAX_RX_LENGTH 1536 +@@ -87,6 +88,7 @@ + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) + #define MTK_GDMA_TO_PDMA 0x0 ++#define MTK_GDMA_TO_PPE 0x4444 + #define MTK_GDMA_DROP_ALL 0x7777 + + /* Unicast Filter MAC Address Register - Low */ +@@ -321,6 +323,12 @@ + #define RX_DMA_VID(_x) ((_x) & 0xfff) + + /* QDMA descriptor rxd4 */ ++#define MTK_RXD4_FOE_ENTRY GENMASK(13, 0) ++#define MTK_RXD4_PPE_CPU_REASON GENMASK(18, 14) ++#define MTK_RXD4_SRC_PORT GENMASK(21, 19) ++#define MTK_RXD4_ALG GENMASK(31, 22) ++ ++/* QDMA descriptor rxd4 */ + #define RX_DMA_L4_VALID BIT(24) + #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */ + #define RX_DMA_FPORT_SHIFT 19 +@@ -827,6 +835,7 @@ struct mtk_soc_data { + u32 caps; + u32 required_clks; + bool required_pctl; ++ u8 offload_version; + netdev_features_t hw_features; + }; + +@@ -938,6 +947,8 @@ struct mtk_eth { + u32 tx_int_status_reg; + u32 rx_dma_l4_valid; + int ip_align; ++ ++ struct mtk_ppe ppe; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -0,0 +1,497 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2020 Felix Fietkau */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mtk_ppe.h" ++#include "mtk_ppe_regs.h" ++ ++static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val) ++{ ++ writel(val, ppe->base + reg); ++} ++ ++static u32 ppe_r32(struct mtk_ppe *ppe, u32 reg) ++{ ++ return readl(ppe->base + reg); ++} ++ ++static u32 ppe_m32(struct mtk_ppe *ppe, u32 reg, u32 mask, u32 set) ++{ ++ u32 val; ++ ++ val = ppe_r32(ppe, reg); ++ val &= ~mask; ++ val |= set; ++ ppe_w32(ppe, reg, val); ++ ++ return val; ++} ++ ++static u32 ppe_set(struct mtk_ppe *ppe, u32 reg, u32 val) ++{ ++ return ppe_m32(ppe, reg, 0, val); ++} ++ ++static u32 ppe_clear(struct mtk_ppe *ppe, u32 reg, u32 val) ++{ ++ return ppe_m32(ppe, reg, val, 0); ++} ++ ++static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) ++{ ++ unsigned long timeout = jiffies + HZ; ++ ++ while (time_is_after_jiffies(timeout)) { ++ if (!(ppe_r32(ppe, MTK_PPE_GLO_CFG) & MTK_PPE_GLO_CFG_BUSY)) ++ return 0; ++ ++ usleep_range(10, 20); ++ } ++ ++ dev_err(ppe->dev, "PPE table busy"); ++ ++ return -ETIMEDOUT; ++} ++ ++static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) ++{ ++ ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); ++ ppe_clear(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); ++} ++ ++static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable) ++{ ++ mtk_ppe_cache_clear(ppe); ++ ++ ppe_m32(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_EN, ++ enable * MTK_PPE_CACHE_CTL_EN); ++} ++ ++static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e) ++{ ++ u32 hv1, hv2, hv3; ++ u32 hash; ++ ++ switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) { ++ case MTK_PPE_PKT_TYPE_BRIDGE: ++ hv1 = e->bridge.src_mac_lo; ++ hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16); ++ hv2 = e->bridge.src_mac_hi >> 16; ++ hv2 ^= e->bridge.dest_mac_lo; ++ hv3 = e->bridge.dest_mac_hi; ++ break; ++ case MTK_PPE_PKT_TYPE_IPV4_ROUTE: ++ case MTK_PPE_PKT_TYPE_IPV4_HNAPT: ++ hv1 = e->ipv4.orig.ports; ++ hv2 = e->ipv4.orig.dest_ip; ++ hv3 = e->ipv4.orig.src_ip; ++ break; ++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: ++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: ++ hv1 = e->ipv6.src_ip[3] ^ e->ipv6.dest_ip[3]; ++ hv1 ^= e->ipv6.ports; ++ ++ hv2 = e->ipv6.src_ip[2] ^ e->ipv6.dest_ip[2]; ++ hv2 ^= e->ipv6.dest_ip[0]; ++ ++ hv3 = e->ipv6.src_ip[1] ^ e->ipv6.dest_ip[1]; ++ hv3 ^= e->ipv6.src_ip[0]; ++ break; ++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE: ++ case MTK_PPE_PKT_TYPE_IPV6_6RD: ++ default: ++ WARN_ON_ONCE(1); ++ return MTK_PPE_HASH_MASK; ++ } ++ ++ hash = (hv1 & hv2) | ((~hv1) & hv3); ++ hash = (hash >> 24) | ((hash & 0xffffff) << 8); ++ hash ^= hv1 ^ hv2 ^ hv3; ++ hash ^= hash >> 16; ++ hash <<= 1; ++ hash &= MTK_PPE_ENTRIES - 1; ++ ++ return hash; ++} ++ ++static inline struct mtk_foe_mac_info * ++mtk_foe_entry_l2(struct mtk_foe_entry *entry) ++{ ++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ ++ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) ++ return &entry->ipv6.l2; ++ ++ return &entry->ipv4.l2; ++} ++ ++static inline u32 * ++mtk_foe_entry_ib2(struct mtk_foe_entry *entry) ++{ ++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ ++ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) ++ return &entry->ipv6.ib2; ++ ++ return &entry->ipv4.ib2; ++} ++ ++int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, ++ u8 pse_port, u8 *src_mac, u8 *dest_mac) ++{ ++ struct mtk_foe_mac_info *l2; ++ u32 ports_pad, val; ++ ++ memset(entry, 0, sizeof(*entry)); ++ ++ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | ++ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | ++ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | ++ MTK_FOE_IB1_BIND_TTL | ++ MTK_FOE_IB1_BIND_CACHE | ++ MTK_FOE_IB1_BIND_KEEPALIVE; ++ entry->ib1 = val; ++ ++ val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) | ++ FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port); ++ ++ if (is_multicast_ether_addr(dest_mac)) ++ val |= MTK_FOE_IB2_MULTICAST; ++ ++ ports_pad = 0xa5a5a500 | (l4proto & 0xff); ++ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE) ++ entry->ipv4.orig.ports = ports_pad; ++ if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T) ++ entry->ipv6.ports = ports_pad; ++ ++ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { ++ entry->ipv6.ib2 = val; ++ l2 = &entry->ipv6.l2; ++ } else { ++ entry->ipv4.ib2 = val; ++ l2 = &entry->ipv4.l2; ++ } ++ ++ l2->dest_mac_hi = get_unaligned_be32(dest_mac); ++ l2->dest_mac_lo = get_unaligned_be16(dest_mac + 4); ++ l2->src_mac_hi = get_unaligned_be32(src_mac); ++ l2->src_mac_lo = get_unaligned_be16(src_mac + 4); ++ ++ if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T) ++ l2->etype = ETH_P_IPV6; ++ else ++ l2->etype = ETH_P_IP; ++ ++ return 0; ++} ++ ++int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool egress, ++ __be32 src_addr, __be16 src_port, ++ __be32 dest_addr, __be16 dest_port) ++{ ++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ struct mtk_ipv4_tuple *t; ++ ++ switch (type) { ++ case MTK_PPE_PKT_TYPE_IPV4_HNAPT: ++ if (egress) { ++ t = &entry->ipv4.new; ++ break; ++ } ++ fallthrough; ++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE: ++ case MTK_PPE_PKT_TYPE_IPV4_ROUTE: ++ t = &entry->ipv4.orig; ++ break; ++ case MTK_PPE_PKT_TYPE_IPV6_6RD: ++ entry->ipv6_6rd.tunnel_src_ip = be32_to_cpu(src_addr); ++ entry->ipv6_6rd.tunnel_dest_ip = be32_to_cpu(dest_addr); ++ return 0; ++ default: ++ WARN_ON_ONCE(1); ++ return -EINVAL; ++ } ++ ++ t->src_ip = be32_to_cpu(src_addr); ++ t->dest_ip = be32_to_cpu(dest_addr); ++ ++ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE) ++ return 0; ++ ++ t->src_port = be16_to_cpu(src_port); ++ t->dest_port = be16_to_cpu(dest_port); ++ ++ return 0; ++} ++ ++int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry, ++ __be32 *src_addr, __be16 src_port, ++ __be32 *dest_addr, __be16 dest_port) ++{ ++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ u32 *src, *dest; ++ int i; ++ ++ switch (type) { ++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE: ++ src = entry->dslite.tunnel_src_ip; ++ dest = entry->dslite.tunnel_dest_ip; ++ break; ++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: ++ case MTK_PPE_PKT_TYPE_IPV6_6RD: ++ entry->ipv6.src_port = be16_to_cpu(src_port); ++ entry->ipv6.dest_port = be16_to_cpu(dest_port); ++ fallthrough; ++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: ++ src = entry->ipv6.src_ip; ++ dest = entry->ipv6.dest_ip; ++ break; ++ default: ++ WARN_ON_ONCE(1); ++ return -EINVAL; ++ }; ++ ++ for (i = 0; i < 4; i++) ++ src[i] = be32_to_cpu(src_addr[i]); ++ for (i = 0; i < 4; i++) ++ dest[i] = be32_to_cpu(dest_addr[i]); ++ ++ return 0; ++} ++ ++int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port) ++{ ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ ++ l2->etype = BIT(port); ++ ++ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER)) ++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ else ++ l2->etype |= BIT(8); ++ ++ entry->ib1 &= ~MTK_FOE_IB1_BIND_VLAN_TAG; ++ ++ return 0; ++} ++ ++int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid) ++{ ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ ++ switch (FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1)) { ++ case 0: ++ entry->ib1 |= MTK_FOE_IB1_BIND_VLAN_TAG | ++ FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ l2->vlan1 = vid; ++ return 0; ++ case 1: ++ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) { ++ l2->vlan1 = vid; ++ l2->etype |= BIT(8); ++ } else { ++ l2->vlan2 = vid; ++ entry->ib1 += FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ } ++ return 0; ++ default: ++ return -ENOSPC; ++ } ++} ++ ++int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid) ++{ ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ ++ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER) || ++ (entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) ++ l2->etype = ETH_P_PPP_SES; ++ ++ entry->ib1 |= MTK_FOE_IB1_BIND_PPPOE; ++ l2->pppoe_id = sid; ++ ++ return 0; ++} ++ ++static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry) ++{ ++ return !(entry->ib1 & MTK_FOE_IB1_STATIC) && ++ FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND; ++} ++ ++int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, ++ u16 timestamp) ++{ ++ struct mtk_foe_entry *hwe; ++ u32 hash; ++ ++ timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP; ++ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; ++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); ++ ++ hash = mtk_ppe_hash_entry(entry); ++ hwe = &ppe->foe_table[hash]; ++ if (!mtk_foe_entry_usable(hwe)) { ++ hwe++; ++ hash++; ++ ++ if (!mtk_foe_entry_usable(hwe)) ++ return -ENOSPC; ++ } ++ ++ memcpy(&hwe->data, &entry->data, sizeof(hwe->data)); ++ wmb(); ++ hwe->ib1 = entry->ib1; ++ ++ dma_wmb(); ++ ++ mtk_ppe_cache_clear(ppe); ++ ++ return hash; ++} ++ ++int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base, ++ int version) ++{ ++ struct mtk_foe_entry *foe; ++ ++ /* need to allocate a separate device, since it PPE DMA access is ++ * not coherent. ++ */ ++ ppe->base = base; ++ ppe->dev = dev; ++ ppe->version = version; ++ ++ foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe), ++ &ppe->foe_phys, GFP_KERNEL); ++ if (!foe) ++ return -ENOMEM; ++ ++ ppe->foe_table = foe; ++ ++ return 0; ++} ++ ++static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe) ++{ ++ static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 }; ++ int i, k; ++ ++ memset(ppe->foe_table, 0, MTK_PPE_ENTRIES * sizeof(ppe->foe_table)); ++ ++ if (!IS_ENABLED(CONFIG_SOC_MT7621)) ++ return; ++ ++ /* skip all entries that cross the 1024 byte boundary */ ++ for (i = 0; i < MTK_PPE_ENTRIES; i += 128) ++ for (k = 0; k < ARRAY_SIZE(skip); k++) ++ ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC; ++} ++ ++int mtk_ppe_start(struct mtk_ppe *ppe) ++{ ++ u32 val; ++ ++ mtk_ppe_init_foe_table(ppe); ++ ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys); ++ ++ val = MTK_PPE_TB_CFG_ENTRY_80B | ++ MTK_PPE_TB_CFG_AGE_NON_L4 | ++ MTK_PPE_TB_CFG_AGE_UNBIND | ++ MTK_PPE_TB_CFG_AGE_TCP | ++ MTK_PPE_TB_CFG_AGE_UDP | ++ MTK_PPE_TB_CFG_AGE_TCP_FIN | ++ FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS, ++ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD) | ++ FIELD_PREP(MTK_PPE_TB_CFG_KEEPALIVE, ++ MTK_PPE_KEEPALIVE_DUP_CPU) | ++ FIELD_PREP(MTK_PPE_TB_CFG_HASH_MODE, 1) | ++ FIELD_PREP(MTK_PPE_TB_CFG_SCAN_MODE, ++ MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) | ++ FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM, ++ MTK_PPE_ENTRIES_SHIFT); ++ ppe_w32(ppe, MTK_PPE_TB_CFG, val); ++ ++ ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK, ++ MTK_PPE_IP_PROTO_CHK_IPV4 | MTK_PPE_IP_PROTO_CHK_IPV6); ++ ++ mtk_ppe_cache_enable(ppe, true); ++ ++ val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | ++ MTK_PPE_FLOW_CFG_IP4_UDP_FRAG | ++ MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | ++ MTK_PPE_FLOW_CFG_IP6_5T_ROUTE | ++ MTK_PPE_FLOW_CFG_IP6_6RD | ++ MTK_PPE_FLOW_CFG_IP4_NAT | ++ MTK_PPE_FLOW_CFG_IP4_NAPT | ++ MTK_PPE_FLOW_CFG_IP4_DSLITE | ++ MTK_PPE_FLOW_CFG_L2_BRIDGE | ++ MTK_PPE_FLOW_CFG_IP4_NAT_FRAG; ++ ppe_w32(ppe, MTK_PPE_FLOW_CFG, val); ++ ++ val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) | ++ FIELD_PREP(MTK_PPE_UNBIND_AGE_DELTA, 3); ++ ppe_w32(ppe, MTK_PPE_UNBIND_AGE, val); ++ ++ val = FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_UDP, 12) | ++ FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_NON_L4, 1); ++ ppe_w32(ppe, MTK_PPE_BIND_AGE0, val); ++ ++ val = FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP_FIN, 1) | ++ FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP, 7); ++ ppe_w32(ppe, MTK_PPE_BIND_AGE1, val); ++ ++ val = MTK_PPE_BIND_LIMIT0_QUARTER | MTK_PPE_BIND_LIMIT0_HALF; ++ ppe_w32(ppe, MTK_PPE_BIND_LIMIT0, val); ++ ++ val = MTK_PPE_BIND_LIMIT1_FULL | ++ FIELD_PREP(MTK_PPE_BIND_LIMIT1_NON_L4, 1); ++ ppe_w32(ppe, MTK_PPE_BIND_LIMIT1, val); ++ ++ val = FIELD_PREP(MTK_PPE_BIND_RATE_BIND, 30) | ++ FIELD_PREP(MTK_PPE_BIND_RATE_PREBIND, 1); ++ ppe_w32(ppe, MTK_PPE_BIND_RATE, val); ++ ++ /* enable PPE */ ++ val = MTK_PPE_GLO_CFG_EN | ++ MTK_PPE_GLO_CFG_IP4_L4_CS_DROP | ++ MTK_PPE_GLO_CFG_IP4_CS_DROP | ++ MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE; ++ ppe_w32(ppe, MTK_PPE_GLO_CFG, val); ++ ++ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); ++ ++ return 0; ++} ++ ++int mtk_ppe_stop(struct mtk_ppe *ppe) ++{ ++ u32 val; ++ int i; ++ ++ for (i = 0; i < MTK_PPE_ENTRIES; i++) ++ ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, ++ MTK_FOE_STATE_INVALID); ++ ++ mtk_ppe_cache_enable(ppe, false); ++ ++ /* disable offload engine */ ++ ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN); ++ ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0); ++ ++ /* disable aging */ ++ val = MTK_PPE_TB_CFG_AGE_NON_L4 | ++ MTK_PPE_TB_CFG_AGE_UNBIND | ++ MTK_PPE_TB_CFG_AGE_TCP | ++ MTK_PPE_TB_CFG_AGE_UDP | ++ MTK_PPE_TB_CFG_AGE_TCP_FIN; ++ ppe_clear(ppe, MTK_PPE_TB_CFG, val); ++ ++ return mtk_ppe_wait_busy(ppe); ++} +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -0,0 +1,274 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2020 Felix Fietkau */ ++ ++#ifndef __MTK_PPE_H ++#define __MTK_PPE_H ++ ++#include ++#include ++ ++#define MTK_ETH_PPE_BASE 0xc00 ++ ++#define MTK_PPE_ENTRIES_SHIFT 3 ++#define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT) ++#define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1) ++ ++#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0) ++#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(23, 8) ++#define MTK_FOE_IB1_UNBIND_PREBIND BIT(24) ++ ++#define MTK_FOE_IB1_BIND_TIMESTAMP GENMASK(14, 0) ++#define MTK_FOE_IB1_BIND_KEEPALIVE BIT(15) ++#define MTK_FOE_IB1_BIND_VLAN_LAYER GENMASK(18, 16) ++#define MTK_FOE_IB1_BIND_PPPOE BIT(19) ++#define MTK_FOE_IB1_BIND_VLAN_TAG BIT(20) ++#define MTK_FOE_IB1_BIND_PKT_SAMPLE BIT(21) ++#define MTK_FOE_IB1_BIND_CACHE BIT(22) ++#define MTK_FOE_IB1_BIND_TUNNEL_DECAP BIT(23) ++#define MTK_FOE_IB1_BIND_TTL BIT(24) ++ ++#define MTK_FOE_IB1_PACKET_TYPE GENMASK(27, 25) ++#define MTK_FOE_IB1_STATE GENMASK(29, 28) ++#define MTK_FOE_IB1_UDP BIT(30) ++#define MTK_FOE_IB1_STATIC BIT(31) ++ ++enum { ++ MTK_PPE_PKT_TYPE_IPV4_HNAPT = 0, ++ MTK_PPE_PKT_TYPE_IPV4_ROUTE = 1, ++ MTK_PPE_PKT_TYPE_BRIDGE = 2, ++ MTK_PPE_PKT_TYPE_IPV4_DSLITE = 3, ++ MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T = 4, ++ MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T = 5, ++ MTK_PPE_PKT_TYPE_IPV6_6RD = 7, ++}; ++ ++#define MTK_FOE_IB2_QID GENMASK(3, 0) ++#define MTK_FOE_IB2_PSE_QOS BIT(4) ++#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5) ++#define MTK_FOE_IB2_MULTICAST BIT(8) ++ ++#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12) ++#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16) ++#define MTK_FOE_IB2_WHNAT_NAT BIT(17) ++ ++#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12) ++ ++#define MTK_FOE_IB2_PORT_AG GENMASK(23, 18) ++ ++#define MTK_FOE_IB2_DSCP GENMASK(31, 24) ++ ++#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0) ++#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6) ++#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14) ++ ++enum { ++ MTK_FOE_STATE_INVALID, ++ MTK_FOE_STATE_UNBIND, ++ MTK_FOE_STATE_BIND, ++ MTK_FOE_STATE_FIN ++}; ++ ++struct mtk_foe_mac_info { ++ u16 vlan1; ++ u16 etype; ++ ++ u32 dest_mac_hi; ++ ++ u16 vlan2; ++ u16 dest_mac_lo; ++ ++ u32 src_mac_hi; ++ ++ u16 pppoe_id; ++ u16 src_mac_lo; ++}; ++ ++struct mtk_foe_bridge { ++ u32 dest_mac_hi; ++ ++ u16 src_mac_lo; ++ u16 dest_mac_lo; ++ ++ u32 src_mac_hi; ++ ++ u32 ib2; ++ ++ u32 _rsv[5]; ++ ++ u32 udf_tsid; ++ struct mtk_foe_mac_info l2; ++}; ++ ++struct mtk_ipv4_tuple { ++ u32 src_ip; ++ u32 dest_ip; ++ union { ++ struct { ++ u16 dest_port; ++ u16 src_port; ++ }; ++ struct { ++ u8 protocol; ++ u8 _pad[3]; /* fill with 0xa5a5a5 */ ++ }; ++ u32 ports; ++ }; ++}; ++ ++struct mtk_foe_ipv4 { ++ struct mtk_ipv4_tuple orig; ++ ++ u32 ib2; ++ ++ struct mtk_ipv4_tuple new; ++ ++ u16 timestamp; ++ u16 _rsv0[3]; ++ ++ u32 udf_tsid; ++ ++ struct mtk_foe_mac_info l2; ++}; ++ ++struct mtk_foe_ipv4_dslite { ++ struct mtk_ipv4_tuple ip4; ++ ++ u32 tunnel_src_ip[4]; ++ u32 tunnel_dest_ip[4]; ++ ++ u8 flow_label[3]; ++ u8 priority; ++ ++ u32 udf_tsid; ++ ++ u32 ib2; ++ ++ struct mtk_foe_mac_info l2; ++}; ++ ++struct mtk_foe_ipv6 { ++ u32 src_ip[4]; ++ u32 dest_ip[4]; ++ ++ union { ++ struct { ++ u8 protocol; ++ u8 _pad[3]; /* fill with 0xa5a5a5 */ ++ }; /* 3-tuple */ ++ struct { ++ u16 dest_port; ++ u16 src_port; ++ }; /* 5-tuple */ ++ u32 ports; ++ }; ++ ++ u32 _rsv[3]; ++ ++ u32 udf; ++ ++ u32 ib2; ++ struct mtk_foe_mac_info l2; ++}; ++ ++struct mtk_foe_ipv6_6rd { ++ u32 src_ip[4]; ++ u32 dest_ip[4]; ++ u16 dest_port; ++ u16 src_port; ++ ++ u32 tunnel_src_ip; ++ u32 tunnel_dest_ip; ++ ++ u16 hdr_csum; ++ u8 dscp; ++ u8 ttl; ++ ++ u8 flag; ++ u8 pad; ++ u8 per_flow_6rd_id; ++ u8 pad2; ++ ++ u32 ib2; ++ struct mtk_foe_mac_info l2; ++}; ++ ++struct mtk_foe_entry { ++ u32 ib1; ++ ++ union { ++ struct mtk_foe_bridge bridge; ++ struct mtk_foe_ipv4 ipv4; ++ struct mtk_foe_ipv4_dslite dslite; ++ struct mtk_foe_ipv6 ipv6; ++ struct mtk_foe_ipv6_6rd ipv6_6rd; ++ u32 data[19]; ++ }; ++}; ++ ++enum { ++ MTK_PPE_CPU_REASON_TTL_EXCEEDED = 0x02, ++ MTK_PPE_CPU_REASON_OPTION_HEADER = 0x03, ++ MTK_PPE_CPU_REASON_NO_FLOW = 0x07, ++ MTK_PPE_CPU_REASON_IPV4_FRAG = 0x08, ++ MTK_PPE_CPU_REASON_IPV4_DSLITE_FRAG = 0x09, ++ MTK_PPE_CPU_REASON_IPV4_DSLITE_NO_TCP_UDP = 0x0a, ++ MTK_PPE_CPU_REASON_IPV6_6RD_NO_TCP_UDP = 0x0b, ++ MTK_PPE_CPU_REASON_TCP_FIN_SYN_RST = 0x0c, ++ MTK_PPE_CPU_REASON_UN_HIT = 0x0d, ++ MTK_PPE_CPU_REASON_HIT_UNBIND = 0x0e, ++ MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED = 0x0f, ++ MTK_PPE_CPU_REASON_HIT_BIND_TCP_FIN = 0x10, ++ MTK_PPE_CPU_REASON_HIT_TTL_1 = 0x11, ++ MTK_PPE_CPU_REASON_HIT_BIND_VLAN_VIOLATION = 0x12, ++ MTK_PPE_CPU_REASON_KEEPALIVE_UC_OLD_HDR = 0x13, ++ MTK_PPE_CPU_REASON_KEEPALIVE_MC_NEW_HDR = 0x14, ++ MTK_PPE_CPU_REASON_KEEPALIVE_DUP_OLD_HDR = 0x15, ++ MTK_PPE_CPU_REASON_HIT_BIND_FORCE_CPU = 0x16, ++ MTK_PPE_CPU_REASON_TUNNEL_OPTION_HEADER = 0x17, ++ MTK_PPE_CPU_REASON_MULTICAST_TO_CPU = 0x18, ++ MTK_PPE_CPU_REASON_MULTICAST_TO_GMAC1_CPU = 0x19, ++ MTK_PPE_CPU_REASON_HIT_PRE_BIND = 0x1a, ++ MTK_PPE_CPU_REASON_PACKET_SAMPLING = 0x1b, ++ MTK_PPE_CPU_REASON_EXCEED_MTU = 0x1c, ++ MTK_PPE_CPU_REASON_PPE_BYPASS = 0x1e, ++ MTK_PPE_CPU_REASON_INVALID = 0x1f, ++}; ++ ++struct mtk_ppe { ++ struct device *dev; ++ void __iomem *base; ++ int version; ++ ++ struct mtk_foe_entry *foe_table; ++ dma_addr_t foe_phys; ++ ++ void *acct_table; ++}; ++ ++int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base, ++ int version); ++int mtk_ppe_start(struct mtk_ppe *ppe); ++int mtk_ppe_stop(struct mtk_ppe *ppe); ++ ++static inline void ++mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash) ++{ ++ ppe->foe_table[hash].ib1 = 0; ++ dma_wmb(); ++} ++ ++int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, ++ u8 pse_port, u8 *src_mac, u8 *dest_mac); ++int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool orig, ++ __be32 src_addr, __be16 src_port, ++ __be32 dest_addr, __be16 dest_port); ++int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry, ++ __be32 *src_addr, __be16 src_port, ++ __be32 *dest_addr, __be16 dest_port); ++int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port); ++int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid); ++int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); ++int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, ++ u16 timestamp); ++ ++#endif +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h +@@ -0,0 +1,144 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2020 Felix Fietkau */ ++ ++#ifndef __MTK_PPE_REGS_H ++#define __MTK_PPE_REGS_H ++ ++#define MTK_PPE_GLO_CFG 0x200 ++#define MTK_PPE_GLO_CFG_EN BIT(0) ++#define MTK_PPE_GLO_CFG_TSID_EN BIT(1) ++#define MTK_PPE_GLO_CFG_IP4_L4_CS_DROP BIT(2) ++#define MTK_PPE_GLO_CFG_IP4_CS_DROP BIT(3) ++#define MTK_PPE_GLO_CFG_TTL0_DROP BIT(4) ++#define MTK_PPE_GLO_CFG_PPE_BSWAP BIT(5) ++#define MTK_PPE_GLO_CFG_PSE_HASH_OFS BIT(6) ++#define MTK_PPE_GLO_CFG_MCAST_TB_EN BIT(7) ++#define MTK_PPE_GLO_CFG_FLOW_DROP_KA BIT(8) ++#define MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE BIT(9) ++#define MTK_PPE_GLO_CFG_UDP_LITE_EN BIT(10) ++#define MTK_PPE_GLO_CFG_UDP_LEN_DROP BIT(11) ++#define MTK_PPE_GLO_CFG_MCAST_ENTRIES GNEMASK(13, 12) ++#define MTK_PPE_GLO_CFG_BUSY BIT(31) ++ ++#define MTK_PPE_FLOW_CFG 0x204 ++#define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6) ++#define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7) ++#define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8) ++#define MTK_PPE_FLOW_CFG_IP6_5T_ROUTE BIT(9) ++#define MTK_PPE_FLOW_CFG_IP6_6RD BIT(10) ++#define MTK_PPE_FLOW_CFG_IP4_NAT BIT(12) ++#define MTK_PPE_FLOW_CFG_IP4_NAPT BIT(13) ++#define MTK_PPE_FLOW_CFG_IP4_DSLITE BIT(14) ++#define MTK_PPE_FLOW_CFG_L2_BRIDGE BIT(15) ++#define MTK_PPE_FLOW_CFG_IP_PROTO_BLACKLIST BIT(16) ++#define MTK_PPE_FLOW_CFG_IP4_NAT_FRAG BIT(17) ++#define MTK_PPE_FLOW_CFG_IP4_HASH_FLOW_LABEL BIT(18) ++#define MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY BIT(19) ++#define MTK_PPE_FLOW_CFG_IP6_HASH_GRE_KEY BIT(20) ++ ++#define MTK_PPE_IP_PROTO_CHK 0x208 ++#define MTK_PPE_IP_PROTO_CHK_IPV4 GENMASK(15, 0) ++#define MTK_PPE_IP_PROTO_CHK_IPV6 GENMASK(31, 16) ++ ++#define MTK_PPE_TB_CFG 0x21c ++#define MTK_PPE_TB_CFG_ENTRY_NUM GENMASK(2, 0) ++#define MTK_PPE_TB_CFG_ENTRY_80B BIT(3) ++#define MTK_PPE_TB_CFG_SEARCH_MISS GENMASK(5, 4) ++#define MTK_PPE_TB_CFG_AGE_PREBIND BIT(6) ++#define MTK_PPE_TB_CFG_AGE_NON_L4 BIT(7) ++#define MTK_PPE_TB_CFG_AGE_UNBIND BIT(8) ++#define MTK_PPE_TB_CFG_AGE_TCP BIT(9) ++#define MTK_PPE_TB_CFG_AGE_UDP BIT(10) ++#define MTK_PPE_TB_CFG_AGE_TCP_FIN BIT(11) ++#define MTK_PPE_TB_CFG_KEEPALIVE GENMASK(13, 12) ++#define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14) ++#define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16) ++#define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18) ++ ++enum { ++ MTK_PPE_SCAN_MODE_DISABLED, ++ MTK_PPE_SCAN_MODE_CHECK_AGE, ++ MTK_PPE_SCAN_MODE_KEEPALIVE_AGE, ++}; ++ ++enum { ++ MTK_PPE_KEEPALIVE_DISABLE, ++ MTK_PPE_KEEPALIVE_UNICAST_CPU, ++ MTK_PPE_KEEPALIVE_DUP_CPU = 3, ++}; ++ ++enum { ++ MTK_PPE_SEARCH_MISS_ACTION_DROP, ++ MTK_PPE_SEARCH_MISS_ACTION_FORWARD = 2, ++ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD = 3, ++}; ++ ++#define MTK_PPE_TB_BASE 0x220 ++ ++#define MTK_PPE_TB_USED 0x224 ++#define MTK_PPE_TB_USED_NUM GENMASK(13, 0) ++ ++#define MTK_PPE_BIND_RATE 0x228 ++#define MTK_PPE_BIND_RATE_BIND GENMASK(15, 0) ++#define MTK_PPE_BIND_RATE_PREBIND GENMASK(31, 16) ++ ++#define MTK_PPE_BIND_LIMIT0 0x22c ++#define MTK_PPE_BIND_LIMIT0_QUARTER GENMASK(13, 0) ++#define MTK_PPE_BIND_LIMIT0_HALF GENMASK(29, 16) ++ ++#define MTK_PPE_BIND_LIMIT1 0x230 ++#define MTK_PPE_BIND_LIMIT1_FULL GENMASK(13, 0) ++#define MTK_PPE_BIND_LIMIT1_NON_L4 GENMASK(23, 16) ++ ++#define MTK_PPE_KEEPALIVE 0x234 ++#define MTK_PPE_KEEPALIVE_TIME GENMASK(15, 0) ++#define MTK_PPE_KEEPALIVE_TIME_TCP GENMASK(23, 16) ++#define MTK_PPE_KEEPALIVE_TIME_UDP GENMASK(31, 24) ++ ++#define MTK_PPE_UNBIND_AGE 0x238 ++#define MTK_PPE_UNBIND_AGE_MIN_PACKETS GENMASK(31, 16) ++#define MTK_PPE_UNBIND_AGE_DELTA GENMASK(7, 0) ++ ++#define MTK_PPE_BIND_AGE0 0x23c ++#define MTK_PPE_BIND_AGE0_DELTA_NON_L4 GENMASK(30, 16) ++#define MTK_PPE_BIND_AGE0_DELTA_UDP GENMASK(14, 0) ++ ++#define MTK_PPE_BIND_AGE1 0x240 ++#define MTK_PPE_BIND_AGE1_DELTA_TCP_FIN GENMASK(30, 16) ++#define MTK_PPE_BIND_AGE1_DELTA_TCP GENMASK(14, 0) ++ ++#define MTK_PPE_HASH_SEED 0x244 ++ ++#define MTK_PPE_DEFAULT_CPU_PORT 0x248 ++#define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4)) ++ ++#define MTK_PPE_MTU_DROP 0x308 ++ ++#define MTK_PPE_VLAN_MTU0 0x30c ++#define MTK_PPE_VLAN_MTU0_NONE GENMASK(13, 0) ++#define MTK_PPE_VLAN_MTU0_1TAG GENMASK(29, 16) ++ ++#define MTK_PPE_VLAN_MTU1 0x310 ++#define MTK_PPE_VLAN_MTU1_2TAG GENMASK(13, 0) ++#define MTK_PPE_VLAN_MTU1_3TAG GENMASK(29, 16) ++ ++#define MTK_PPE_VPM_TPID 0x318 ++ ++#define MTK_PPE_CACHE_CTL 0x320 ++#define MTK_PPE_CACHE_CTL_EN BIT(0) ++#define MTK_PPE_CACHE_CTL_LOCK_CLR BIT(4) ++#define MTK_PPE_CACHE_CTL_REQ BIT(8) ++#define MTK_PPE_CACHE_CTL_CLEAR BIT(9) ++#define MTK_PPE_CACHE_CTL_CMD GENMASK(13, 12) ++ ++#define MTK_PPE_MIB_CFG 0x334 ++#define MTK_PPE_MIB_CFG_EN BIT(0) ++#define MTK_PPE_MIB_CFG_RD_CLR BIT(1) ++ ++#define MTK_PPE_MIB_TB_BASE 0x338 ++ ++#define MTK_PPE_MIB_CACHE_CTL 0x350 ++#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0) ++#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2) ++ ++#endif diff --git a/ipq806x/pending-5.4/770-16-net-ethernet-mediatek-mtk_eth_soc-add-flow-offloadin.patch b/ipq806x/pending-5.4/770-16-net-ethernet-mediatek-mtk_eth_soc-add-flow-offloadin.patch new file mode 100644 index 0000000..b0f06f6 --- /dev/null +++ b/ipq806x/pending-5.4/770-16-net-ethernet-mediatek-mtk_eth_soc-add-flow-offloadin.patch @@ -0,0 +1,401 @@ +From: Felix Fietkau +Date: Sun, 11 Oct 2020 22:28:32 +0200 +Subject: [PATCH] net: ethernet: mediatek: mtk_eth_soc: add flow offloading + support + +Only supports IPv4 for now + +Signed-off-by: Felix Fietkau +--- + create mode 100644 drivers/net/ethernet/mediatek/mtk_offload.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c + +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -4,4 +4,4 @@ + # + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o +-mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o ++mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_offload.o +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include "mtk_eth_soc.h" +@@ -1348,8 +1350,12 @@ static int mtk_poll_rx(struct napi_struc + (trxd.rxd2 & RX_DMA_VTAG)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + RX_DMA_VID(trxd.rxd3)); +- skb_record_rx_queue(skb, 0); +- napi_gro_receive(napi, skb); ++ if (mtk_offload_check_rx(eth, skb, trxd.rxd4) == 0) { ++ skb_record_rx_queue(skb, 0); ++ napi_gro_receive(napi, skb); ++ } else { ++ dev_kfree_skb(skb); ++ } + + skip_rx: + ring->data[idx] = new_data; +@@ -2882,6 +2888,25 @@ static int mtk_set_rxnfc(struct net_devi + return ret; + } + ++static int ++mtk_flow_offload(enum flow_offload_type type, struct flow_offload *flow, ++ struct flow_offload_hw_path *src, ++ struct flow_offload_hw_path *dest) ++{ ++ struct mtk_mac *mac = netdev_priv(src->dev); ++ struct mtk_eth *eth = mac->hw; ++ ++ if (!eth->soc->offload_version) ++ return -EINVAL; ++ ++ if (src->dev->base_addr != dest->dev->base_addr) ++ return -EINVAL; ++ ++ mac = netdev_priv(src->dev); ++ ++ return mtk_flow_offload_add(eth, type, flow, src, dest); ++} ++ + static const struct ethtool_ops mtk_ethtool_ops = { + .get_link_ksettings = mtk_get_link_ksettings, + .set_link_ksettings = mtk_set_link_ksettings, +@@ -2913,6 +2938,7 @@ static const struct net_device_ops mtk_n + #ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = mtk_poll_controller, + #endif ++ .ndo_flow_offload = mtk_flow_offload, + }; + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +@@ -3178,6 +3204,10 @@ static int mtk_probe(struct platform_dev + eth->base + MTK_ETH_PPE_BASE, 2); + if (err) + goto err_free_dev; ++ ++ err = mtk_flow_offload_init(eth); ++ if (err) ++ goto err_free_dev; + } + + for (i = 0; i < MTK_MAX_DEVS; i++) { +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -949,6 +949,7 @@ struct mtk_eth { + int ip_align; + + struct mtk_ppe ppe; ++ struct flow_offload __rcu **foe_flow_table; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the +@@ -993,4 +994,12 @@ int mtk_gmac_sgmii_path_setup(struct mtk + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); + ++int mtk_flow_offload_init(struct mtk_eth *eth); ++int mtk_flow_offload_add(struct mtk_eth *eth, ++ enum flow_offload_type type, ++ struct flow_offload *flow, ++ struct flow_offload_hw_path *src, ++ struct flow_offload_hw_path *dest); ++int mtk_offload_check_rx(struct mtk_eth *eth, struct sk_buff *skb, u32 rxd4); ++ + #endif /* MTK_ETH_H */ +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_offload.c +@@ -0,0 +1,146 @@ ++/* This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2018 John Crispin ++ */ ++ ++#include ++#include "mtk_eth_soc.h" ++ ++static int ++mtk_offload_prepare_v4(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ struct flow_offload_tuple *s_tuple, ++ struct flow_offload_tuple *d_tuple, ++ struct flow_offload_hw_path *src, ++ struct flow_offload_hw_path *dest) ++{ ++ int dest_port = 1; ++ ++ if (dest->dev == eth->netdev[1]) ++ dest_port = 2; ++ ++ mtk_foe_entry_prepare(entry, MTK_PPE_PKT_TYPE_IPV4_HNAPT, s_tuple->l4proto, ++ dest_port, dest->eth_src, dest->eth_dest); ++ mtk_foe_entry_set_ipv4_tuple(entry, false, ++ s_tuple->src_v4.s_addr, s_tuple->src_port, ++ s_tuple->dst_v4.s_addr, s_tuple->dst_port); ++ mtk_foe_entry_set_ipv4_tuple(entry, true, ++ d_tuple->dst_v4.s_addr, d_tuple->dst_port, ++ d_tuple->src_v4.s_addr, d_tuple->src_port); ++ ++ if (dest->flags & FLOW_OFFLOAD_PATH_PPPOE) ++ mtk_foe_entry_set_pppoe(entry, dest->pppoe_sid); ++ ++ if (dest->flags & FLOW_OFFLOAD_PATH_VLAN) ++ mtk_foe_entry_set_vlan(entry, dest->vlan_id); ++ ++ if (dest->flags & FLOW_OFFLOAD_PATH_DSA) ++ mtk_foe_entry_set_dsa(entry, dest->dsa_port); ++ ++ return 0; ++} ++ ++int mtk_flow_offload_add(struct mtk_eth *eth, ++ enum flow_offload_type type, ++ struct flow_offload *flow, ++ struct flow_offload_hw_path *src, ++ struct flow_offload_hw_path *dest) ++{ ++ struct flow_offload_tuple *otuple = &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple; ++ struct flow_offload_tuple *rtuple = &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple; ++ struct mtk_foe_entry orig, reply; ++ u32 ohash, rhash, timestamp; ++ ++ if (otuple->l4proto != IPPROTO_TCP && otuple->l4proto != IPPROTO_UDP) ++ return -EINVAL; ++ ++ if (type == FLOW_OFFLOAD_DEL) { ++ ohash = (unsigned long)flow->priv; ++ rhash = ohash >> 16; ++ ohash &= 0xffff; ++ mtk_foe_entry_clear(ð->ppe, ohash); ++ mtk_foe_entry_clear(ð->ppe, rhash); ++ rcu_assign_pointer(eth->foe_flow_table[ohash], NULL); ++ rcu_assign_pointer(eth->foe_flow_table[rhash], NULL); ++ synchronize_rcu(); ++ ++ return 0; ++ } ++ ++ switch (otuple->l3proto) { ++ case AF_INET: ++ if (mtk_offload_prepare_v4(eth, &orig, otuple, rtuple, src, dest) || ++ mtk_offload_prepare_v4(eth, &reply, rtuple, otuple, dest, src)) ++ return -EINVAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ timestamp = mtk_r32(eth, 0x0010); ++ ++ ohash = mtk_foe_entry_commit(ð->ppe, &orig, timestamp); ++ if (ohash < 0) ++ return -EINVAL; ++ ++ rhash = mtk_foe_entry_commit(ð->ppe, &reply, timestamp); ++ if (rhash < 0) { ++ mtk_foe_entry_clear(ð->ppe, ohash); ++ return -EINVAL; ++ } ++ ++ rcu_assign_pointer(eth->foe_flow_table[ohash], flow); ++ rcu_assign_pointer(eth->foe_flow_table[rhash], flow); ++ ++ ohash |= rhash << 16; ++ flow->priv = (void *)(unsigned long)ohash; ++ ++ return 0; ++} ++ ++static void mtk_offload_keepalive(struct mtk_eth *eth, unsigned int hash) ++{ ++ struct flow_offload *flow; ++ ++ rcu_read_lock(); ++ flow = rcu_dereference(eth->foe_flow_table[hash]); ++ if (flow) ++ flow->timeout = jiffies + 30 * HZ; ++ rcu_read_unlock(); ++} ++ ++int mtk_offload_check_rx(struct mtk_eth *eth, struct sk_buff *skb, u32 rxd4) ++{ ++ unsigned int hash; ++ ++ switch (FIELD_GET(MTK_RXD4_PPE_CPU_REASON, rxd4)) { ++ case MTK_PPE_CPU_REASON_KEEPALIVE_UC_OLD_HDR: ++ case MTK_PPE_CPU_REASON_KEEPALIVE_MC_NEW_HDR: ++ case MTK_PPE_CPU_REASON_KEEPALIVE_DUP_OLD_HDR: ++ hash = FIELD_GET(MTK_RXD4_FOE_ENTRY, rxd4); ++ mtk_offload_keepalive(eth, hash); ++ return -1; ++ case MTK_PPE_CPU_REASON_PACKET_SAMPLING: ++ return -1; ++ default: ++ return 0; ++ } ++} ++ ++int mtk_flow_offload_init(struct mtk_eth *eth) ++{ ++ eth->foe_flow_table = devm_kcalloc(eth->dev, MTK_PPE_ENTRIES, ++ sizeof(*eth->foe_flow_table), ++ GFP_KERNEL); ++ ++ if (!eth->foe_flow_table) ++ return -ENOMEM; ++ ++ return 0; ++} +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -375,6 +375,8 @@ int mtk_ppe_init(struct mtk_ppe *ppe, st + + ppe->foe_table = foe; + ++ mtk_ppe_debugfs_init(ppe); ++ + return 0; + } + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -271,4 +271,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_f + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 timestamp); + ++/* internal */ ++int mtk_ppe_debugfs_init(struct mtk_ppe *ppe); ++ + #endif +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -0,0 +1,114 @@ ++/* This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ * Copyright (C) 2020 Felix Fietkau ++ */ ++ ++#include ++#include ++#include "mtk_eth_soc.h" ++ ++static const char *mtk_foe_entry_state_str[] = { ++ "INVALID", ++ "UNBIND", ++ "BIND", ++ "FIN" ++}; ++ ++static const char *mtk_foe_packet_type_str[] = { ++ "IPV4_HNAPT", ++ "IPV4_HNAT", ++ "IPV6_1T_ROUTE", ++ "IPV4_DSLITE", ++ "IPV6_3T_ROUTE", ++ "IPV6_5T_ROUTE", ++ "IPV6_6RD", ++}; ++ ++#define es(entry) (mtk_foe_entry_state_str[FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1)]) ++//#define ei(entry, end) (MTK_PPE_TBL_SZ - (int)(end - entry)) ++#define pt(entry) (mtk_foe_packet_type_str[FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1)]) ++ ++static int mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private) ++{ ++ struct mtk_ppe *ppe = m->private; ++ int i, count; ++ ++ for (i = 0, count = 0; i < MTK_PPE_ENTRIES; i++) { ++ struct mtk_foe_entry *entry = &ppe->foe_table[i]; ++ ++ if (!FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1)) ++ continue; ++ ++ if (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1) == ++ MTK_PPE_PKT_TYPE_IPV4_HNAPT) { ++ struct mtk_foe_ipv4 *ip4 = &entry->ipv4; ++ struct mtk_foe_mac_info *l2 = &ip4->l2; ++ ++ __be32 saddr = htonl(ip4->orig.src_ip); ++ __be32 daddr = htonl(ip4->orig.dest_ip); ++ __be32 nsaddr = htonl(ip4->new.src_ip); ++ __be32 ndaddr = htonl(ip4->new.dest_ip); ++ unsigned char h_dest[ETH_ALEN]; ++ unsigned char h_source[ETH_ALEN]; ++ ++ *((__be32 *) h_source) = htonl(l2->src_mac_hi); ++ *((__be16*) &h_source[4]) = htons(l2->src_mac_lo); ++ *((__be32*) h_dest) = htonl(l2->dest_mac_hi); ++ *((__be16*) &h_dest[4]) = htons(l2->dest_mac_lo); ++ seq_printf(m, ++ "(%x)0x%05x|state=%s|type=%s|" ++ "%pI4:%d->%pI4:%d=>%pI4:%d->%pI4:%d|%pM=>%pM|" ++ "etype=0x%04x|info1=0x%x|info2=0x%x|" ++ "vlan1=%d|vlan2=%d\n", ++ count, i, es(entry), pt(entry), ++ &saddr, ip4->orig.src_port, ++ &daddr, ip4->orig.dest_port, ++ &nsaddr, ip4->new.src_port, ++ &ndaddr, ip4->new.dest_port, ++ h_source, h_dest, ++ ntohs(l2->etype), ++ entry->ib1, ++ ip4->ib2, ++ l2->vlan1, ++ l2->vlan2); ++ count++; ++ } else ++ seq_printf(m, "0x%05x state=%s\n", count, es(entry)); ++ } ++ ++ return 0; ++} ++ ++static int mtk_ppe_debugfs_foe_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mtk_ppe_debugfs_foe_show, inode->i_private); ++} ++ ++static const struct file_operations mtk_ppe_debugfs_foe_fops = { ++ .open = mtk_ppe_debugfs_foe_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++int mtk_ppe_debugfs_init(struct mtk_ppe *ppe) ++{ ++ struct dentry *root; ++ ++ root = debugfs_create_dir("mtk_ppe", NULL); ++ if (!root) ++ return -ENOMEM; ++ ++ debugfs_create_file("entries", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_fops); ++ ++ return 0; ++} diff --git a/ipq806x/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch b/ipq806x/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch new file mode 100644 index 0000000..511a9f7 --- /dev/null +++ b/ipq806x/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch @@ -0,0 +1,64 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: [PATCH] bcma: get SoC device struct & copy its DMA params to the + subdevices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For bus devices to be fully usable it's required to set their DMA +parameters. + +For years it has been missing and remained unnoticed because of +mips_dma_alloc_coherent() silently handling the empty coherent_dma_mask. +Kernel 4.19 came with a lot of DMA changes and caused a regression on +the bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic +dma noncoherent ops for simple noncoherent platforms") DMA coherent +allocations just fail. Example: +[ 1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed +[ 1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA +[ 1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12 +[ 1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded + +This change fixes above regression in addition to the MIPS bcm47xx +commit 321c46b91550 ("MIPS: BCM47XX: Setup struct device for the SoC"). + +It also fixes another *old* GPIO regression caused by a parent pointing +to the NULL: +[ 0.157054] missing gpiochip .dev parent pointer +[ 0.157287] bcma: bus0: Error registering GPIO driver: -22 +introduced by the commit 74f4e0cc6108 ("bcma: switch GPIO portions to +use GPIOLIB_IRQCHIP"). + +Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms") +Fixes: 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP") +Cc: linux-mips@linux-mips.org +Cc: Christoph Hellwig +Cc: Linus Walleij +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/bcma/host_soc.c ++++ b/drivers/bcma/host_soc.c +@@ -191,6 +191,8 @@ int __init bcma_host_soc_init(struct bcm + struct bcma_bus *bus = &soc->bus; + int err; + ++ bus->dev = soc->dev; ++ + /* Scan bus and initialize it */ + err = bcma_bus_early_register(bus); + if (err) +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -241,8 +241,10 @@ void bcma_prepare_core(struct bcma_bus * + core->dev.bus = &bcma_bus_type; + dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); + core->dev.parent = bus->dev; +- if (bus->dev) ++ if (bus->dev) { + bcma_of_fill_device(bus->dev, core); ++ dma_coerce_mask_and_coherent(&core->dev, bus->dev->coherent_dma_mask); ++ } + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: diff --git a/ipq806x/pending-5.4/810-pci_disable_common_quirks.patch b/ipq806x/pending-5.4/810-pci_disable_common_quirks.patch new file mode 100644 index 0000000..5aea055 --- /dev/null +++ b/ipq806x/pending-5.4/810-pci_disable_common_quirks.patch @@ -0,0 +1,62 @@ +From: Gabor Juhos +Subject: debloat: add kernel config option to disabling common PCI quirks + +Signed-off-by: Gabor Juhos +--- + drivers/pci/Kconfig | 6 ++++++ + drivers/pci/quirks.c | 6 ++++++ + 2 files changed, 12 insertions(+) + +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -115,6 +115,13 @@ config XEN_PCIDEV_FRONTEND + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + ++config PCI_DISABLE_COMMON_QUIRKS ++ bool "PCI disable common quirks" ++ depends on PCI ++ help ++ If you don't know what to do here, say N. ++ ++ + config PCI_ATS + bool + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -206,6 +206,7 @@ static void quirk_mmio_always_on(struct + DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + /* + * The Mellanox Tavor device gives false positive parity errors. Mark this + * device with a broken_parity_status to allow PCI scanning code to "skip" +@@ -3323,6 +3324,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. + * To work around this, query the size it should be configured to by the +@@ -3348,6 +3351,8 @@ static void quirk_intel_ntb(struct pci_d + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + /* + * Some BIOS implementations leave the Intel GPU interrupts enabled, even + * though no one is handling them (e.g., if the i915 driver is never +@@ -3386,6 +3391,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * PCI devices which are on Intel chips can skip the 10ms delay + * before entering D3 mode. diff --git a/ipq806x/pending-5.4/811-pci_disable_usb_common_quirks.patch b/ipq806x/pending-5.4/811-pci_disable_usb_common_quirks.patch new file mode 100644 index 0000000..6e4584c --- /dev/null +++ b/ipq806x/pending-5.4/811-pci_disable_usb_common_quirks.patch @@ -0,0 +1,115 @@ +From: Felix Fietkau +Subject: debloat: disable common USB quirks + +Signed-off-by: Felix Fietkau +--- + drivers/usb/host/pci-quirks.c | 16 ++++++++++++++++ + drivers/usb/host/pci-quirks.h | 18 +++++++++++++++++- + include/linux/usb/hcd.h | 7 +++++++ + 3 files changed, 40 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -125,6 +125,8 @@ struct amd_chipset_type { + u8 rev; + }; + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static struct amd_chipset_info { + struct pci_dev *nb_dev; + struct pci_dev *smbus_dev; +@@ -630,6 +632,10 @@ bool usb_amd_pt_check_port(struct device + } + EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); + ++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ ++#if IS_ENABLED(CONFIG_USB_UHCI_HCD) ++ + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -709,8 +715,17 @@ reset_needed: + uhci_reset_hc(pdev, base); + return 1; + } ++#else ++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) ++{ ++ return 0; ++} ++ ++#endif + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) + { + u16 cmd; +@@ -1271,3 +1286,4 @@ static void quirk_usb_early_handoff(stru + } + DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); ++#endif +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -5,6 +5,9 @@ + #ifdef CONFIG_USB_PCI + void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); + int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); ++#endif /* CONFIG_USB_PCI */ ++ ++#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS) + int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); + bool usb_amd_hang_symptom_quirk(void); + bool usb_amd_prefetch_quirk(void); +@@ -19,6 +22,18 @@ void sb800_prefetch(struct device *dev, + bool usb_amd_pt_check_port(struct device *device, int port); + #else + struct pci_dev; ++static inline int usb_amd_quirk_pll_check(void) ++{ ++ return 0; ++} ++static inline bool usb_amd_hang_symptom_quirk(void) ++{ ++ return false; ++} ++static inline bool usb_amd_prefetch_quirk(void) ++{ ++ return false; ++} + static inline void usb_amd_quirk_pll_disable(void) {} + static inline void usb_amd_quirk_pll_enable(void) {} + static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} +@@ -29,6 +44,11 @@ static inline bool usb_amd_pt_check_port + { + return false; + } ++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {} ++static inline bool usb_xhci_needs_pci_reset(struct pci_dev *pdev) ++{ ++ return false; ++} + #endif /* CONFIG_USB_PCI */ + + #endif /* __LINUX_USB_PCI_QUIRKS_H */ +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -483,7 +483,14 @@ extern int usb_hcd_pci_probe(struct pci_ + extern void usb_hcd_pci_remove(struct pci_dev *dev); + extern void usb_hcd_pci_shutdown(struct pci_dev *dev); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); ++#else ++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev) ++{ ++ return 0; ++} ++#endif + + #ifdef CONFIG_PM + extern const struct dev_pm_ops usb_hcd_pci_pm_ops; diff --git a/ipq806x/pending-5.4/820-libata-Assign-OF-node-to-the-SCSI-device.patch b/ipq806x/pending-5.4/820-libata-Assign-OF-node-to-the-SCSI-device.patch new file mode 100644 index 0000000..bec9363 --- /dev/null +++ b/ipq806x/pending-5.4/820-libata-Assign-OF-node-to-the-SCSI-device.patch @@ -0,0 +1,86 @@ +From 43a93893eb33e996836b99fb3e1f7300c0132a51 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Tue, 31 Dec 2019 18:15:33 +0100 +Subject: [PATCH 5/7] libata: Assign OF node to the SCSI device + +When we spawn a SCSI device from an ATA device in libata-scsi +the SCSI device had no relation to the device tree. + +The DT binding allows us to define port nodes under a +PATA (IDE) or SATA host controller, so we can have proper device +nodes for these devices. + +If OF is enabled, walk the children of the host controller node +to see if there is a valid device tree node to assign. The reg +is used to match to ID 0 for the master device and ID 1 for the +slave device. + +The corresponding device tree bindings have been accepted by +the device tree maintainers. + +Cc: Chris Healy +Cc: Martin K. Petersen +Cc: Bart Van Assche +Cc: Guenter Roeck +Signed-off-by: Linus Walleij +--- +ChangeLog v1->v2: +- Use dev_dbg() for the debug print +- return immediately after finding a matching OF node +--- + drivers/ata/libata-scsi.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/drivers/ata/libata-scsi.c ++++ b/drivers/ata/libata-scsi.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #include "libata.h" + #include "libata-transport.h" +@@ -4579,6 +4580,34 @@ int ata_scsi_add_hosts(struct ata_host * + return rc; + } + ++#ifdef CONFIG_OF ++static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap) ++{ ++ struct scsi_device *sdev = dev->sdev; ++ struct device *d = ap->host->dev; ++ struct device_node *np = d->of_node; ++ struct device_node *child; ++ ++ for_each_available_child_of_node(np, child) { ++ int ret; ++ u32 val; ++ ++ ret = of_property_read_u32(child, "reg", &val); ++ if (ret) ++ continue; ++ if (val == dev->devno) { ++ dev_dbg(d, "found matching device node\n"); ++ sdev->sdev_gendev.of_node = child; ++ return; ++ } ++ } ++} ++#else ++static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap) ++{ ++} ++#endif ++ + void ata_scsi_scan_host(struct ata_port *ap, int sync) + { + int tries = 5; +@@ -4604,6 +4633,7 @@ void ata_scsi_scan_host(struct ata_port + NULL); + if (!IS_ERR(sdev)) { + dev->sdev = sdev; ++ ata_scsi_assign_ofnode(dev, ap); + scsi_device_put(sdev); + } else { + dev->sdev = NULL; diff --git a/ipq806x/pending-5.4/834-ledtrig-libata.patch b/ipq806x/pending-5.4/834-ledtrig-libata.patch new file mode 100644 index 0000000..f33ceec --- /dev/null +++ b/ipq806x/pending-5.4/834-ledtrig-libata.patch @@ -0,0 +1,149 @@ +From: Daniel Golle +Subject: libata: add ledtrig support + +This adds a LED trigger for each ATA port indicating disk activity. + +As this is needed only on specific platforms (NAS SoCs and such), +these platforms should define ARCH_WANTS_LIBATA_LEDS if there +are boards with LED(s) intended to indicate ATA disk activity and +need the OS to take care of that. +In that way, if not selected, LED trigger support not will be +included in libata-core and both, codepaths and structures remain +untouched. + +Signed-off-by: Daniel Golle +--- + drivers/ata/Kconfig | 16 ++++++++++++++++ + drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++ + include/linux/libata.h | 9 +++++++++ + 3 files changed, 66 insertions(+) + +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -45,6 +45,22 @@ config ATA_VERBOSE_ERROR + + If unsure, say Y. + ++config ARCH_WANT_LIBATA_LEDS ++ bool ++ ++config ATA_LEDS ++ bool "support ATA port LED triggers" ++ depends on ARCH_WANT_LIBATA_LEDS ++ select NEW_LEDS ++ select LEDS_CLASS ++ select LEDS_TRIGGERS ++ default y ++ help ++ This option adds a LED trigger for each registered ATA port. ++ It is used to drive disk activity leds connected via GPIO. ++ ++ If unsure, say N. ++ + config ATA_ACPI + bool "ATA ACPI Support" + depends on ACPI +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -714,6 +714,19 @@ u64 ata_tf_read_block(const struct ata_t + return block; + } + ++#ifdef CONFIG_ATA_LEDS ++#define LIBATA_BLINK_DELAY 20 /* ms */ ++static inline void ata_led_act(struct ata_port *ap) ++{ ++ unsigned long led_delay = LIBATA_BLINK_DELAY; ++ ++ if (unlikely(!ap->ledtrig)) ++ return; ++ ++ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0); ++} ++#endif ++ + /** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @tf: Target ATA taskfile +@@ -5149,6 +5162,9 @@ struct ata_queued_cmd *ata_qc_new_init(s + if (tag < 0) + return NULL; + } ++#ifdef CONFIG_ATA_LEDS ++ ata_led_act(ap); ++#endif + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = qc->hw_tag = tag; +@@ -6085,6 +6101,9 @@ struct ata_port *ata_port_alloc(struct a + ap->stats.unhandled_irq = 1; + ap->stats.idle_irq = 1; + #endif ++#ifdef CONFIG_ATA_LEDS ++ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); ++#endif + ata_sff_port_init(ap); + + return ap; +@@ -6120,6 +6139,12 @@ static void ata_host_release(struct kref + + kfree(ap->pmp_link); + kfree(ap->slave_link); ++#ifdef CONFIG_ATA_LEDS ++ if (ap->ledtrig) { ++ led_trigger_unregister(ap->ledtrig); ++ kfree(ap->ledtrig); ++ }; ++#endif + kfree(ap); + host->ports[i] = NULL; + } +@@ -6583,7 +6608,23 @@ int ata_host_register(struct ata_host *h + host->ports[i]->print_id = atomic_inc_return(&ata_print_id); + host->ports[i]->local_port_no = i + 1; + } ++#ifdef CONFIG_ATA_LEDS ++ for (i = 0; i < host->n_ports; i++) { ++ if (unlikely(!host->ports[i]->ledtrig)) ++ continue; + ++ snprintf(host->ports[i]->ledtrig_name, ++ sizeof(host->ports[i]->ledtrig_name), "ata%u", ++ host->ports[i]->print_id); ++ ++ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name; ++ ++ if (led_trigger_register(host->ports[i]->ledtrig)) { ++ kfree(host->ports[i]->ledtrig); ++ host->ports[i]->ledtrig = NULL; ++ } ++ } ++#endif + /* Create associated sysfs transport objects */ + for (i = 0; i < host->n_ports; i++) { + rc = ata_tport_add(host->dev,host->ports[i]); +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -23,6 +23,9 @@ + #include + #include + #include ++#ifdef CONFIG_ATA_LEDS ++#include ++#endif + + /* + * Define if arch has non-standard setup. This is a _PCI_ standard +@@ -882,6 +885,12 @@ struct ata_port { + #ifdef CONFIG_ATA_ACPI + struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ + #endif ++ ++#ifdef CONFIG_ATA_LEDS ++ struct led_trigger *ledtrig; ++ char ledtrig_name[8]; ++#endif ++ + /* owned by EH */ + u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned; + }; diff --git a/ipq806x/pending-5.4/840-hwrng-bcm2835-set-quality-to-1000.patch b/ipq806x/pending-5.4/840-hwrng-bcm2835-set-quality-to-1000.patch new file mode 100644 index 0000000..247c6d8 --- /dev/null +++ b/ipq806x/pending-5.4/840-hwrng-bcm2835-set-quality-to-1000.patch @@ -0,0 +1,26 @@ +From d6988cf1d16faac56899918bb2b1be8d85155e3f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 20 Feb 2021 18:36:38 +0100 +Subject: [PATCH] hwrng: bcm2835: set quality to 1000 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows devices without a high precission timer to reduce boot from >100s +to <30s. + +Signed-off-by: Álvaro Fernández Rojas +--- + drivers/char/hw_random/bcm2835-rng.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/char/hw_random/bcm2835-rng.c ++++ b/drivers/char/hw_random/bcm2835-rng.c +@@ -167,6 +167,7 @@ static int bcm2835_rng_probe(struct plat + priv->rng.init = bcm2835_rng_init; + priv->rng.read = bcm2835_rng_read; + priv->rng.cleanup = bcm2835_rng_cleanup; ++ priv->rng.quality = 1000; + + if (dev_of_node(dev)) { + rng_id = of_match_node(bcm2835_rng_of_match, np); diff --git a/ipq806x/pending-5.4/920-mangle_bootargs.patch b/ipq806x/pending-5.4/920-mangle_bootargs.patch new file mode 100644 index 0000000..83db926 --- /dev/null +++ b/ipq806x/pending-5.4/920-mangle_bootargs.patch @@ -0,0 +1,71 @@ +From: Imre Kaloz +Subject: init: add CONFIG_MANGLE_BOOTARGS and disable it by default + +Enabling this option renames the bootloader supplied root= +and rootfstype= variables, which might have to be know but +would break the automatisms OpenWrt uses. + +Signed-off-by: Imre Kaloz +--- + init/Kconfig | 9 +++++++++ + init/main.c | 24 ++++++++++++++++++++++++ + 2 files changed, 33 insertions(+) + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1665,6 +1665,15 @@ config EMBEDDED + an embedded system so certain expert options are available + for configuration. + ++config MANGLE_BOOTARGS ++ bool "Rename offending bootargs" ++ depends on EXPERT ++ help ++ Sometimes the bootloader passed bogus root= and rootfstype= ++ parameters to the kernel, and while you want to ignore them, ++ you need to know the values f.e. to support dual firmware ++ layouts on the flash. ++ + config HAVE_PERF_EVENTS + bool + help +--- a/init/main.c ++++ b/init/main.c +@@ -367,6 +367,29 @@ static inline void setup_nr_cpu_ids(void + static inline void smp_prepare_cpus(unsigned int maxcpus) { } + #endif + ++#ifdef CONFIG_MANGLE_BOOTARGS ++static void __init mangle_bootargs(char *command_line) ++{ ++ char *rootdev; ++ char *rootfs; ++ ++ rootdev = strstr(command_line, "root=/dev/mtdblock"); ++ ++ if (rootdev) ++ strncpy(rootdev, "mangled_rootblock=", 18); ++ ++ rootfs = strstr(command_line, "rootfstype"); ++ ++ if (rootfs) ++ strncpy(rootfs, "mangled_fs", 10); ++ ++} ++#else ++static void __init mangle_bootargs(char *command_line) ++{ ++} ++#endif ++ + /* + * We need to store the untouched command line for future reference. + * We also need to store the touched command line since the parameter +@@ -597,6 +620,7 @@ asmlinkage __visible void __init start_k + pr_notice("%s", linux_banner); + early_security_init(); + setup_arch(&command_line); ++ mangle_bootargs(command_line); + setup_command_line(command_line); + setup_nr_cpu_ids(); + setup_per_cpu_areas();